ThinkPHP6.0.13反序列化漏洞分析

發布: 2022-10-09 18:47:34
轉載
2687 人瀏覽過

最近有點閒下來了,不找點事幹比較難受,打算找點漏洞分析一下,於是就打算看看TP的一些漏洞,ThinkPHP6.0.13是TP的最新版,八月份有師傅提交了一個issue指出TP有反序列化問題,網路上也有些師傅分析了一波,不過斷點下的比較多,而且部分方法沒有闡明其用途,所以我也嘗試詳細的分析一波。以下先給POC

ThinkPHP6.0.13反序列化漏洞分析

分析

先看看POC的起始點

ThinkPHP6.0.13反序列化漏洞分析

ThinkPHP6.0.13反序列化漏洞分析

發現起始點在Psr6Cache這個類,我們進入這個類,不過沒有發現__destruct或__wakeup等常見的反序列化起始魔術方法,推測應該在其父類別AbstractCache這個抽象類別中。跟入AbstractCache類別

ThinkPHP6.0.13反序列化漏洞分析

如圖,成功發現本次反序列化鍊子的起始類別。這裡我們可以控制autosave這個屬性為false,從而進入save方法。

回到Psr6Cache類別看這個方法

ThinkPHP6.0.13反序列化漏洞分析

可以發現,pool屬性和key屬性我們都可以控制。因此可能存在兩種路線,呼叫不同類別的同名方法(getItem)。或是直接嘗試觸發__call方法。我們來看看POC作者是怎麼讓反序列化進行下去的。

ThinkPHP6.0.13反序列化漏洞分析

作者用建構法傳入了exp,exp其實是在實例化Channel類別。我們進入Channel類別查看

ThinkPHP6.0.13反序列化漏洞分析

Channel類別中有一個__call方法,那麼作者是選擇觸發__call來讓鍊子繼續下去。這個call方法接受了兩個參數,method是寫死的(getItem),parameters是可控的(即前面可控的key屬性)

ThinkPHP6.0.13反序列化漏洞分析

跟入log方法查看,其接受三個傳參(但其實對後續的鍊子沒啥用),傳入record方法

ThinkPHP6.0.13反序列化漏洞分析

##跟入record方法

ThinkPHP6.0.13反序列化漏洞分析

#再回傳查看作者的POC,發現其控制lazy屬性為false,讓函數進入最後一個if分支執行save方法

1ThinkPHP6.0.13反序列化漏洞分析##那麼save方法應該是比較關鍵的方法了,跟入save方法,這裡面有三個可能被利用的點,作者選擇了哪一個呢?

1ThinkPHP6.0.13反序列化漏洞分析根據POC不難發現作者選擇了控制logger屬性,利用建構子對其賦值,令其為Socket類別的物件

1ThinkPHP6.0.13反序列化漏洞分析

1ThinkPHP6.0.13反序列化漏洞分析在這個類別中,我們找到了一個複雜的同名方法,其中有大量的操作。

1ThinkPHP6.0.13反序列化漏洞分析我們繼續來看作者是怎麼建構的,作者控制config屬性,給其賦值為陣列。陣列有以下內容

1ThinkPHP6.0.13反序列化漏洞分析關鍵在於這兩個鍵值,作者控制config,讓程式執行到呼叫invoke方法的分支

1ThinkPHP6.0.13反序列化漏洞分析同時,app屬性可控,作者令app屬性為App類別的對象,我們進入App類別

1ThinkPHP6.0.13反序列化漏洞分析這裡先看看App類別的的exists方法的情況,在其父類別中找到了這個方法

繼續往後,這裡對App類別進行了唯一一個操作,控制了instances屬性的值。這裡控制其值是為了進入Request類,並且執行url方法

ThinkPHP6.0.13反序列化漏洞分析

2ThinkPHP6.0.13反序列化漏洞分析

#作者在這裡對Request類別做出唯一的操縱,就是控制url屬性的值。可以看出,如果url屬性存在,那麼就會進入第一個分支,其值等於本身。

2ThinkPHP6.0.13反序列化漏洞分析

同時又注意到,complete我們之前傳入的是true。因此最終回傳的結果就是$this->domain().$url,url我們已經控制了,那麼domain方法回傳什麼呢?

2ThinkPHP6.0.13反序列化漏洞分析

#OK,這點我們就不用看了。分析了這麼多,我們得到了$currentUri最後的值,就是:

http://localhost/

2ThinkPHP6.0.13反序列化漏洞分析

currentUri作為一個陣列被傳入invoke了,根據鍊子的長度,達到invoke,我們的反序列化之旅就快結束了

2ThinkPHP6.0.13反序列化漏洞分析

#查看invoke,App類別找不到這個方法,在他的父類別裡找到了這個方法

2ThinkPHP6.0.13反序列化漏洞分析

這裡可以看到。這個函數內有三個分支走向,那麼最後會走向哪裡呢?根據我們先前$config['format_head']的傳入, 首先我們傳入的這個物件不是Closure的實例或子類,也不符合第二個分支的條件

2ThinkPHP6.0.13反序列化漏洞分析

因此進入到第三個分支。我們跟進invokeMethod()方法。這裡傳入的$callabel就是[new \think\view\driver\Php,'display']、而$vars就是['http://localhost/']

2ThinkPHP6.0.13反序列化漏洞分析

注意,我們傳入的$method是數組,因此進入第一個分支。把new \think\view\driver\Php (即物件)賦值給$class,’display’(即方法名稱)賦值給新的$method。

然後下面進行了一個判斷,如果$class是對象,那麼其值就為它本身,因為我們傳入的是對象,所以這裡沒什麼變化。然後進入最關鍵的程式碼

可以看到,把物件new \think\view\driver\Php 以及方法 display傳入了ReflectionMethod。

2ThinkPHP6.0.13反序列化漏洞分析

在最後,呼叫invokeArgs方法,傳入了new \think\view\driver\Php對象,同時傳入了$args

ThinkPHP6.0.13反序列化漏洞分析

#那麼args是什麼呢?

3ThinkPHP6.0.13反序列化漏洞分析

我們跟入之後發現是一個處理函數,因為本人比較懶,而且到這都快分析完了,就不去硬讀了,直接給結論,總之我們傳入的$vars ,也即['http://localhost/'] 其中的關鍵部分保留了下來,並且進入了後續的傳參中

3ThinkPHP6.0.13反序列化漏洞分析

##繼續往後看,對於這個函數(invokeArgs),可以簡單的類比call_user_func(),因此最後的關鍵程式碼其實只有這兩行

3ThinkPHP6.0.13反序列化漏洞分析

#也即

$reflect = new ReflectionMethod(new \think\view\driver\Php,’display’); return $reflect->invokeArgs(new \think\view\driver\Php,’ ’)
登入後複製

常看tp反序列化的朋友就知道,已經結束咧嘴!畢竟呼叫display方法了。但是上述這個呼叫ReflectionMethod類別的操作到底是什麼呢?我們可以藉助如下實例來示範。所以說這玩意和call_user_func很像

3ThinkPHP6.0.13反序列化漏洞分析

最後是display方法,沒什麼好說的了,content傳入display方法中,eval執行指令了

3ThinkPHP6.0.13反序列化漏洞分析

#結語

TP的鍊子一如既往的有意思(以及復雜),特別是最後的ReflectionMethod類別的用法上,如果不了解這個類別以及類別中的方法組合可以實現類似call_user_func函數的作用的話,那麼就很容易錯過這樣一個精彩的漏洞。

【相關教學推薦:thinkphp框架

以上是ThinkPHP6.0.13反序列化漏洞分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:公众号--合天网安实验室
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!