PHP反序列化在CTF赛题中的常见利用场景
TOPIC SOURCE
Bugku-welcome to bugkuctf
说起我第一次在CTF里被PHP反序列化玩得团团转,真是哭笑不得。那天我正准备刷Web题,忽然一个看似普通的unserialize($_GET['p'])把我直接送进了文件读取的坑,后来才发现这背后藏着一整套“魔术方法”玩意儿。
常见的利用切入口
PHP里几个魔术方法最爱被黑客盯上:__toString、__wakeup、__destruct和__invoke。只要对象在序列化后被不经意地调用,就能把属性当成指令跑出来。
- 读取任意文件——利用
__toString在被echo时自动执行file_get_contents($this->file),常见于include($file)配合可控属性。 - 命令执行——
__destruct里写了system($this->cmd),对象销毁时直接跑shell,配合register_shutdown_function更是一键RCE。 - 登录绕过——
__wakeup里检查$this->isAdmin,只要序列化时把属性设为true,登录验证瞬间失效。 - Gadget Chain——借助第三方库(如Laravel、Monolog)里的连环魔术方法,层层触发最终完成文件写入或代码注入。
<?php
class Flag{
public $file;
public function __toString(){
echo file_get_contents($this->file);
return "";
}
}
?>
实战小技巧
我最常用的套路是把payload塞进php://input,配合GET参数的txt=php://input让服务器直接读取POST的序列化字符串。在线工具(比如1024tools的unserialize)能帮我快速把对象结构转成可读的数组,省下不少调试时间。
- 在
GET里控制file参数指向hint.php,再让txt指向php://input,实现“读取+执行”。 - 利用
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}的序列化字符串直接泄露flag。 - 别忘了把
serialize()的结果做URL编码,否则GET太长会被截断。
每次看到审计报告里那句“未过滤的unserialize”,我都会忍不住笑出声——这不就是CTF里最常见的“甜点”吗?下次再遇到类似的题目,记得先把魔术方法列出来,找找有没有可以利用的属性,玩起来才会更顺手。

参与讨论
魔术方法这块得好好记一下。
有没有更简单的payload构造方法?
之前也遇到过__destruct直接执行命令的题。
php://input这招确实好用。
O:4:”Flag”:1:{s:4:”file”;s:8:”flag.php”;} 这个payload直接抄了🤣
看不懂,太复杂了。
感觉反序列化题都一个套路。
求问register_shutdown_function具体怎么用的?
__wakeup绕过登录那个例子挺实用的。
在线工具确实省时间,不然调试太麻烦了。
Gadget Chain是不是得看运气?
这题我卡了半天才想到用__toString读文件。
魔术方法这块儿,实战中经常能卡住思路。