目录
本文讲解CISP-PTE靶场反序列关卡渗透的全流程。首先打开靶场页面,分析获取密钥的PHP源码,该代码通过反序列化验证用户输入与预设字符串TEMP的匹配性。渗透过程分为序列化计算和实战两个步骤:先使用PHP脚本生成TEMP的序列化字符串"s:44:"Whatever..."",然后通过GET请求将该字符串传给str参数。当服务端反序列化结果与$TEMP完全匹配时,会输出key4.php中的密钥值,成功获取flag。该方法利用了反序列化机制的特性,通过构造精确匹配的序列化数据绕过验证。
一、渗透准备
1、打开靶场
打开靶场,页面提示"++序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。++",如下所示。

2、开始答题
点击开始答题,进入如下带有源码的页面,这段PHP代码实现了一个基于反序列化验证的密钥获取机制。代码首先引入存储密钥的key4.php文件,并预设固定字符串TEMP。通过GET参数str接收用户输入的反序列化数据,当反序列化结果与TEMP全等匹配时,输出密钥$key4的值。

3、源码分析
如下所示,这是一个典型的反序列化的简单密钥获取关卡,由于 TEMP 是一个普通字符串,我们需要将 TEMP 序列化后的字符串通过 str 参数传递,这样 unserialize(_GET['str']) 就会返回 "Whatever is worth doing is worth doing well.",从而满足条件,打印出 key4。详细注释后源码如下所示。
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <?php // 关闭所有错误报告,避免执行过程中显示敏感错误信息 error_reporting(0); // 引入外部文件key4.php,该文件中应包含key4变量,存储目标密钥 include "key4.php"; // 定义固定字符串变量TEMP,作为反序列化验证的基准值 TEMP = "Whatever is worth doing is worth doing well."; // 从GET请求参数'str'中获取用户输入的序列化字符串 str = _GET\['str'\]; // 反序列化处理:将字符串转换为PHP值,并与TEMP进行全等比较(类型和值都必须相同) if (unserialize(str) === TEMP) { // 如果验证通过,输出密钥key4的值 echo "key4"; } // 高亮显示当前文件的源代码(通常用于调试或教学展示) show_source(FILE); |
(1)反序列化机制
-
unserialize()将序列化字符串还原为PHP值 -
序列化格式:
s:44:"Whatever is worth doing is worth doing well.";-
s表示字符串类型 -
44表示字符串长度 -
引号内为具体内容
-
(2)验证逻辑
-
使用全等比较
===确保类型和值完全匹配 -
必须精确匹配字符串内容和长度
(3)安全设计
-
error_reporting(0)防止错误信息泄露 -
show_source(__FILE__)提供代码透明度
二、渗透实战
1、序列化计算
根据反序列化源码,编写code,具体如下所示。
<?php
$TEMP = "Whatever is worth doing is worth doing well.";
echo serialize($TEMP);
?>
参考来源于如下反序列化的简单密钥获取的源码(答题页面显示的code),具体如下所示。

2.使用菜鸟工具执行php脚本结果
https://c.runoob.com/compile/1/
生成结果如下所示:s:44:"Whatever is worth doing is worth doing well.";

2、渗透实战
通过向/start/index.php发送GET请求,并在str参数中传入经过正确序列化的字符串s:44:"Whatever is worth doing is worth doing well.";,以此触发服务端反序列化验证机制。由于该序列化数据与服务端预设的TEMP变量完全匹配,条件判断为真,系统将执行echo key4输出隐藏的密钥。此操作可直接获取key4.php中存储的flag信息,如下所示渗透成功。
s:44:"Whatever is worth doing is worth doing well.";
http://cf0c1e93.clsadp.com/start/index.php/start/index.php?str=s:44:"Whatever is worth doing is worth doing well.";
本次攻击的主要原理是构造正确的序列化字符串作为GET参数:?str=s:44:"Whatever is worth doing is worth doing well.";服务端接收参数后执行 unserialize($str),将序列化数据还原为原始字符串。还原后的字符串与预设的 $TEMP 变量进行全等比较 (===),因内容与长度完全匹配,条件成立。验证通过后,服务端输出 key4.php 中存储的密钥值 (echo $key4),从而直接获取目标 flag。

三、渗透总结
1、基本概念
反序列化安全风险是发生在应用程序将序列化数据还原为对象或数据结构过程中的安全缺陷,攻击者通过构造恶意序列化数据在目标系统上执行非预期操作,属于高危风险。
- 序列化:将对象的状态信息(如属性、数据)转换为可存储或传输的格式(如二进制、XML、JSON、特定语言的序列化格式等)的过程。目的是便于数据在网络传输、本地存储等场景中使用。
- 反序列化:将序列化后的数据流恢复为原始对象的过程,使程序能重新使用该对象的状态和方法。
2、反序列原理
当程序接收不可信的序列化数据(如用户输入、网络传输的数据),并直接对其进行反序列化操作时,攻击者可通过构造恶意的序列化数据,在反序列化过程中触发对象的特殊方法(如构造函数、析构函数、__wakeup()、__destruct()等)或调用链,最终执行恶意代码(如命令执行、文件读写、服务器控制等)。关键条件如下所示。
- 程序存在反序列化操作,且输入的序列化数据可控(攻击者可构造)。
- 反序列化过程中调用了危险的方法或存在可利用的调用链。
- 程序未对序列化数据进行严格的校验(如签名验证、格式检查、白名单限制等)。
3、攻击流程分析
本观看的攻击流程始于对PHP反序列化机制的恶意利用:攻击者首先精确构造序列化字符串s:44:"Whatever is worth doing is worth doing well.";,其中s明确定义数据类型为字符串,44精确计算并声明字符串长度,冒号后为完整的目标字符串内容。通过HTTP GET请求将构造的序列化数据作为str参数传递给服务端,当服务端的unserialize()函数解析该参数时,会严格按格式说明重建字符串对象。由于重建后的字符串在类型、长度及内容上与预设的$TEMP变量完全一致,系统判定条件成立,进而触发密钥输出逻辑,执行echo $key4显示敏感信息。整个过程揭示了反序列化功能中,若未对输入数据施加严格的来源验证与内容过滤,仅依赖格式匹配即可被利用为泄露关键数据的有效通道。如下为总结的利用 PHP 反序列化获取密钥的标准过程:
(1) 序列化数据构造
将目标字符串 "Whatever is worth doing is worth doing well." 序列化为 s:44:"..." 格式,其中 s 表示字符串类型,44 为精确字符长度。
(2) 参数传递
通过 GET 方式将序列化字符串作为 str 参数传递给服务端:?str=s:44:"Whatever is worth doing is worth doing well.";
(3)服务端处理
服务端接收参数后执行 unserialize($str),将序列化数据还原为原始字符串。
(4)条件验证
还原后的字符串与预设的 $TEMP 变量进行全等比较 (===),因内容与长度完全匹配,条件成立。
(5) 密钥输出
验证通过后,服务端输出 key4.php 中存储的密钥值 (echo $key4),从而直接获取目标 flag。