做安全工作的人应该都有过这种经历:甲方部署了一套WAF,白天做了一轮基础测试,规则看起来覆盖得挺全,晚上攻防演练一开打,几分钟就被一个冷门编码姿势破了防。问题很多时候不在WAF产品本身,而在测试方手里没有足够多样、足够贴近真实攻击手法的绕过样本,没法提前把规则漏洞暴露出来。我最近这段时间就在折腾一件事:把大语言模型(LLM)接到WAF绕过Payload生成这个环节里,让模型充当一个“永远在变样本的测试样本制造机”。
这篇文章是这个项目的完整复盘,包含整体思路、系统架构、Prompt设计、模型选型、实测数据和踩坑记录,给正在做WAF有效性评估、红蓝对抗、安全工具开发的同行一个可以直接参考的落地版本。特别说明一点,这个引擎的定位是防御侧的验证工具:在明确授权的测试环境里生成绕过样本,用来暴露WAF规则缺陷、驱动规则加固,而不是教人攻击未授权系统。
1. 不用LLM之前,绕过样本生成为什么这么难
1.1 传统三种打法的硬伤
先说说传统上怎么获取WAF绕过样本,我自己的感受是三种主流方式都有明显短板。
第一种是规则库遍历。把市面上公开的绕过样本库拉下来,一条条跑。这种方式看似省事,但样本库的更新永远滞后于攻击手法迭代,而且大部分公开样本都是老编码姿势,WAF规则早就针对性地封掉了,能产出价值的绕过样本比例很低。更头疼的是,样本库里的Payload和真实目标系统的参数上下文完全对不上,即便绕过WAF,到了后端也大概率不触发。
第二种是模板化变形工具。一些自动化注入测试工具本身就带tamper脚本,能对Payload做大小写混淆、注释符插入、等价函数替换等机械操作。我用过一段时间后发现,这类工具的变形逻辑是固定的,生成结果在“花样”上有限,遇到基于语义分析的WAF特别容易翻车——因为机械变形只改表面特征,不改变内部语义结构,规则引擎稍微做一层语法归一化就能识别出来。
第三种是专家手工构造。让有经验的安全研究员针对目标WAF的规则特征一个个手搓Payload。质量确实高,但效率太低,一个人一天能搓出几十条就算不错了,而且高度依赖个人经验和临场状态,没法规模化,也不利于知识沉淀。
1.2 LLM带来的范式转变
LLM切入这个场景,本质上改变了一件事:把“绕过方式”从规则层面的机械替换,变成了语义层面的连续改写。WAF读的是字符串,做的是模式匹配和语义判断;Payload对WAF来说就是一种“待分析的字符串语言”,而对后端应用来说又是一种“待解释的表达式语言”。LLM恰好擅长做同一语义前提下不同表达形式的生成,这和绕过样本制造的需求天然吻合。
实际用下来,LLM路径有两个传统方式比不了的优势。第一是生成多样性。同样一条SQL注入种子样本,模型可以同时从编码切割、注释插入、等价函数、空白符变体、条件结构重写等多个维度生成变体,覆盖面远超固定模板。第二是闭环反馈能力。这是最值钱的部分:在生成—检测—反馈的循环里,模型能把WAF“拦了什么”“放行了什么”作为上下文重新组织生成策略,相当于让测试样本从静态库变成了不断自进化的动态集合。
2. 整体架构与核心模块设计
2.1 一次完整的生成—检测—反馈闭环
整个引擎的工作流,我拆成五个模块:样本输入层、Prompt构造层、LLM生成层、检测验证层、反馈回灌层。
配一个标准的闭环流程来看:
- 输入一条种子攻击样本,比如一条典型的SQL注入检测字符串。
- 对种子样本做规范化处理,去掉无效前缀、抽取核心触发片段。
- 构建Prompt,要求模型在指定约束下生成N个变体。
- 模型返回候选Payload,后处理模块负责解析、去重、格式统一。
- 把每一个候选Payload构造进HTTP请求,发送到实验靶场的WAF检测端。
- 根据响应状态码、响应长度、返回页特征综合判定该Payload是否被拦截。
- 未被拦截的样本进入“通过样本池”,被拦截的样本连同拦截特征一起打包,回灌到下一轮Prompt上下文。
- 反复迭代,直到通过样本达到目标数量,或达到最大迭代轮次。
这个闭环看着简单,真正的难点在第6步的判定口径和第7步的反馈组织形式。先说判定:单靠“是否返回拦截页”是不够的,因为有些WAF是静默放行后在日志侧做审计,有些是返回200但内容里被清洗过字段。所以我在检测端加了“后端Sink验证”,也就是Payload到达后端后是否真的触发了预期行为(典型的比如数据库报错回显、命令执行回显、响应时间异常),确保我们收集到的绕过样本不是“WAF没拦但后端也没执行”的无效项。这个口径直接影响后面所有统计数据的可信度。
2.2 Prompt设计:把WAF检测机制翻译给模型
LLM不会平白无故生成高质量绕过样本,Prompt里必须把目标的检测机制、约束条件、成功标准全部说清楚。我的Prompt模板固定为五个区段:角色描述、任务描述、约束区、示例区、输出区。
这里给出一个简化版模板,实际使用时会根据目标WAF类型做动态拼接:
你是一名Web安全防御验证专家,正在为一个WAF规则评估项目构造测试样本。 原始载荷:{seed_payload} 约束条件: - 目标检测方式:正则规则检测 + 关键词黑名单 - 变体中不允许出现与原始载荷完全连续相同的5个以上关键字 - 生成数量:10 - 输出格式:JSON数组,字段包含payload、encode、tactic、note 要求: 1. 改写前后触发语义保持不变 2. 优先使用等价函数替换、注释符分隔、空白符变化、编码嵌套 3. 不得在载荷中无意义地填充随机字符串 4. 每个变体的绕过策略需要写在tactic字段中一个值得强调的设计细节:示例区只放两到三个成功案例加一个失败案例,不要在示例里塞太多内容。我试过把绕过案例库全部塞进Prompt,效果反而变差,因为模型会被大量示例带偏,只模仿示例的特定模式而丧失探索多样性。少样本引导让模型理解“这个方向可行”就足够了,剩下的交给温度和采样配置去发散。
反馈回灌的Prompt优化:到了第二轮及以后,我还会在模板末尾追加“前一轮检测结果”的JSON块,包含被拦截样本的完整Payload、命中规则编号(如果WAF暴露了)、响应状态码、响应体长度。模型其实非常擅长从这类“失败案例”里归纳共性,比如连续几轮都在注释符位置出错,下一轮它会自动调整插入位置或改用别的注释风格。
2.3 模型与算力选型:为什么我不建议直接调云端API
这个项目开始前,我在模型部署方式上纠结过一阵:直接用商用大模型API,还是本地部署开源模型。后来实际测试做完,我的结论是本地部署优先。
主要原因有三条。第一是数据安全:测试过程中的Payload和检测结果本质上属于安全评估的敏感内部数据,走云端API意味着这些数据要出域,很多授权测试项目根本不允许这么做。第二是限流问题:绕过样本生成是高频小请求场景,云端API的速率限制和异步返回机制会让整个闭环变得很别扭。第三是成本:一次完整的生成—检测循环可能要调用几十次模型接口,长期跑下来API费用并不低。
本地部署的选型方面,我整理了常用参数的实际对比:
| 模型档位 | 量化方式 | 显存需求参考 | 单条生成耗时参考 | 生成质量 |
|---|---|---|---|---|
| 7B级 | INT4 | 约5GB-7GB | 1秒-2秒 | 满足基础变体生成 |
| 7B级 | INT8 | 约9GB-11GB | 2秒-3秒 | 语义保持更好 |
| 13B级 | INT4 | 约9GB-12GB | 3秒-5秒 | 复杂绕过多轮反馈更稳定 |
| 13B级 | INT8 | 约15GB-18GB | 5秒-8秒 | 接近商用大模型常规表现 |
我实际用下来,7B INT4和13B INT4之间的差距主要在复杂语义保持上。简单SQL注入绕过,7B够了;涉及存储型XSS的多种编码嵌套、命令注入的管道符变体组合这类复杂场景,13B明显更稳。13B INT4在单卡上就能跑,性价比最合适,也是我最常用的配置。
有个反直觉的结论:并非模型参数越大越好。绕过生成任务真正考验的是模型对“检测模式”的先验知识量和上下文跟随能力,这跟模型的框架设计、训练数据覆盖度关系更大,往上堆参数量带来的收益在超过一定阈值后会快速衰减,但延迟和显存成本会直线上升。
3. 实战实现:从数据集到三轮迭代实测
3.1 实验环境与种子样本集构建
实验环境我搭在一个完全隔离的本地网络里:一套基于常见Web漏洞的靶场应用,前面挂一个可配置规则的WAF模拟层。WAF规则集我配了三个检测等级:第一层是关键词和正则黑名单,第二层是简单的语法归一化检测,第三层是请求体大小写和特殊字符频率统计。这套规则组合能模拟市面上大部分WAF的基础检测逻辑,同时完全可控可复现。
种子样本集的构建是整个项目里最花时间的部分。我从前期的安全测试报告、公开漏洞公告、历史攻防演练记录里整理了一批原始攻击样本,然后做三步处理:
- 分类:按注入类型分成SQL注入、跨站脚本、命令注入、文件包含、日志注入五个大类。
- 最小化:去掉每条样本里的无关前缀和标签,只保留能触发后端行为的最小核心片段。
- 标注:给每条样本补充目标参数名、适用的编码类型、可替换的等价函数列表。
整理后的种子样本数量不用太多,我最终留下了大约80条核心样本,质量远重要过于数量,因为LLM的生成能力会把每条种子的覆盖范围成倍放大。
3.2 生成参数设置与评测口径
模型服务跑起来后,我调整了一组生成参数,目标是多样性优先但不过度:
| 参数 | 设置值 | 设置理由 |
|---|---|---|
| temperature | 0.9-1.1 | 保多样性又不至于全乱码 |
| top_p | 0.95 | 采样范围够宽 |
| 每轮候选数 | 10 | 兼顾覆盖面和检测请求耗时 |
| 最大迭代轮数 | 5 | 反馈收敛后再多轮边际收益递减 |
| 重复惩罚 | 1.1 | 防止模型复制种子样本原样输出 |
评测口径我定了三个指标。原始绕过率:WAF未拦截的样本数占总生成样本数的比例。有效绕过率:WAF未拦截且后端Sink验证通过的样本比例,这是我最看重的指标。变体多样性:用分组哈希统计去重后的独立绕过策略数量,衡量生成的花样是否足够多。
3.3 三轮迭代实测记录
下面这组数据来自我在本地靶场跑的一轮完整测试,目标是针对“SQL注入类种子样本”生成可绕过三层检测规则的变体:
| 轮次 | 生成样本数 | 原始绕过率 | 有效绕过率 | 命中策略数 |
|---|---|---|---|---|
| 第1轮 | 100 | 27% | 11% | 6 |
| 第2轮 | 100 | 44% | 24% | 9 |
| 第3轮 | 100 | 58% | 39% | 12 |
从数据可以清楚看到反馈闭环的效果。第一轮模型基本是在种子样本基础上做“表面变形”,对三层规则的真实检测逻辑理解不够,所以原始绕过率只有27%,有效绕过率更是低到11%。到了第二轮,我把第一轮所有失败样本的响应特征回灌进Prompt,模型明显开始尝试“绕过第一层关键词检测但避开第二层语法归一化”的组合策略,原始绕过率提升到44%。第三轮时模型已经学会了“多个编码层叠+注释符打乱+等价函数替换”的复合套路,有效绕过率拉到了39%。
这个趋势也验证了我在设计阶段的一个判断:这类系统真正的工作重心不在模型本身的生成能力,而在反馈工程。模型能力只是底座,反馈信息的组织方式决定了它能爬多高。
4. 常见问题与排查技巧实录
4.1 生成质量差、绕过率长期低位
这是所有刚接触这个方向的人最常遇到的情况。如果你连续几轮生成都处于“只能换换大小写”的状态,先别怀疑模型能力,去检查两件事:Prompt里的检测机制描述是否具体,反馈回灌信息是否完整。
我最初踩的坑是只把“被拦截”三个字反馈给模型,没有任何细节。模型根本无从知道自己是栽在关键词上还是栽在语法归一化上。后来把反馈改成结构化形式:状态码、拦截响应头、响应体长度、命中的规则类别、原Payload,四要素齐全后再回灌,第三轮绕过率直接翻倍。
另一个常见问题是示例区塞太多。我建议示例最多三组,太多会把模型的探索空间锁死。真需要强化某个方向的生成时,用反馈回灌代替示例堆砌,效果更直接。
4.2 绕过成功但Payload后端不生效
这个问题的迷惑性最强,表面上看WAF放行了,但后端也没有任何触发回显,单独看指标会高估系统能力。出现这种情况主要有三个原因:语义被过度改写、编码后上下文错位、等价函数替换错了语境。
解决办法是双管齐下。第一,Prompt里显式要求“每个变体在保留触发语义的前提下做外观改写”,并且要求模型填写note字段做自检说明。第二,检测流程中必须带上后端Sink验证,不能只看WAF侧放行与否。我给检测请求设计了一个通用验证规则:根据样本类型检查数据库报错回显、命令执行回显、响应时间差、输出点内容变化四类信号,至少命中一个才算有效。
4.3 高频生成触发WAF限流策略
自动化测试跑起来后,目标WAF很容易对测试源IP产生限流或阻断,尤其是请求频率比较高的时候。这个问题本身的信号是良性的——说明WAF有基础防护意识——但会干扰验证结果,你会分不清样本是被规则拦了还是被频率策略拦了。
处理方式我分三个层面。请求侧:单次请求间隔至少1秒,随机化请求头的UA和Accept字段,避免机器特征太明显。流程侧:每轮生成后的检测请求做一个随机打散,不按固定顺序发。数据侧:如果同一休息时段内连续出现大量“响应码429/403且响应特征一致”的记录,先暂停该目标点的测试,等待策略冷却后再继续,不要盲目重试。
4.4 模型幻觉导致的无效编码与伪变体
LLM在这类任务里幻觉率不低,最典型的表现是编造不存在的编码函数名、拼错数据库关键字、生成前后语义断裂的长变体。这种样本不仅拉低整体统计指标,更麻烦的是如果手工审阅,会浪费大量时间。
我后来加了一套轻量后处理校验层,在样本进入检测请求前跑三层检查:关键字白名单校验,检查替换的函数名和编码方式是否真实存在;编码合法性校验,对URL编码、Unicode编码做可逆解码测试;长度和结构约束校验,超过预设长度或明显乱码的直接丢弃。这套校验大约过滤掉了15%到20%的无效生成,让有效绕过率的数据更干净,也让进入通过池的每条样本都有保存价值。
下面是一张小型的常见问题速查表,方便直接对照排查:
| 问题现象 | 直接原因 | 优先排查项 |
|---|---|---|
| 绕过率连续零增长 | 反馈信息过于抽象 | 检查回灌JSON的状态码和规则命中字段 |
| 输出全是乱码字符串 | 温度过高 | 把temperature调回1.0以下 |
| 样本有效但重复度高 | 采样配置偏保守 | 上调top_p到0.95,打开重复惩罚 |
| 生成耗时过长 | 模型档位偏高 | 切换INT4量化,缩短Prompt长度 |
| 后端验证全部失败 | 语义改写过度 | 在Prompt中追加“保留触发语义”硬约束 |
5. 边界、规范与后续演进方向
5.1 授权边界与数据安全底线
这类工具绕不开两个敏感词:绕过和自动化。我必须把边界说透:这套引擎从设计定位上就是一个防御验证工具,所有测试样本的生成和投放都限定在获得明确书面授权的测试环境内,任何情况下都不应该对着未授权的线上系统跑。
数据安全方面有三个动作是我坚持保留的:模型服务全部本地化部署,不让任何测试数据出域;靶场和检测端的日志按周清理,不做长期留存;生成样本库只保留触发特征和绕过模式,凡是涉及真实业务参数名和敏感字段的地方一律脱敏。如果你的测试目标涉及外部单位,还要额外确认数据留存时限和上报范围的要求。
如果只记住一条:这个引擎产出的不是攻击武器,而是规则体检报告。每一批有效绕过样本都应该同步推给WAF规则负责人,而不是只存在测试人员的硬盘里。
5.2 我把后续重点放在三个延伸方向上
第一个方向是把有效绕过样本自动转成WAF规则补充特征。目前我在做的是每周导出一批高价值绕过样本,对照现有规则集做差异分析,找出规则没覆盖到的模式,反哺给规则维护人员。与其让绕过样本只是在测试报告里躺平,不如让它变成防御侧的增量资产。
第二个方向是沉淀绕过模式知识库。每轮生成过程中模型产出的有效策略,我会整理成“模式描述+典型样本+适用场景”的三元组,积累成一张可检索的知识表。以后碰到新客户或新靶场,先查知识库再启动生成,效率会比从零开始跑高很多。
第三个方向是从单点Payload生成往攻击链生成演进。现在的引擎只做单个请求的绕过,现实中的攻防对抗往往是多步骤组合,比如先绕过登录接口的过滤,再在后续请求里注入。这个演进并不简单,需要引入请求序列的上下文建模和状态追踪,我还在逐步摸索。
最后分享一个我在实际测试中发现的细节:整个项目最影响成败的往往不是模型的聪明程度,而是反馈信息的完整度。我第一次做闭环的时候,把拦截结果截断成几个字符就塞回Prompt,模型根本看不懂问题出在哪。后来改成把状态码、规则命中ID、响应特征、原始样本四个要素打包,格式固定,绕过率立刻明显上了一个台阶。做这类工具的朋友,建议把反馈工程放在和模型选型同等重要的位置,投入产出比会远超你的预期。