Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

ka1n4t發表於2019-07-31

目錄

分析

首先看一下控制器,功能是根據使用者傳來的id,修改對應使用者的密碼。

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

13行把使用者傳來的id引數送入where()作為SQL語句中的WHERE語句,將pwd引數送入save()作為UPDATE語句。
這裡我們假設請求id引數為array("bind","aaa"),pwd引數為bbb。

其中11行12行的意思是獲取id、pwd引數,並通過I函式進行過濾。我們跟進一下I()

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

可以看到,這裡首先對引數進行htmlspecialchars過濾,然後在最後呼叫think_filter()函式進行過濾,跟進一下這個函式

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

可以看到,這裡通過匹配引數中的一些關鍵字,並在其後加上空格。
到這裡I函式就結束了。

回到控制器繼續往下走,首先進入where()

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

可以看到由於$where是陣列、$parser是null,所以三個if都不滿足,直接到1813行,接下來就是將$this->options['where']與$where拼接到一起,用於最終拼湊成一條完整的SQL語句。

繼續跟進就到save函式了。

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

由於$data非空,到409行。這裡主要對比$data與資料庫中的表中的各個欄位的資料型別是否一致,如果不一致則會進行一些強制轉換或是直接報錯【TODO】。
然後到416行呼叫了_parseOptions(),這裡用於解析出表名、where中的欄位名等【TODO】。

下面直接跳到最後,呼叫update函式準備執行SQL語句

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

跟進update,直接進入899行

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

跟進parseWhere

其中在536行呼叫了parseWhereItem,跟進

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

可以看到,這裡直接拼接了$key和$val[1]到$whereStr中

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

最後可以看到,$whereStr="`id` = :aaa",其中aaa就是我們一開始傳入的id=array('bind', 'aaa')陣列中的第二項。由於後來直接被拼接到SQL語句中,因此這個裡存在注入。

Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析

http://127.0.0.1/thinkphp/thinkphp_3.2.3_full/index.php/home/index/sqli1?id[0]=bind&id[1]=0%20and%20(updatexml(1,concat(0x7e,user(),0x7e),1))&pwd=bbb

總結

本質原因是框架處理pdo時,將使用者可控的字串作為了佔位符,導致sql注入在預處理之前就已經形成了,而所謂的過濾bind只是治標不治本而已(沒做過開發,也有可能這本來就是一種寫法?)。也有可能就是本來入口也就不多吧【TODO】。

哎,好菜。
01點46分

相關文章