74cms_v3.5.1_20141027.zip 无限制SQL注入

刚下了个74cms_v3.5.1_20141027.zip,diff了一下发现了下面的改动:

diff -Nurp upload.1020/plus/weixin.php upload.1027/plus/weixin.php --- upload.1020/plus/weixin.php 2014-10-18 12:14:22.000000000 +0800 +++ upload.1027/plus/weixin.php 2014-10-25 14:45:22.000000000 +0800 @@ -21,10 +21,10 @@ class wechatCallbackapiTest extends mysq } public function responseMsg() { - if(!$this->checkSignature()) - { - exit(); - } + // if(!$this->checkSignature()) + // { + // exit(); + // } $postStr = addslashes($GLOBALS["HTTP_RAW_POST_DATA"]); if (!empty($postStr)) {

注释调了checkSignature(),是为了啥?????

被次利用的是另外两个BUG。

先看code.

class wechatCallbackapiTest extends mysql { public function valid() { $echoStr = $_GET["echostr"]; if($this->checkSignature()) { exit($echoStr); } } public function responseMsg() { // if(!$this->checkSignature()) // { // exit(); // } $postStr = addslashes($GLOBALS["HTTP_RAW_POST_DATA"]); if (!empty($postStr)) { // libxml_disable_entity_loader(true); $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $postObj->FromUserName; $toUsername = $postObj->ToUserName; $keyword = trim($postObj->Content); $keyword = utf8_to_gbk($keyword); $keyword = addslashes($keyword); $time = time(); $event = trim($postObj->Event); if ($event === "subscribe") { $word= "»ØžŽj·µ»ØœôŒ±ÕÐÆž£¬»ØžŽn·µ»Ø×îÐÂÕÐÆž£¡Äú¿ÉÒÔ³¢ÊÔÊäÈëְλÃû³ÆÈç¡°»áŒÆ¡±£¬ÏµÍ³œ«»á·µ»ØÄúÒªÕÒµÄÐÅÏ¢£¬ÎÒÃÇŬÁŠŽòÔì×îÈËÐÔ»¯µÄ·þÎñƜ̚£¬Ð»Ð»¹Ø×¢¡£"; $this->exit_word_message($word,$fromUsername,$toUsername,$time); } $default_pic=ROOT."/data/images/".DEFAULT_PIC; $first_pic=ROOT."/data/images/".FIRST_PIC; if($event === "CLICK"){ if($_CFG['weixin_apiopen']=='0') { $word="Íø՟΢ÐŜӿÚÒÑŸ­¹Ø±Õ"; $this->exit_word_message($word,$fromUsername,$toUsername,$time); } if($postObj->EventKey=="binding"){ $usinfo = $this->get_user_info($fromUsername); if(!empty($usinfo)){ $word="ÄúÒÑŸ­°ó¶š¹ýÁË!"; }else{ $word="ÇëÊäÈëÄúµÄÕ˺ÅÃÜÂë. ÀýÈç:ÕÅÈý/123456"; } $this->exit_word_message($word,$fromUsername,$toUsername,$time); } ... private function get_user_info($fromUsername){ $usinfo = array(); $usinfo_obj = $this->query("select * from ".table('members')." where weixin_openid='".$fromUsername."' limit 1"); while($row = $this->fetch_array($usinfo_obj)){ $usinfo = $row; } return $usinfo; }

$postStr = addslashes($GLOBALS["HTTP_RAW_POST_DATA"]);

对整个POST_DATA做了addslashes。

$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $postObj->FromUserName;

然后:

$usinfo = $this->get_user_info($fromUsername); ===> $this->query("select * from ".table('members')." where weixin_openid='".$fromUsername."' limit 1");

$fromUsername从simplexml_load_string()后就直接进入了SQL中,addslashes($GLOBALS["HTTP_RAW_POST_DATA"])就解决了所有问题么?答案是否定的。因为XML中特殊字符也可以编码:

特殊字符 特殊含义 实体编码

> 开始标记 &gt; < 结束标记 &lt; " 引号 &quot; ' 撇号 &apos; & 和号 &amp;

也就是说在XML中使用&apos就把'号注入进去了,并且这里post data没有任何过滤,可以注入任何SQL语句,所以我们可以导出整个数据库,甚至getshell.

看到下面的代码,也许有人会说,这里是有条件的,因为这里判断了$_CFG['weixin_apiopen']=='0')。