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, 蓝队分析, 请求拦截