本文已首發i春秋論壇Thinkphp框架 3.2.x sql注入漏洞分析_白帽子技術/思路_i春秋社區-分享你的技術,為安全加點溫度.

0x01 前言

Thinkphp 3.2.x用的也挺多的,以前的程序大部分都是用這邊版本的,如果移動到2版本又挺麻煩,而且小程序不說,大程序就複雜很多了。

這次的漏洞是出現在WHERE這這個地方。

0x02 環境搭建和漏洞復現

程序下載地址:thinkphp.cn/donate/down PHPstudy:Apache+php7.1+MySQL 工具:PHPstorm

  1. 首先建立一個資料庫名為:thinkphp
  2. 建立一個表名為:user
  3. 添加兩個欄位:name,pass

  1. thinkphp3.2版本和之前的5版本略有不同,它的資料庫信息文件是在 這個文件:thinkphp/ThinkPHP/Conf/convention.php 在這裡面填上我們剛才建立的資料庫信息:

  1. 打開thinkphp的調試模式: 在剛才的文件:thinkphp/ThinkPHP/Conf/convention.php 然後修改為true: SHOW_ERROR_MSG => true, // 顯示錯誤信息
  2. 這個3.2版本的控制器位置又是和5版本有點區別。具體的可以在本文的參考鏈接詳細查看thinkphp3.2版本的開發手冊。 文件位置:thinkphp/Application/Home/Controller/IndexController.class.php 在裡面寫一個簡單的update的例子:

<?php
namespace HomeController;
use ThinkController;
class IndexController extends Controller
{
public function index()
{
$tj[name] = I(name);
$data[pass] = 111111;
$res = M("user")->where($tj)->save($data);

}
}

I函數和5版本的input助手函數差不多,具體可以看:document.thinkphp.cn/ma

因為我們僅僅執行基本的CURD操作,所以用M方法來實例化資料庫對象就行了。 實例化模型可以看:document.thinkphp.cn/ma 7. 那麼現在就開始執行我們的Payload: http://127.0.0.1/thinkphp/index.php?name[0]=bind&name[1]=0 and updatexml(2,concat(0x7e,user()),0)

0x03 漏洞分析

  1. 這裡也是用phpstorm+debug進行動態分析,配置方法在我上一篇的5版本注入文章裡面也寫過了,如有不懂可以去查閱。 我們先在I函數這裡下一個斷點,看下I函數有沒有過濾掉我們的輸入。

然後訪問我們payload,它會跳到入口文件,我們只要分析的是I函數執行的地方,所以我們直接F8跳到執行I函數地方:

2. F7跟進,它會跳到文件:thinkphp/ThinkPHP/Common/functions.php這裡。 判斷傳入的值是用什麼方式:

接下來就是對我們傳入的值進行過濾:

對我們傳入的bind值進行過濾:

3. 然後執行我們的資料庫更新的操作:

我們F7繼續跟下去,有些影響不大的函數可以直接F8跳過去,到save函數:

執行到update函數我們F7跟進去:

4. 我們繼續往下,F7進入parseSet函數,可以看到賦值了一個佔位符0給pass,代替我們的密碼111111

5. parseSet函數執行完後,我們繼續F7進入parseWhere函數。

我們再往下面的parseWhereItem函數進行分析,這裡寫到,$exp=$val[0]也就是我們傳入的bind

$exp = strtolower($val[0])

這裡判斷如果我們傳入的數組[0]為bind就進行拼接:

6. 從拼接這裡也能看出我們為什麼要把第二個數組構造的時候填0,因為是要對應上面parseSet函數,賦值了一個佔位符為0,用來代替上面的密碼111111,而接下來就沒有這種賦值操作了,所以我們如果填其他值得話執行SQL語句的時候就會報錯,到後面我會點出在哪裡的。

7. 我們繼續,F7進去執行預處理語句的地方:

我們可以看到這裡用到了bindValue,綁定一個值到一個參數,也就是把111111密碼綁定到:0這裡。

8. 繼續跟下來,到SQL語句執行報錯的地方,可以很清楚看到直接了我們的報錯語句updatexml的值:

我們再往error函數跟,可以看到替換掉佔位符的語句:

  1. 如果我們把0換成1會是怎麼樣的結果呢? 訪問payload,注意已經把數組第二個0改成1了。 http://127.0.0.1/thinkphp/index.php?name[0]=bind&name[1]=1 and updatexml(2,concat(0x7e,user()),0)

我們把斷點直接斷在SQL執行的地方:

F7進去然後F8直接走,走到執行報錯的地方,我們就會看到如果為1的話那SQL就無法執行下去了。

0x04 結束

如果調試的時候覺得跟得有點亂的時候,可以耐心的重頭調試多幾次就清楚了。

0x05 參考

php.net/manual/en/book.

document.thinkphp.cn/ma

mp.weixin.qq.com/s?

推薦閱讀:

相關文章