public function test01()
{
$data = M('user')->find(I('GET.id'));
var_dump($data);
}
payload:http://tp32.com/index.php/home/index/test01?id[where]=1 and 1=updatexml(1,concat(0x7e,database(),0x7e),1)
漏洞分析:
首先在如下地方進行下斷點分析
一開始肯定是觸發自動加載機制,實例化一個數據庫操作對象
返回接着進入到 I 方法中對接收的參數進行分割判斷
然后 I 方法中進行一次 htmlspecialchars 和 think_filter 的過濾處理
隨后從I方法中出來之后就進入到了 find 方法中
接着來到進入 _parseOptions 方法中,來進行字段的驗證的處理
主要是這段代碼,當我們id[where]
是這樣的時候,這段代碼是不走的,因為is_array($options['where'])
這個條件不滿足
出來了之后接着繼續走select 方法
之后的都很正常數據也沒被處理,最后導致了SQL注入
那么最主要的原因其實也就是 _parseOptions 方法中 字段類型驗證 ,如果is_array($options['where'])
這個條件滿足,那么我們注入的SQL語句都會被_parseType 進行強轉,如果是id[where]則導致不滿足,從而產生了SQL注入!
那么我們來跟下如果傳入的url是http://tp32.com/index.php/home/index/test01?id=1 and 1=updatexml(1,concat(0x7e,database(),0x7e),1)
,結果會如何
首先這里會讓$options[where]下面成為一個數組
然后繼續進入到 _parseOptions 方法中
此時該條件滿足 所以進入到 字段類型驗證的操作
接着繼續進入到 _parseType 的方法中該id字段下的內容,就是sql注入的內容就會被強轉為 int 類型 導致最后無法觸發!!!
修復代碼:
https://github.com/top-think/thinkphp/commit/9e1db19c1e455450cfebb8b573bb51ab7a1cef04
v3.2.4 將 $options 和 $this->options 進行了區分,從而傳入的參數無法污染到 $this->options,也就無法控制sql語句了