面向影响 5 亿+ 网站的 WordPress 预认证 XSS-to-RCE 攻击链的行为优先批量扫描器与证据级 PoC 生成器。
仅用于检测。不进行武器化。专为漏洞赏金计划和蓝队打造。
这是什么? • 快速开始 • Shodan 搜索语法 • 使用方法 • 判定矩阵 • 检测 • 常见问题
在扫描之前,先在整个互联网上寻找可能存在漏洞的 WordPress 实例:
http.component:"wordpress" -http.title:"Just a moment"
查找 WordPress 站点,同时排除 Cloudflare「I'm Under Attack」模式 / 机器人防护页面,这些页面会拦截或质询自动化请求。
http.component:"wordpress" http.title:"Log In"
仅返回 WordPress 登录页面 — 这正是 CVE-2026-64638 的确切攻击面。
http.component:"wordpress" "wp-content" "?ver=7.0" -"?ver=7.0.3"
通过资源版本指纹识别,标记出未应用 7.0.3 补丁的 WordPress 7.0.x 实例。
http.component:"wordpress" http.html:"wp-login.php"
捕获那些 wp-login.php 可访问但未必是当前页面的站点 — 覆盖面更广。
http.component:"wordpress" -http.title:"Just a moment" -http.title:"Attention Required" -org:"Cloudflare"
激进的过滤器,可剔除大多数由 Cloudflare 前置的目标。在配合 --active 大规模扫描时使用 — Cloudflare 会对探测请求进行限速或拦截。
提示: 使用
shodan download导出 Shodan 结果,并将主机名直接管道输入xss2shell_mass.py -i。
2026 年 8 月 7 日,pwn.ai 披露了 CVE-2026-64638(XSS2Shell) — 这是 WordPress Core 中一个严重的预认证跨站脚本漏洞,可在服务器上一路串联升级为远程代码执行。[citation:pwn.ai blog]
该漏洞利用了 PHP 的 strip_tags() 与 WordPress 的 wp_kses_post() 之间的解析器分歧:
strip_tags() 使用紧跟字母的 < 来识别 HTML 标签。< area id=...>(带空格)会被视为文本 — 因此它能存活。wp_kses_post()(KSES)将 < area 识别为有效的 <area> 元素 — 而 <area> 在 KSES 中属于白名单元素。[citation:pwn.ai blog]一次使用特制用户名 < area id=ajaxurl href=/?rest_route=/&_method=GET&_jsonp=alert>... 的失败登录即可同时绕过这两种过滤器,在登录页面上被渲染为实时 DOM,通过 DOM 污染劫持 WordPress 自身的 user-profile.js 脚本,并在 WordPress 源中触发 alert() — 零点击、零认证、零 Cookie。[citation:pwn.ai blog]
升级为已登录的管理员?同样的原语可通过同源方法执行(SOME)窃取应用程序密码,上传恶意插件,并以 www-data 身份执行 PHP。[citation:pwn.ai blog] [citation:hadrian.io blog]
受影响版本: WordPress 6.4 至 7.0.2 — 已在 7.0.3 中修复,并向后移植到 4.7+。
影响范围: 披露时约 5 亿个网站。[citation:pwn.ai blog]
这是一个仅用于检测的工具包。它不会将漏洞武器化 — 它为安全研究人员、漏洞赏金猎人和蓝队提供所需的一切,以便:
「版本字符串只能说明代码应该处于什么补丁级别。
只有登录页过滤器(sanitizer)的行为才能说明该漏洞是否真的触发。」
托管主机会在静默中向后移植安全补丁,而不更新版本字符串。登录加固插件则会完全替换错误消息,即使在不安全的版本上也会封死反射通道。仅凭版本判断的扫描器既会产生误报,也会产生漏报。 本扫描器只发送一个良性探测请求,并对实际的过滤器行为进行分类。
git clone https://github.com/jakestone/xss2shell.git
cd xss2shell
pip install -r requirements.txt
# Passive — no probes sent to target, version + endpoint fingerprinting only
python3 xss2shell_mass.py -i domains.txt -o results
# Active — sends ONE benign failed-login per host (authorized assets only!)
python3 xss2shell_mass.py -i domains.txt -o results --active --workers 80
# Single target
python3 make_poc.py --target https://blog.example.com
# Batch from scanner output
python3 make_poc.py --from-results results.csv -o pocs/
在录制视频的同时,在浏览器中打开生成的 .poc.html → 如果 alert() 触发,你就捕获到了预认证 XSS 的证据。
xss2shell_mass.py)usage: xss2shell_mass.py [-h] -i INPUT [-o OUTPUT]
[--active] [--workers WORKERS]
[--timeout TIMEOUT] [--quiet]
?ver= 参数、wp-content 引用)user-profile.js gadget 已入队、核心资源版本/?rest_route=/&_method=GET&_jsonp=<random> 发起无害的 GET 请求 — JSONP 路径是否开放?--active 标志)发送一次用户名为 < area id=<RANDOM> href=/x2s> 的失败登录,并对 HTML 响应进行分类:
bypass — 带有我们标记的真实 <area> 元素存活 → 确认存在 strip_tags/KSES 不一致escaped — 标记存在但已被实体编码 → 已打补丁或已加固stripped — 显示默认 WP 错误,标签已被移除 → acevomod 或已打补丁closed — 完全没有用户名回显 → 已安装登录加固插件make_poc.py)usage: make_poc.py [-h] [--target TARGET] [--from-results FROM_RESULTS]
[-o OUTDIR]
为每个目标生成已发布的 pwn.ai PoC 页面 — 即能在未修补的 WordPress 上触发 alert() 的精确 HTML 表单。注释中包含三种载荷变体:
扫描器的判定引擎将版本分类(来自 WordPress.org 的 stable-check API)与行为证据相结合,产生 10 种不同的判定结果:
CSV 列: host、url、status、checker_status、wp_version、branch_status、evidence、http、ms、error
checker_status 列映射到 pwn.ai 公共检查器的词汇表(vulnerable / patched / not_wordpress / unreachable / inconclusive / error),便于直接关联。
如果你处于防御方,以下是该漏洞留下的取证信号:
# Primary signal: encoded '<' in the log parameter
POST /wp-login.php → log=%3C... (URL-encoded < in username field)
# Higher confidence: paired with REST pivoting
GET /?rest_route=/&_method=GET&_jsonp=... # JSONP callback
GET /wp-json/wp/v2/statuses/publish?_jsonp=... # WAF-bypass variant
# Escalation stage indicators
GET /wp-admin/authorize-application.php?success_url=<off-origin>
POST /wp-admin/update.php?action=upload-plugin
GET /wp-content/plugins/<random>/shell.php
拦截 log 参数包含 %3C(URL 编码的 <)的 POST /wp-login.php 请求。有效的 WordPress 用户名绝不会包含尖括号。不要将规则限定到特定标签 — KSES 允许在 < 后出现制表符、换行符、回车符以及任何白名单标签,因此针对特定标签的规则很容易被绕过。[citation:hadrian.io blog]
升级阶段的 _jsonp= 回调使用点号进行属性遍历(例如 window.opener.approve.click)。请将包含带点号 JSONP 回调的 REST 请求标记为利用行为的有力指标。[citation:hadrian.io blog]
THIS TOOL IS DETECTION-ONLY. IT DOES NOT:
✗ Weaponize the JSONP callback beyond the public alert()
✗ Include admin-lure pages or Application Password capture
✗ Include REST abuse, plugin upload, or PHP shell code
✗ Execute more than one failed login per target per scan
YOU MUST:
✓ Only scan assets you own or have written authorization to test
✓ Only generate PoCs for your own browser on your own server
✓ Never send PoC links to site admins/users
✓ Never escalate past alert() without program written approval
✓ Follow the bug bounty program scope and rules
This toolkit exists for authorized security research, bug bounty
programs, and defensive detection engineering. Misuse is your
responsibility.
xss2shell/
├── README.md ← You are here
├── xss2shell_mass.py ← Behavior-first mass scanner (v1.1.0)
├── make_poc.py ← Evidence-grade PoC page generator
├── requirements.txt ← Python dependencies (just `requests`)
├── .gitignore ← Ignores scan outputs and cache
└── example/
├── domains.txt ← Example input file
└── example_output.csv ← Example scan output
问:为什么不直接检查 WordPress 版本字符串?
答: 托管主机(WP Engine、Kinsta、Pantheon 等)经常在静默中向后移植安全补丁而不更新版本号。登录加固插件会完全替换错误消息。这两种情况都会让仅凭版本的扫描器产生误报,也会让隐藏版本产生漏报。本扫描器测试的是实际的过滤器行为。
问:--active 探测有危险吗?
答: 没有。它只发送一次带有良性标记用户名的失败登录。它不会尝试执行 JavaScript,不会枚举有效用户名,也不会触发任何实际利用。它比一次标准登录尝试的侵入性更低。
问:这个工具可以用于未授权扫描吗?
答: 不可以。主动探测会向 /wp-login.php 发送 HTTP POST,这是对目标服务器的一次请求。只能在你自己拥有或获得明确书面授权测试的资产上使用。
问:vulnerable 和 confirmed_vulnerable 有什么区别?
答: vulnerable 表示 WordPress.org API 认为该版本不安全,但我们尚未从行为上确认 strip_tags/KSES 的不一致。confirmed_vulnerable 表示我们发送了探测,且 <area> 元素同时绕过了两种过滤器 — 已发布的攻击链可以触发。
问:我可以在漏洞赏金计划的报告中使用这个工具吗?
答: 可以!checker_status 列直接映射到 pwn.ai 公共检查器的词汇表,便于关联。将扫描结果与 make_poc.py 生成的 PoC 视频证据结合,即可形成完整的报告。
问:该工具能检测 RCE 攻击链吗?
答: 不能。本工具包检测的是预认证 XSS 入口点。完整的 RCE 攻击链需要已登录的管理员、启用应用程序密码以及插件上传权限 — 这些条件本扫描器不会评估。扫描器聚焦于外部可观察的内容:过滤器绕过。
由 0xlipon 构建 • 仅用于检测 • 仅供授权使用
| 资源 | 链接 |
|---|
| 原始披露(pwn.ai) | pwn.ai/blog/xss2shell |
| Hadrian 技术分析 | hadrian.io/blog/wordpress-xss2shell |
| WordPress 安全公告(GHSA) | GHSA-52p2-r8wf-jcrf |
| SOME 攻击研究(2022) | pwn.ai/blog/bypass-csp-using-wordpress |
| WordPress 7.0.3 发布 | wordpress.org/news/2026/08/wordpress-7-0-3-release |
| 标志 | 说明 |
|---|
-i, --input | 包含主机列表的文件,每行一个主机(裸域名或完整 URL) |
-o, --output | 输出文件的基础路径(生成 .csv + .json) |
--active | 启用行为探测 — 每台主机一次失败登录 |
--workers | 线程池大小(默认:50,连接良好时最多约 200) |
--timeout | HTTP 超时时间(秒)(默认:10) |
--quiet | 仅打印 confirmed_vulnerable、vulnerable 和 likely_vulnerable |
| 变体 | href 值 | 适用场景 |
|---|
| 默认 | /?rest_route=/&_method=GET&_jsonp=alert | 标准 WordPress |
| Envelope | /?rest_route=/&_method=GET&_envelope=1&_jsonp=alert | REST 返回 401(包装为 200) |
| WAF 绕过 | /wp-json/wp/v2/statuses/publish?_jsonp=alert&_method=GET | ?rest_route= 被 WAF 拦截 |
| 判定结果 | 条件 |
|---|
confirmed_vulnerable 🔴 | 版本不安全,且探测标记以 <area> 元素存活,且存在 user-profile.js gadget |
vulnerable 🔴 | 根据 wordpress.org 判断版本不安全;未运行行为探测(请使用 --active 重新运行) |
likely_vulnerable 🟠 | 探测标记存活,但 user-profile.js 未入队(缺少已发布的自动触发 gadget) |
mitigated 🟣 | 版本不安全,但探测标记已被转义/剥离/无回显(静默向后移植或已加固) |
likely_patched 🟢 | 版本隐藏/未知,但探测标记已被转义/剥离 |
patched 🟢 | 版本为 latest 或 outdated(包含安全向后移植) |
not_wordpress ⚫ | 未检测到 WordPress 指纹 |
unreachable ⚫ | 连接失败(超时、SSL、DNS) |
inconclusive 🟡 | WAF 拦截、Cloudflare 质询、版本隐藏且未运行探测,或登录页面缺失 |
error 🟡 | 扫描期间发生意外故障 |