- Web代碼安全漏洞深度剖析
- 曹玉杰 王樂 李家輝 孔韜循編著
- 2496字
- 2021-09-26 16:05:22
4.2 GET型SQL注入防御腳本繞過案例剖析
在公司企業門戶群體當中,使用CMS程序的用戶不少,信息安全隱患也隨著用戶的數量而變化。本節將結合實際案例進行源代碼剖析,以常見的GET類型注入展開分析。
4.2.1 復現條件
環境:Windows 7+phpStudy 2018+PHP 5.4.45+Apache。
程序框架:damicms 2014。
條件:需要登錄。
特點:屬于GET型注入,且存在防御腳本、防御方法。
4.2.2 復現漏洞
先注冊一個賬號:賬號名為test0,密碼為test0。
登錄進行場景復現,訪問鏈接http://localhost/test0/index.php?s=/api/ajax_arclist/model/article/field/username,userpwd from dami_member%23(注意:要寫成%23而不寫成#,因為進行get請求時,可控參數進入服務器端時會自動進行一次urldecode解碼,如圖4-1所示)。

圖4-1 系統所產生的報錯帶有賬號和密碼
從圖4-1中可以看到賬號、密碼已經顯示出來,證明漏洞存在。
接下來進行漏洞利用、代碼剖析。在剖析之前,先要了解一下此程序的URL路由,便于URL鏈接構造。
4.2.3 URL鏈接構造
首先進入個人資料處,可以看到注冊、登錄、個人資料的鏈接,如下所示。
●注冊:http://localhost/test0/index.php?s=/Member/register.html。
●登錄:http://localhost/test0/index.php?s=/Member/login.html。
●個人資料:http://localhost/test0/index.php?s=/Member/main.html。
通過以上三個鏈接可以得知,目標程序為單一入口文件訪問模式,URL路由的映射采用的寫法是“網站域名/index.php?s=/控制器名/方法名.html”,在這里看到html后綴,基本可以判斷目標程序采用的是偽靜態規則,但是也不絕對,可以嘗試去掉后綴,查看鏈接是否可用,來驗證是否為偽靜態規則。
猜測帶參數的URL鏈接構成如下所示。
網站域名/index.php?s=/控制器/方法/參數名/參數值.html
或
網站域名/index.php?s=/控制器/方法/參數名/參數值
現在我們已經大概知道了鏈接是如何構造的。
接下來查看目錄結構,如圖4-2所示,發現目錄命名結構有點像使用了ThinkPHP框架。打開/Core/Core.php,查看注釋,得知是ThinkPHP框架。
提示:在拿到一款CMS源代碼之后,如果你知道該源代碼采用的開發框架名稱或版本,可公開搜索該框架的使用手冊,直接查看手冊如何設置URL路由映射相關知識點。
假設不知目標程序用的是什么框架,也沒有對應的開發手冊進行分析,也可以猜測到哪個目錄有什么作用功能。
●Admin:后臺功能目錄、后臺的相關類方法、配置文件基本都在此。
●Core:核心目錄。
●install:安裝程序的目錄。
●Public:一般css、js文件、圖片文件、編輯器插件、字體等,都會放在這里面公用。
●Trade:查看該目錄下的文件名,查看文件里的注釋,得知這是接口文件目錄。
●Web:前臺程序功能目錄。
●Runtime:緩存目錄,一般緩存的內容都會生成在這里面。
●偽靜態文件:對程序做偽靜態的配置。

圖4-2 CMS系統源碼的目錄結構
前臺的控制器就在目錄/Web/Lib/Action/控制器名+Action.class.php中。后臺控制器同上,只是將Web改成了Admin,也就是/Admin/Lib/Action/控制器名+Action.class.php,這樣就可以通過構造URL找到路由映射的代碼位置。
下面根據漏洞復現的場景鏈接尋找出現漏洞的代碼進行復現剖析。
4.2.4 漏洞利用代碼剖析
代碼的剖析最終要進行不斷的驗證與分析,下面的分析會更詳細。
1.查看入口文件是否引入了防御腳本
先看一下網站源碼index.php,如圖4-3所示,看到第13行引入了php_safe.php。打開此腳本,查看php_safe.php內的代碼,如圖4-4所示。第2行是//Code By Safe3,推測是360的防御腳本或者改造了的防御腳本。從第24~33行可以看到,不管是GET、POST還是cookie方式傳送的參數都要進行過濾。

圖4-3 index.php源代碼

圖4-4 防御腳本的代碼
2.通過漏洞連接定位漏洞位置
通過以上分析,根據漏洞鏈接可以定位到漏洞位置在\Web\Lib\Action\ApiAction.class.php的ajax_arclist方法中,如圖4-5所示。
提示:一般情況下,我們把自己寫的類里面的方法叫作方法,PHP自帶的方法叫作函數。

圖4-5 ajax_arclist方法
3.分析漏洞源碼
可以看到在ajax_arclist方法的入口處,有很多$_REQUEST來接收參數(_REQUEST[ ]具有$_POST[ ] $_GET[ ]的功能,但是$_REQUEST[ ]執行得比較慢。通過post和get方法提交的所有數據都可以用$_REQUEST獲得),不要因此而迷失了雙眼,先找到有SQL語句的代碼,在第60行、第64行、第70行。
以上三個SQL語句中,可控的參數$where 、$order、 $num、$field分別在第46~48行和第54行被帶入inject_check方法。使用phpStorm編輯器,按住Ctrl鍵,將光標移動至inject_check上點擊鼠標左鍵,選擇/Core/Common/functions.php,定位到第988行的inject_check方法,如圖4-6所示。
從圖4-6中看到eregi方法被劃掉了,這說明該方法被棄用,PHP 5.3x不再支持eregi。這里可以選擇忽略,也可以選擇不忽略。為什么可以這樣選擇呢?因為之前在查看網站源碼index.php的時候知道本程序調用了防御腳本,GET方式傳參的值都會被檢測。另外,這也與你運行該程序時用的PHP版本相關。

圖4-6 inject_check方法
回到上述三個SQL語句,可以看到可控參數被分別帶入了where()、order()、field()、limit()方法中。由于本程序使用的是ThinkPHP框架,因此這四種方法的使用可查看ThinkPHP的手冊。由于ThinkPHP版本很多,最好先打印一下ThinkPHP的版本,在ajax_arclist方法開始處輸入如下代碼:

在顯示的結果中可以看到版本號為2.1。
提示:這里也可以用斷點調試,可根據使用習慣而定。
然后去查看ThinkPHP 2.1版的手冊。因為筆者沒有找到2.1版的手冊,所以這里查看的是3.2版的手冊,這兩個版本間改動不大,所以查看3.2版的手冊也是可以的。四個參數說明如下:
●where()

對應的原生SQL語句如下所示:

●order()

對應的原生SQL語句如下所示:

●field()

對應的原生SQL語句如下所示:

●limit()

對應的原生SQL語句如下所示:

可以構造如下寫法讓四個函數都用到:

生成的SQL語句如下所示:

提示:如果有不理解的地方,大部分原因都是你對PHP相關主流框架或者PHP原生的增刪改查不是很了解。可以簡單學習一下PHP的網站開發基礎知識,再重新來看本書里的內容,你會覺得更輕松。
通過分析發現,在where位置、limit位置和order位置,如果構造可控參數的值為惡意語句的話,都可能會涉及php_safe.php文件中安全防御所使用的危險關鍵詞。這里我們不去研究如何繞過這個防御腳本來進行注入,而是在現有的漏洞環境中分析漏洞產生的原因。但是在field位置,就可以直接構造出用于查詢其他表中字段的攻擊語句?;氐絘jax_arclist的開頭往下走(參見圖4-5),看如何執行第71行的語句。
在第35行我們看到了exit() (提示:終止語句意味著不往下繼續執行),如果要繞過,給變量$model隨便賦值一個存在白名單的字符串,就可以繞過并繼續執行下面的代碼,這里給$model賦值“article”。繼續往下,在第37行判斷是否有傳遞的表名前綴,如果有就與表名拼接;如果沒有就繼續往下執行。在第58行判斷是否有傳參,如果有傳參page值就執行第64行;如果不傳參$page就執行第70行。
4.2.5 Payload構造思路
想要知道賬號和密碼,就要查詢dami_member表中的username、userpwd兩個字段。dami_member是當前CMS所使用的數據庫中的用戶表,username和userpwd是當前用戶表中的數據字段。想要執行如下語句:

就要給field傳參:

構造鏈接訪問以下地址。

在當前環境下,執行的語句如下。

注入的Payload被拼接閉合在原來的SQL語句中,導致顯示了賬號和密碼的輸出,證明了SQL注入漏洞的存在。