當(dāng)在php中創(chuàng)建了一個(gè)對象后,可以通過 serialize() 函數(shù)把這個(gè)對象轉(zhuǎn)變成一個(gè)字符串,保存對象的值方便之后的傳遞與使用。

與 serialize() 對應(yīng)的就是反序列化函數(shù) unserialize() ,它可以將一個(gè)字符串轉(zhuǎn)變?yōu)橄鄬?yīng)的php對象。

其實(shí)本質(zhì)上來說,serialize() 和 unserialize() 在 PHP內(nèi)部實(shí)現(xiàn)上是沒有漏洞的,之所以會產(chǎn)生反序列化漏洞是因?yàn)閼?yīng)用程序在處理對象、魔術(shù)函數(shù)以及序列化相關(guān)問題的時(shí)候?qū)е碌摹?/p>
當(dāng)傳給 unserialize() 的參數(shù)可控時(shí),那么用戶就可以注入精心構(gòu)造的 payload。當(dāng)進(jìn)行反序列化的時(shí)候就有可能會觸發(fā)對象中的一些魔術(shù)方法,造成意想不到的危害。
這里簡單說一下魔術(shù)方法。"Magic Function" 是 php 中一類特殊的方法。這里我們著重關(guān)注以下幾個(gè):
- __construct():當(dāng)對象創(chuàng)建(new)時(shí)會自動調(diào)用。但在 unserialize() 時(shí)是不會自動調(diào)用的。(構(gòu)造函數(shù))
- __destruct():當(dāng)對象被銷毀時(shí)會自動調(diào)用。(析構(gòu)函數(shù))
- __wakeup():unserialize() 時(shí)會自動調(diào)用。
下面結(jié)合代碼可以更好的理解:


下面來看一下很簡單的存在反序列化漏洞的例子:

由于 unserialize() 的參數(shù)可控,我們就,且chybeta類的對象在被銷毀時(shí),會執(zhí)行 $this->test->action 方法,它的 $this->test 我們也可以控制。所以我們可以構(gòu)造如下代碼來生成經(jīng)過序列化后的 poc:

于是,我們就成功構(gòu)造了一句話木馬:

知道了漏洞的原理和利用方式之后,下面就來實(shí)戰(zhàn)一把。
訪問靶場地址:

填點(diǎn)東西,提交表單:

點(diǎn)擊超鏈接“Check Code”,頁面上打印出了 index.php 的源碼:

來分析下代碼。首先看HTML的部分,其中會通過php的foreach循環(huán)來遍歷$todos遍歷的內(nèi)容,并以無序列表的形式顯示在頁面上。
然后看一下表單處理的部分,首先獲取textarea提交的文本,存儲到數(shù)組變量 $todos 中,然后對 $todos 進(jìn)行序列化并存入變量 $m中,
再對 $m進(jìn)行md5加密,加密后的內(nèi)容存到變量 $h中,最后將 $h和$m拼接起來作為 Cookie todos的值,然后重定向到當(dāng)前頁面。
接著,獲取Cookie中 todos的值,分別取出$h和 $m的值,比較兩者是否相等,如果相等,則將$m的值進(jìn)行反序列化,并將結(jié)果存到變量$todos,最終在下面的foreach循環(huán)中顯示在頁面上。
再往上看,有一個(gè)叫 readme的類,該類中重寫了魔術(shù)方法 __toString(),如果用echo 打印該類的對象,則內(nèi)容就是Readme.txt 和 成員變量 $this->source 的內(nèi)容的拼接。

而且可以看到,成員變量可以控制。因此可以按照上面代碼中對Cookie的處理邏輯,構(gòu)造好包含著能反序列化為 readme 對象的字符串,然后放到Cookie中去訪問http://120.203.13.75:8123/uns/index.php ,就能講 flag.php的內(nèi)容打印到頁面上。
于是,在本地構(gòu)造php程序,sez.php 如下:

訪問結(jié)果如下:

再次訪問 http://120.203.13.75:8123/uns/index.php, 然后利用Firefox的Cookie Quick Manager 插件,修改Cookie中todos的值為上面得到的結(jié)果:

保存設(shè)置后的值,然后刷新頁面,flag.php的內(nèi)容就顯示在了頁面上:
