ThinkPHP5.0.x框架SQL注入

漏洞簡述

儘管ThinkPHP 5.0.x框架採用了參數化查詢方式,來操作數據庫,但是在

insert 和 update 方法中,傳入的參數可控,且無嚴格過濾,最終導致本次SQL注入漏洞發生。

ThinkPHP基礎知識

在進行漏洞分析之前,我們需要了解一下ThinkPHP基礎知識,這裡僅介紹對本次漏洞分析有幫助的部分。

ThinkPHP5.0的 目錄結構

thinkphp 應用部署目錄

├─application 應用目錄(可設置)

│ ├─common 公共模塊目錄(可更改)

│ ├─index 模塊目錄(可更改)

│ │ ├─config.php 模塊配置文件

│ │ ├─common.php 模塊函數文件

│ │ ├─controller 控制器目錄

│ │ ├─model 模型目錄

│ │ ├─view 視圖目錄

│ │ └─ ... 更多類庫目錄

│ ├─command.php 命令行工具配置文件

│ ├─common.php 應用公共(函數)文件

│ ├─config.php 應用(公共)配置文件

│ ├─database.php 數據庫配置文件

│ ├─tags.php 應用行為擴展定義文件

│ └─route.php 路由配置文件

├─extend 擴展類庫目錄(可定義)

├─public WEB 部署目錄(對外訪問目錄)

│ ├─static 靜態資源存放目錄(css,js,image)

│ ├─index.php 應用入口文件

│ ├─router.php 快速測試文件

│ └─.htaccess 用於 apache 的重寫

├─runtime 應用的運行時目錄(可寫,可設置)

├─vendor 第三方類庫目錄(Composer)

├─thinkphp 框架系統目錄

│ ├─lang 語言包目錄

│ ├─library 框架核心類庫目錄

│ │ ├─think Think 類庫包目錄

│ │ └─traits 系統 Traits 目錄

│ ├─tpl 系統模板目錄

│ ├─.htaccess 用於 apache 的重寫

│ ├─.travis.yml CI 定義文件

│ ├─base.php 基礎定義文件

│ ├─composer.json composer 定義文件

│ ├─console.php 控制檯入口文件

│ ├─convention.php 慣例配置文件

│ ├─helper.php 助手函數文件(可選)

│ ├─LICENSE.txt 授權說明文件

│ ├─phpunit.xml 單元測試配置文件

│ ├─README.md README 文件

│ └─start.php 框架引導文件

├─build.php 自動生成定義文件(參考)

├─composer.json composer 定義文件

├─LICENSE.txt 授權說明文件

├─README.md README 文件

├─think 命令行入口文件

我們本次的 payload 為:http://localhost/thinkphp/public/index.php/index/index/index?name[0]=inc&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1 ,解釋如下:

http://localhost/thinkphp/ public/ index.php/ index/ index/ index 域名 網站目錄 對外訪問目錄 入口文件 前臺 控制器 方法名

變量獲取

	$name = input("get.name/a");
input()為TP框架的助手函數,get.name/a 表示獲取get傳入的name變量,並將其強制轉換為數組類型

數據庫查詢

	Db::table("users")->where(["id"=>1])->insert(["username"=>$name]);
TP框架採用的是PDO方式對數據庫進行查詢

環境搭建

在瞭解了基本知識後,我們可以開始搭建環境。這裡我們使用ThinkPHP 5.0.14版本來進行實驗,下載地址:http://www.thinkphp.cn/download/1107.html

我們先安裝好phpstudy,然後將下載好的ThinkPHP 5.0.14解壓至phpstudy的網站根目錄下,安裝ThinkPHP 5.0.14需要Mbstring、PDO、Curl三個插件,php版本這裡用5.6。

ThinkPHP5.0.x框架SQL注入

接著我們需要配置連接數據庫的文件,並開啟thinkphp的調試功能。在此之前,你需要先在數據庫中創建用於測試的數據,例如這裡我用thinkphp作為數據庫名,那麼就在mysql命令行下執行create database thinkphp; 然後在建立一個users表,列名有id,username,password,執行create table users(id int auto_increment primary key,username varchar(20),password varchar(30)); 即可,最後我們往表中插入測試數據,命令行執行insert into users(id,username,password) values(1,"test","thinkphp"); 這樣就算測試數據創建成功了。

ThinkPHP5.0.x框架SQL注入

配置連接數據庫的文件,並開啟thinkphp的調試功能,如下圖:

ThinkPHP5.0.x框架SQL注入

最後修改文件 application\index\controller\Index.php 的內容,如下:

namespace app\index\controller;
use think\Db;
class Index
{
public function index()
{
$name = input("get.name/a");
Db::table("users")->where(["id"=>1])->insert(["username"=>$name]);
return "ThinkPHP SQL Test.";

}
}

修改好後,訪問我們的payload就可以觸發漏洞了

ThinkPHP5.0.x框架SQL注入

漏洞分析

首先,我們知道 insert 方法存在漏洞,那就查看 insert 方法的具體實現。該方法位於 thinkphp\library\think\db\Builder.php 文件中,我們可以看到在函數開頭調用了 parseData

方法,並將 $data 作為參數傳入, $data 的值是我們通過 get方式傳入的一個數組類型的數據,如下圖:

ThinkPHP5.0.x框架SQL注入

我們跟進 parseData 方法,該方法也在 thinkphp\library\think\db\Builder.php 文件中。可以看到,在結尾處有個switch語句,而且進入該語句後,會跳到case 'inc'的地方,這裡關鍵就是看看 $this->parseKey 是否有對 $val[1] 變量進行過濾了,因為

$val[1] 變量就是我們payload中的updatexml(1,concat(0x7,user(),0x7e),1) ,如下圖:

ThinkPHP5.0.x框架SQL注入

繼續跟進 parseKey 方法,會發現直接將傳入的 $key 返回了,沒有進行任何過濾。

ThinkPHP5.0.x框架SQL注入

我們再回到最開始的 insert 方法,加上調試語句,看看此時的sql語句變成了什麼樣子,如下圖:

ThinkPHP5.0.x框架SQL注入

另一處update函數的注入與這個insert是類似的,這裡就不在贅述。

總結

筆者也是第一次審計Thinkphp框架,在審計這套框架前還找了網絡上的視頻快速入門了下,再結合Thinkphp5.0手冊,完成此次漏洞的審計。當然,文章有不當之處,還希望大家斧正。


分享到:


相關文章: