mosajjal/wp2shell-go
GitHub: mosajjal/wp2shell-go
WordPress 未授权批量路由混淆 SQL 注入漏洞的 Go 移植 PoC,提供漏洞检测、盲注数据提取及后渗透辅助功能。
Stars: 1 | Forks: 0
# wp2shell-go
wp2shell PoC 的一个 Go 移植版本。它针对的是 Searchlight Cyber 在 wp2shell 安全通告中披露的 WordPress 未授权 REST 批量路由混淆 SQL 注入漏洞。所有操作都通过同一个端点进行:`POST /wp-json/batch/v1`。
这不是 Searchlight 的官方检查工具,也不复现任何未公开的 wp2shell 内部机制。`check` 用于确认 SQLi 路径,`read` 通过盲注提取数据,而 `shell` 是一个可选的后渗透辅助工具,用于在你已经拥有管理员凭据后上传插件型 webshell。
仅使用标准库。没有第三方 Go 依赖,无需执行 `go get`。
## 受影响版本
| 版本范围 | 状态 |
| ------------- | ------ |
| <= 6.8.5 | 不受影响 |
| 6.9.0 到 6.9.4 | 受影响 |
| 7.0.0 到 7.0.1 | 受影响 |
## 工作原理
`/batch/v1` 端点无需授权,可以在一次调用中执行多个子请求。它依赖于每个子请求各自进行验证和权限检查,而这个假设正是漏洞的突破口。
`serve_batch_request_v1()` 构建了两个并列的数组。`$matches` 包含每个子请求匹配到的 handler,`$validation` 包含每个子请求的验证结果,并且分派时会使用相同的索引对两者进行检索。路径无法通过 `wp_parse_url()` 解析的子请求会被追加到 `$validation` 中,但不会被追加到 `$matches` 中。此时这两个数组就产生了错位,导致某个子请求会在另一个子请求的 handler 下运行。这就是路由混淆。
该 PoC 将这个技巧嵌套使用了两次:
1. 一个携带 `requests` 主体的 `POST /wp/v2/posts` 请求落入到了批量 handler 自身中。因为它被当作 posts 请求进行验证,其 `requests` 列表永远不会被拿来与批量 schema 进行校验,因此内部的子请求可以自由使用 `GET`。方法白名单就此失效。
2. 在那个内部批量请求中,一个携带 `author_exclude` 字符串的 `GET /wp/v2/users` 请求。由于 users schema 中没有这个参数,该值便毫无阻拦地通过了验证。它被分派到了 posts 的 `get_items()` handler 下,在那里 `author_exclude` 被映射到了 `WP_Query` 的 `author__not_in` 查询变量中,而存在漏洞的版本会将其作为原始字符串直接拼接到 SQL 中。
最终导致的结果是,你可以在未授权的情况下触发布尔型和时间型盲注 SQL 注入。此代码库利用该读取路径来提取管理员密码哈希。将哈希转化为上传插件形式的代码执行是另一个独立的步骤,它需要破解出的明文,因此它不属于未授权利用原语的一部分。
Searchlight 尚未公布从 SQLi 到未授权 RCE 的最终跨越步骤,此代码库也未曾涉及。
## 构建
```
go build -o wp2shell .
```
或者执行 `make build`。需要 Go 1.23 或更高版本。
## 用法
```
./wp2shell [options]
```
### check(检测)
被动方式启动。它会打印 WordPress 标识和公开的版本提示,然后发送一个无害的批量标识探针。存在漏洞的版本会返回 HTTP 207 以及完整的标识模式:`parse_path_failed`、`block_cannot_read` 和 `rest_batch_not_allowed`。
该探针直接源自核心代码的修复补丁。格式错误的 `///` 请求会产生 `parse_path_failed`。一个 `/wp/v2/posts` 请求充当允许批量的间隔符。`/wp/v2/block-renderer/...` 路由不允许批量,但如果其 handler 被匿名访问,它会返回 `block_cannot_read`,而 `/batch/v1` 会给出 `rest_batch_not_allowed`。在受漏洞影响的构建版本中,解析错误会导致 handler 数组错位,从而使得间隔符请求在 block-renderer handler 下运行。而已修复的构建版本会保持数组对齐,因此对于构造的探针来说,不会出现这种精确的三码组合模式。
默认情况下,`check` 到此为止,不会发送任何 SQL payload。添加 `--confirm-sqli` 可进行主动的成对时间确认。该步骤不读取任何内容,也不更改任何内容。它会发送三对基线/延迟请求,并根据中位数差值做出判断,这可以防止网络抖动产生误报。
```
./wp2shell check http://target
./wp2shell check http://target --confirm-sqli
```
### read(读取)
```
./wp2shell read http://target # server fingerprint
./wp2shell read http://target --preset users # logins and password hashes
./wp2shell read http://target --query "SELECT @@version"
```
提取器通过二分法逐个读取字符的字节值,因此对于短字符串,每个字符只需少量请求即可完成提取。速度慢且请求量大,但在盲注下依然有效。
### shell(命令执行)
这是一个可选的后渗透辅助工具,而不是未授权 RCE 步骤。它需要有效的管理员凭据。如果 `read --preset users` 为你提供了一个哈希值,请离线破解它,并将明文传递到此处。
```
./wp2shell shell http://target --user admin --password '' --cmd id
./wp2shell shell http://target --user admin --password '' -i # interactive
```
它会在一个随机路径和单次运行 token 的掩护下上传一个插件型 webshell,然后打印出该路径。操作完成后请务必进行清理。可以通过传递 `--cleanup` 让其在运行完毕后自行删除,或者手动移除该插件。
## 选项
| 选项 | 应用于 | 描述 |
| ------ | ---------- | ----------- |
| `--rest-route` | check, read | 对未启用固定链接的站点使用 `/?rest_route=/batch/v1`。 |
| `--proxy URL` | all | 通过 HTTP proxy 路由流量,例如 Burp。 |
| `--timeout N` | all | 请求超时时间(秒)。 |
| `--sleep N` | check | 与 `--confirm-sqli` 配合使用的延迟时间。 |
| `--samples N` | check | 与 `--confirm-sqli` 配合使用的时间样本对数(默认为 3)。 |
| `--confirm-sqli` | check | 同时发送主动的 SQL 时间确认 payload。 |
| `--preset` | read | `fingerprint` 或 `users`。 |
| `--query` | read | 要读取的标量 SQL 表达式。 |
| `--prefix` | read | 数据库表前缀(默认为 `wp_`)。 |
| `--max-length N` | read | 每个值读取的字符数上限(默认为 128)。 |
| `--user` / `--password` | shell | 管理员凭据,从哈希恢复出的明文。 |
| `--cmd` | shell | 要运行的命令(使用 `-i` 时省略)。 |
| `-i` / `--interactive` | shell | 部署后打开交互式 shell。 |
| `--cleanup` | shell | 完成后从目标删除 webshell。 |
| `--keep` | shell | 不要对移除 webshell 发出警告。 |
## 目录结构
```
main.go CLI entry point
internal/cli/ argument parsing and command dispatch
internal/wp/ the primitive: client, sqli, shell, version
internal/integration/ live-target tests (build tag: integration)
test/ docker-compose target and integration runner
```
## 测试
单元测试无需任何外部依赖:
```
go test ./...
```
集成测试针对真实的、存在漏洞的 WordPress 7.0.1 容器运行。运行器会启动 WordPress 和 MariaDB,安装站点,针对其运行 Go 集成测试和 CLI 二进制文件,然后销毁环境:
```
make integration
# 或者: ./test/run-integration.sh
# KEEP=1 ./test/run-integration.sh # 保持 stack 运行
```
该测试套件针对实时目标验证了整个利用链:检测和版本指纹识别,路由混淆标识探针,对 MariaDB 版本的盲读,基于时间的 oracle(预测器),从 `wp_users` 中恢复管理员登录名和密码哈希,以及经过授权后的 webshell 部署、运行和清理。最后一次运行成功恢复了 `1|admin|$wp$2y$10$...` 并以 `www-data` 身份执行了 `id`。
## 修复建议
升级至 WordPress 7.0.2;如果你使用的是 6.9 分支,请升级至 6.9.5。在能够进行升级之前,请在边缘网络(edge)拦截 `/wp-json/batch/v1` 以及 `rest_route=/batch/v1` 查询参数,或者通过 `rest_pre_dispatch` filter 要求对批量端点进行授权验证。
## 法律声明
仅供授权的安全测试使用。请仅在你拥有或已获得明确书面授权的系统上使用。不作任何保证,对滥用行为不承担任何责任。
## 参考
- WordPress 7.0.2 发布公告:
- Searchlight Cyber wp2shell 安全通告:
- 本项目移植自的 Python PoC:
标签:CISA项目, EVTX分析, Go, Ruby工具, Web安全, WordPress, 日志审计, 漏洞验证PoC, 蓝队分析, 请求拦截