Thinkphp 3.2.3 parseWhere設計缺陷導致update/delete注入 分析
- 2019 年 10 月 3 日
- 筆記
分析
首先看一下控制器,功能是根據用戶傳來的id,修改對應用戶的密碼。
13行把用戶傳來的id參數送入where()作為SQL語句中的WHERE語句,將pwd參數送入save()作為UPDATE語句。
這裡我們假設請求id參數為array("bind","aaa"),pwd參數為bbb。
其中11行12行的意思是獲取id、pwd參數,並通過I函數進行過濾。我們跟進一下I()
可以看到,這裡首先對參數進行htmlspecialchars過濾,然後在最後調用think_filter()函數進行過濾,跟進一下這個函數
可以看到,這裡通過匹配參數中的一些關鍵字,並在其後加上空格。
到這裡I函數就結束了。
回到控制器繼續往下走,首先進入where()
可以看到由於$where是數組、$parser是null,所以三個if都不滿足,直接到1813行,接下來就是將$this->options[‘where’]與$where拼接到一起,用於最終拼湊成一條完整的SQL語句。
繼續跟進就到save函數了。
由於$data非空,到409行。這裡主要對比$data與資料庫中的表中的各個欄位的數據類型是否一致,如果不一致則會進行一些強制轉換或是直接報錯【TODO】。
然後到416行調用了_parseOptions(),這裡用於解析出表名、where中的欄位名等【TODO】。
下面直接跳到最後,調用update函數準備執行SQL語句
跟進update,直接進入899行
跟進parseWhere
其中在536行調用了parseWhereItem,跟進
可以看到,這裡直接拼接了$key和$val[1]到$whereStr中
最後可以看到,$whereStr="`id` = :aaa",其中aaa就是我們一開始傳入的id=array(‘bind’, ‘aaa’)數組中的第二項。由於後來直接被拼接到SQL語句中,因此這個裡存在注入。
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分