原文標題爲:第三方接口 #黑客怎麼愛你都不嫌多php
#做者 小飛
#fei@90sec.org
#前段時間太忙! 如今終於有時間回土司看看了!html
#原文地址:https://www.t00ls.net/thread-27765-1-1.html程序員
0x01 寫在前面
本文總結了最近爆出的第三方插件高危漏洞,因本文實例都是使用率高,且在近期爆出漏洞的API,具備必定現實意義
在程序中嵌入第三方程序,能夠追溯到discuz!。後來的各類SNS程序,CMS,BBS都紛紛效仿,他們或由官方 或由站長本身添加了各類插件和api,一方面 這些腳本增長了用戶體驗,然而在黑客眼中,實則是增大了入侵概率。
各類接口的添加,通常是在整站程序開發週期以後,那麼開發全局觀的不一樣步是顯而易見的後果,簡而言之,前期種種過濾和安全防禦,可能因爲後期開發對第三方插件盲目的信任,被完全繞過,致使漏洞造成。web
0x02 實例分析
看看那些廠商都是怎麼被出賣的吧
第一彈 Alipay支付插件那碎一地的節操
影響程序:Ecshop,Dedecms,Cmseasy ...
lib\plugins\pay\alipay.php
咱們看看cmseasy怎麼被本身人幹掉的吧 在alipay.php中 本身定義的數據庫函數在rec_update中sql
影響程序:Ecshop,Dedecms,Cmseasy ...
lib\plugins\pay\alipay.php
咱們看看cmseasy怎麼被本身人幹掉的吧 在alipay.php中 本身定義的數據庫函數在rec_update中數據庫
public function rec_update($row , $where){ ... 省略無關代碼 ... $sql="UPDATE `".$this->tablename."` SET ".$sqlud." WHERE ".$where; //漏洞出在這裏 一隻沒帶單引號的$where return $this->simpledb->execute($sql); }
能夠看到, where 是沒有單引號的,咱們看看where從哪裏能傳進來。api
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('改變訂單狀態出錯,請聯繫管理員'); } }
繼續追蹤changeorders安全
function respond() { if (!empty($_POST)) { foreach($_POST as $key =>$data) { $_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); ....省略.... pay::changeorders($order_sn,$_GET);
看到沒$order_sn 沒有過濾 注入因而產生了 因爲沒有顯示點 延時注入便可。
第二彈 Tenpay支付插件也瘋狂微信
lib\plugins\pay\tenpay.php函數
阿里巴巴那麼瘋狂,BAT的三弟騰訊怎麼能示弱? 組隊坑廠商什麼的最有愛了~ 因爲Cmseasy過於信任插件,因此又是他受傷
class tenpay { ...... function respond() { require_once ("tenpay/PayResponseHandler.class.php"); $resHandler = new PayResponseHandler(); $sp_billno = $resHandler->getParameter("sp_billno"); //騰訊的函數,相似於$_GET['sp_billno']或者$_POST['sp_billno'] //上面談到GET不受過濾影響,本地問價內包含POST,GET提交均可,可是注入的話必須提交POST,由於GET是URL碼. //sp_lillno=sp_billno=-1-1-../../../demo 包含根目錄的demo.php preg_match_all("/-(.*)-(.*)-(.*)/isu",$sp_billno,$oidout); $paytype = $where['pay_code'] = $oidout[3][0]; include_once ROOT.'/lib/plugins/pay/'.$paytype.'.php';//匹配上面正則就行,包含之,觸發,可是實在找不到能截斷的PHP文件了,因此雞肋了。 $pay = pay::getInstance()->getrows($where); //SQL注入,跟進0x02 ...... }
看到where沒? 難道又是一隻裸體動物? 答案是NO 此次是Cmseasy自己代碼和API共同沆瀣一氣 看getrows
function getrow($condition,$order='1 desc',$cols='*') { $this->condition($condition); //OMG跟進,又是這個函數 return $this->rec_select_one($condition,'*',$order); } function condition(&$condition) { if (isset($condition) &&is_array($condition)) { $_condition=array(); foreach ($condition as $key=>$value) { $value=str_replace("'","\'",$value);//問題函數在這裏 MARK $_condition[]="`$key`='$value'"; } $condition=implode(' and ',$_condition); } ...... }
試想一下,當咱們POST提交'evalsql 因爲gpc做用 會變成 \'evalsql 通過剛剛mark的那一行代碼 就變成了 \\'evalsql 單引號被解救了 - -
因此賣隊友成功
第三彈 騰訊連彈 換個姿式我們繼續賣隊友
微信sdk接口(weixin.php) 影響程序:數不清,這個太多了點,從大到小
挑個超級典型的對象 PHPYUN
這裏引入一個古老而又粗暴的漏洞 XML實體注入
//weixin/model/index.class.php private function responseMsg() { $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; if (!empty($postStr)){ $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $postObj->FromUserName; $toUsername = $postObj->ToUserName; $keyword = trim($postObj->Content); $time = time(); $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; if(!empty( $keyword )) { $msgType = "text"; $contentStr = "Welcome to wechat world!"; $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr); echo $resultStr; }else{ echo "Input something..."; } }else { echo ""; exit; } }
首先介紹下
$GLOBALS["HTTP_RAW_POST_DATA"]這個變量是講POST提交來的數據原封不動的接收 好比POST a=1
$GLOBALS["HTTP_RAW_POST_DATA"] 就是「a=1」 不受gpc 360wscan的影響 而後接收到$postStr以後 又沒有處理 因而乎...
if($MsgType=='event') { $MsgEvent = $postObj->Event; if ($MsgEvent=='subscribe') { $centerStr = "<Content><![CDATA[歡迎您關注".iconv('gbk','utf-8',$this->config['sy_webname'])."!\n 1:您能夠直接回復關鍵字如【銷售】、【南京 銷售】、【南京 銷售 XX公司】查找您想要的職位\n綁定您的帳戶體驗更多精彩功能\n感謝您的關注!]]></Content>"; $this->MsgType = 'text'; }elseif ($MsgEvent=='CLICK') { $EventKey = $postObj->EventKey; if($EventKey=='個人賬號'){ $centerStr = $this->bindUser($fromUsername);
傳進bindUser以後 最終到達
isBind private function isBind($wxid='') { if($wxid) { $User = $this->obj->DB_select_once("member","`wxid`='".$wxid."'","`uid`,`username`");
wxid就是一開始POST來的數據裏面的參數 注入赤果果的產生
微信團隊開發這個API的時候,實際上是驗證了來源的
驗證了signature(簽名)
驗證的條件是 檢查signature是否非空 非空 非空...
0x03 嘮叨幾句
這樣的第三方插件 應該成爲程序員或者白帽子重點檢查對象,緣由如上0x02 這貨們如同後門通常有魅力...
通常來說 形成此類漏洞的緣由有兩種
一,雙方相互信任 (你不打單引號,咱不過濾,好基友一塊兒死)
二,簽名未設置或者驗證
爲各位客官提供點思路
0x04 真正的最後嘮叨
其實這種漏洞還有不少 好比某投票插件,某社交圈關聯插件,某客服插件名字就不爆出來了,反正只要入庫的 就可能有注入!that is my principle~