程式碼審計Day12 – 誤用htmlentities函式引發的漏洞
本文轉載自先知社群: ofollow,noindex" target="_blank">https://xz.aliyun.com/t/2757
本文由紅日安全成員: l1nk3r 編寫,如有不當,還望斧正。
前言
大家好,我們是紅日安全-程式碼審計小組。最近我們小組正在做一個PHP程式碼審計的專案,供大家學習交流,我們給這個專案起了一個名字叫 PHP-Audit-Labs 。現在大家所看到的系列文章,屬於專案 第一階段 的內容,本階段的內容題目均來自 PHP SECURITY CALENDAR 2017 。對於每一道題目,我們均給出對應的分析,並結合實際CMS進行解說。在文章的最後,我們還會留一道CTF題目,供大家練習,希望大家喜歡。下面是 第12篇 程式碼審計文章: Day 12 - String Lights
題目程式碼如下:
漏洞解析 :
根據題目意思,這裡考察的應該是個 xss漏洞 , 漏洞觸發點應該在程式碼中的 第13-14行 。這兩行程式碼的作用是直接輸出一個html的 <a> 標籤。程式碼中的 第3-5行 ,foreach迴圈 對 $_GET 傳入的引數進行了處理,但是這裡有個問題。我們看下 第四行的程式碼,這行程式碼針對 $value 進行型別轉換,強制變成int型別。但是這部分程式碼只處理了 $value 變數,沒針對 $key 變數進行處理。經過了 第3-5行 的程式碼處理之後,根據 & 這個符號進行分割,然後拼接到 第13行 的 echo 語句中,在輸出的時候又進行了一次 htmlentities 函式處理。 htmlentities 函式主要是會對一些特殊符號進行HTML實體編碼。具體定義如下:
htmlentities — 將字元轉換為 HTML 轉義字元
string htmlentities ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $encoding = ini_get("default_charset") [, bool $double_encode = true ]]] )
作用:在寫PHP程式碼時,不能在字串中直接寫實體字元,PHP提供了一個將HTML特殊字元轉換成實體字元的函式 htmlentities()。
注:htmlentities() 並不能轉換所有的特殊字元,是轉換除了空格之外的特殊字元,且單引號和雙引號需要單獨控制(通過第二個引數)。第2個引數取值有3種,分別如下:
-
ENT_COMPAT(預設值):只轉換雙引號。
-
ENT_QUOTES:兩種引號都轉換。
-
ENT_NOQUOTES:兩種引號都不轉換。
這裡附上一個 HTML 中有用的字元實體表
經過上面的分析,我們再回到題目,想想如何構造一下攻擊 payload 。我們先梳理一些已知資訊:
-
這裡的 $query 引數可控
-
且 htmlentities 函式在這裡可逃逸單引號
-
xss的漏洞觸發點在 <a> 標籤。
在 <a> 中,我們可以通過 javascript 事件來執行js程式碼,例如: onclick 這類事件,因此最後的poc構造如下:
/?a'onclick%3dalert(1)%2f%2f=c
例項分析
本次例項分析選擇 DM企業建站系統 v201710 中的 sql注入漏洞 來進行分析。首先,我們可以從cnvd上面看到一些相關資訊,如下:
從漏洞通告中可以發現一些有用的資訊,漏洞位置在登陸處,搭建的時候提示後臺登陸口位置在 admindm-yourname/g.php檔案中,開啟這個檔案,發現重定向到 admindm-yournamemod_common/login.php 檔案中,所以漏洞觸發點應該就在這個檔案中。
開啟 admindm-yournamemod_common/login.php 這個檔案,一眼就看到漏洞位置,擷取部分相關程式碼如下:
第15行 很明視訊記憶體在sql注入漏洞,通過拼接的方式直接插入到select語句中。 第15行 中的 $user 變數是通過 POST 方式提交上來,其值可控。但是上圖的 第3行 程式碼呼叫 htmlentitiesdm 函式,對 POST 資料進行了處理,我們跟進這個 htmlentitiesdm函式。該函式位置在 component/dm-config/global.common.php 檔案中,擷取關鍵程式碼如下:
這個函式是呼叫 htmlentities 函式針對輸入的資料進行處理。前面我們已經介紹過了這個函式的用法,這裡這個函式的可選引數是 ENT_NOQUOTES ,也就是說兩種引號都不轉換。下面我們來看個小例子:
新版修復的時候將可選引數修改為 ENT_QUOTES ,這個引數的作用就是過濾單引號加雙引號,我們來看看下面這個例子,就很容易明白了這個引數的作用了。
漏洞驗證
這裡因為沒有回顯,所以是盲注,下面是驗證截圖:
漏洞修復
針對 htmlentities 這個函式,我們建議大家在使用的時候,儘量加上可選引數,並且選擇 ENT_QUOTES 引數。
我們看看對比的效果
結語
看完了上述分析,不知道大家是否對 htmlentities 函式在使用過程中可能產生的問題,有了更加深入的理解,文中用到的程式碼可以從 這裡 下載,當然文中若有不當之處,還望各位斧正。如果你對我們的專案感興趣,歡迎傳送郵件到 [email protected] 聯絡我們。Day12 的分析文章就到這裡,我們最後留了一道CTF題目給大家練手,題目如下:
<?php require 'db.inc.php'; if(isset($_REQUEST['username'])){ if(preg_match("/(?:\w*)\W*?[a-z].*(R|ELECT|OIN|NTO|HERE|IO/">NION)/i", $_REQUEST['username'])){ die("Attack detected!!!"); } } if(isset($_REQUEST['password'])){ if(preg_match("/(?:\w*)\W*?[a-z].*(R|ELECT|OIN|NTO|HERE|NION)/i", $_REQUEST['password'])){ die("Attack detected!!!"); } } function clean($str){ if(get_magic_quotes_gpc()){ $str=stripslashes($str); } return htmlentities($str, ENT_QUOTES); } $username = @clean((string)$_GET['username']); $password = @clean((string)$_GET['password']); $query='SELECT * FROM ctf.users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';'; #echo $query; $result=mysql_query($query); while($row = mysql_fetch_array($result)) { echo "<tr>"; echo "<td>" . $row['name'] . "</td>"; echo "</tr>"; } ?>
# Host: localhost(Version: 5.5.53) # Date: 2018-08-05 12:55:29 # Generator: SQL/">MySQL-Front 5.3(Build 4.234) /*!40101 SET NAMES utf8 */; # # Structure for table "users" # DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `pass` varchar(255) DEFAULT NULL, `flag` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; # # Data for table "users" # /*!40000 ALTER TABLE `users` DISABLE KEYS */; INSERT INTO `users` VALUES (1,'admin','qwer!@#zxca','hrctf{sql_Inject1on_Is_1nterEst1ng}'); /*!40000 ALTER TABLE `users` ENABLE KEYS */;
題解我們會階段性放出,如果大家有什麼好的解法,可以在文章底下留言,祝大家玩的愉快!
參考文章