PHP反序列化靶场实战

使用的是探姬制作的反序列化靶场 PHPSerialize-labs

直接下载ZIP后用中间件指向目录即可,小皮也可以

Level 1: 类的实例化

打开题目,我们看到定义了一个类 FLAG,在该类中还使用了 __construct() 方法,在创建对象时会自动调用

使用

new xxx();

来实例化一个对象

得到flag

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 = "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');
}
Now Flag is ???

我们可以发现,flag值应该就在flag_string变量中,那么我们可以有多种方法获取到其值

方法一:直接输出

我们发现flag_string变量是一个全局变量,他是定义在类之外的。那么直接输出其值

code=echo $flag_string; exit;

方法二:利用变量传递

我们观察代码,发现下方会调用get_free_flag()函数,该函数会输出free_flag的值,那么我们修改 $target->free_flag 使其等于 $flag_string

-> 用于访问 ​对象的属性(变量)或方法(函数)​。它的作用类似于其他语言中的 .(如 JavaScript、Python)

code=$target->free_flag = $flag_string;

然后就可以直接输出flag了

方法三:暴力输出所有变量

既然flag存储在变量中,那么我们直接输出所有变量再观察flag即可。

code=var_dump(get_defined_vars());

然后就看到flag

level 3:对象中值的权限

方法一:暴力获取所有变量

源代码:

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

?>
Trying to get FLAG...
Public Flag: HelloCTF{se3_me_
Protected Flag: Error: Cannot access protected property FLAG:: in ?
Private Flag: Error: Cannot access private property FLAG:: in ?
...Wait,where is the flag? 

还是同上一题一样,所有的值存储在变量中,同时观察代码容易发现,flag是被分为了三部分,第一部分为HelloCTF{ 开头,第二部分为不带大括号的中间内容,第三部分是以反大括号结尾的。

code=var_dump(get_defined_vars());

方法二:逐个输出变量

本题中,protected_flagprivate_flag两个变量不是全局变量,是在FLAG类中的私有变量,也就是说在该类中才可调用,我们观察到在代码中有创建对象的操作,即 $target=new FLAG(); ,那么我们直接输出这个对象中的值即可

code=echo $target->public_flag,$target->get_protected_flag(),$target->get_private_flag();exit;

获取类中的变量这个和python也是一样的,如我也创建一个FLAG类

class FLAG:
    def __init__(self):
        self.public_flag = "flag{"
        self._protected_flag = "哈哈哈"
        self.__private_flag = "终于要放假了}"

target  = FLAG()

try:
    print(public_flag)
    print(protected_flag)
    print(private_flag)
except:
    print("你TM都不知道自己在干啥")

print(target.public_flag+target._protected_flag+target._FLAG__private_flag)

在类中同样切分三部分,不同的只是,在python中,类之内变量默认为public, _ 表示protected, __代表private,我们实例化对象之后,才可以调用它的 protected 和 private 变量。

可以看到,上面直接调变量名的都无法访问,下方加上实例化的变量名,同时private变量还要加上.类名才能正常访问

level 4:序列化初体验

首先查看源码

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__);
}

观察代码,发现流程是:

  1. 定义了两个类:
    • FLAG3类:包含一个私有属性$flag3_object_array,是一个数组,初始值为两个问号
    • FLAG类:包含三个私有属性:
      • $flag1_string:字符串,初始为问号
      • $flag2_number:数字(但用字符串表示),初始为问号
      • $flag3_object:一个FLAG3类的对象
  2. 程序创建了一个FLAG类的实例$flag_is_here
  3. 然后检查是否有POST参数code
    • 如果有,就执行eval($code)
    • 如果没有,就高亮显示当前文件内容

方法一:暴力输出变量

依旧是直接暴力输出变量的值,使用:

code=var_dump($flag_is_here);

输出实例化之后的对象中所有的值

可以看见flag1_string变量的值应该就是flag

方法二:使用ReflectionClass

ReflectionClass 是 PHP 的反射类,用于在运行时动态获取和操作类的信息(如属性、方法、接口等),无需实例化即可分析类结构。

核心功能​:

  1. 获取类名、命名空间、父类、接口等元信息。
  2. 检查类特性(是否抽象、接口、Trait)。
  3. 访问私有/受保护属性和方法(通过 setAccessible(true))。
  4. 动态实例化对象(即使构造函数私有)。

典型用途​:依赖注入、单元测试、代码分析工具。

示例​:

$class = new ReflectionClass('User');  
$props = $class->getProperties(); // 获取所有属性
$methods = $class->getMethods(); // 获取所有方法

最终Payload:

code=$ref=new ReflectionClass($flag_is_here);$prop=$ref->getProperty("flag1_string");$prop->setAccessible(true);echo $prop->getValue($flag_is_here);

主要是这几步:

​1、创建反射类对象

$ref = new ReflectionClass($flag_is_here);
  • 获取 $flag_is_here 的类信息。

​2、获取目标属性

$prop = $ref->getProperty("flag1_string");
  • 找到类中的 flag1_string 属性(可能是 privateprotected)。

绕过访问限制

$prop->setAccessible(true);
  • 允许访问私有/受保护的属性。

获取并输出属性值

echo $prop->getValue($flag_is_here);
  • 读取 $flag_is_here 对象的 flag1_string 值并打印。

方法三:序列化

PHP在序列化的时候,会把protected和private属性的变量也同时序列化,只是为了区分不同作用域的属性,PHP 会在私有属性名前添加:

  • private 属性 → \x00类名\x00属性名(如 FLAGflag1_string
  • protected 属性 → \x00*\x00属性名
  • public 属性​ → 直接存储属性名

level-5:序列化的普通值规则

直接看源代码

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

只要这几个变量的反序列化之后的值等于if中这些变量的值,那么就可以获得flag了。那么也就是说,直接把对比结果序列化,然后再对应给相应的变量即可。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇