要发现PHP框架中因反序列化失控导致的远程代码执行,必须精准定位unserialize()调用点并验证其参数是否可控,否则审计将停留在表面。

确认unserialize()是否被直接调用且参数可控
打开项目全局搜索unserialize(,重点关注控制器、中间件、Session处理器、缓存反取逻辑三类位置。
在匹配结果中逐行检查:参数是否来自$_GET、$_POST、$_COOKIE、$_SESSION或文件读取(如file_get_contents);若参数经过base64_decode()、hex2bin()等编码转换,需继续追踪解码前来源。
遇到类似$data = $_POST['payload']; unserialize($data);的写法,立即标记为高危路径——【该调用未做白名单校验,且输入完全由攻击者控制】。
识别可利用的魔术方法与POP链构造入口
方法一:快速扫描__wakeup()和__destruct()定义位置
使用grep -r "__wakeup\|__destruct" app/ --include="*.php",列出所有含这两个方法的类。优先查看那些具备文件操作(file_put_contents)、命令执行(system)、对象调用($this->callback())能力的类。
立即学习“PHP免费学习笔记(深入)”;
方法二:检查是否存在__toString()且其内部触发危险操作
例如某日志类在__toString()中拼接了$this->msg并调用echo,而$msg又可控,则可能配合异常抛出触发输出泄露;若该类还存在writeLog()方法且$this->file可控,就构成一条可用POP链起点。
注意:Laravel 8+默认禁用__wakeup()自动调用,但若项目降级或自定义反序列化逻辑仍启用,则不能忽略。
验证漏洞是否存在并构造有效载荷
第一步:确认目标类是否存在于当前框架自动加载范围内
访问vendor/composer/autoload_classmap.php,搜索类名是否已注册;若未注册,尝试通过Composer PSR-4映射路径推断真实文件位置,例如App\Models\Payload → app/Models/Payload.php。
第二步:手工构造序列化字符串
编写临时测试脚本,声明目标类,设置可控属性(如$this->filename = '/var/www/html/shell.php'; $this->content = ''),然后serialize()后base64_encode(),作为POST参数发送。
第三步:观察响应差异
若返回500错误伴随“Call to undefined method”或“open_basedir restriction”,说明类已加载但方法不存在或路径受限;若页面空白但shell.php出现在预期目录,则漏洞确认成立。
这一步操作起来很简单,直接把生成的base64字符串填入Burp Repeater的payload字段即可发送。



















