hego.red - AI/LLM 红队测试实战笔记

AI/LLM 红队测试实战笔记

从这里开始

欢迎。这是一份关于大语言模型(LLM)红队测试的实战笔记,以渗透测试人员的视角写成。用上方的标签页导航:基础讲清楚你到底在测什么,攻击方法论讲具体怎么做,训练营是一套带教程,PortSwigger 收录了实操靶场,范围攻击流程帮你界定目标,术语则是速查词典。第一次来?把这一页从头到尾读完就好。任何时候按 / 都能全站搜索。

基础:我们究竟在测什么?

先读这一段。一分钟就能讲明白:所谓“AI 功能”到底是什么,模型 / 聊天机器人 / 智能体这几个词分别指什么,以及 AI 是怎么生成回答的。看懂了这张全景图,其他标签页就都好理解了。

1. 你测的是应用,不是“大脑”

所谓“AI 功能”,不过是一个普通应用外接了一个 AI 模型。你要测的是客户自己搭建的那个应用。模型这颗“大脑”通常属于厂商(Claude、OpenAI),不在测试范围内。

你 / 聊天框
你输入消息的地方
应用你要测的是这里
这部分是客户搭建的:
  • 加上隐藏的规则(系统提示词)
  • 可能会读取文档或数据库(RAG)
  • 可能会调用工具(发邮件、查数据库、执行代码)
  • 把回答展示给用户
模型 /“大脑”通常属于厂商
它只是把文本变成更多文本
几乎所有漏洞都在绿色框里(也就是应用),而不在大脑里。让大脑说几句粗话是厂商的问题,算不上真正的发现。

2. 模型 vs 聊天机器人 vs 智能体

这三个词把所有人都绕晕了。其实它就是一级级往上加,每一级只多一样东西。

模型(LLM)
大脑。读文本,猜下一个词,仅此而已。
聊天机器人
模型 + 隐藏规则 + 聊天窗口,能跟你对话。
RAG 应用
聊天机器人 + 能读取文档和你的数据。
智能体
模型 + 工具,能真正“动手做事”、分步执行,而不只是聊天。

越往右,它能做的事越多,你能攻击的面也越大。

3. 它是怎么生成回答的

模型并不会"思考"。它读文字,然后一次又一次地猜下一个词。真正值得盯着看的不是猜,而是它拿来猜的那些文字是谁写的。最终摆在它面前的有五种文字,其中只有一种是做这个应用的人写的。

系统提示词由开发者写的。这一页上唯一属于这个应用的文字,也是任何能让模型把它复述出来的人的奖品。 ↳ 提示词泄露
你的消息由正在打字的人写的。在公开的聊天机器人上,那就是世界上的任何人。 ↳ 直接注入
一份文档由写下那个文件、那个页面或那条记录的人写的。任何能把它放到应用会去读的地方的人,现在就是在往模型里写字。 ↳ 间接注入
工具的返回由控制着工具所触及之物的人写的:一个网站、一个 API、一个收件箱、数据库里的一行。 ↳ 智能体劫持
回答由模型根据以上一切写出来的。它说出的任何来源,都是它自己生成的,不是运行时追踪到的。 ↳ 不安全的输出

一张图,从左往右看。五种文字从左边进来,被拼成一整条字符串,交给模型。注意看那块琥珀色的文档:它坐在绿色的 user 回合里,而等模型拿到它的时候,它已经不见了。每个方框上都写着它会变成哪种攻击,而三处虚线标记是控制唯一能站的位置。

下一轮:给你看过的东西会变成历史回来 系统提示词开发者写的 ↳ 提示词泄露 对话历史之前的轮次,已经是灰的 ↳ 记忆投毒 你的消息正在打字的人 ↳ 直接注入 检索到的文档写这个文件的人 ↳ 间接注入 工具的返回拥有那个站点的人 ↳ 智能体劫持 提示词 拼装 加上角色标签 输入过滤 上下文窗口 system assistant tool user 贴进来的文档 模型 system assistant tool user 角色活下来了,作者没有。 1 角色也是 token 2 只读它前面的内容 3 预测下一个,再重复 角色是倾向,不是规则 输出过滤 渲染给你看markdown、链接、图片 ↳ 不安全的输出 回答一团灰色 引用是生成出来的 一次工具调用如果它要求了的话 ↳ 过度自主权 工具确认 一个网站、一个 API、一个收件箱、数据库的一行 ↳ 数据外带 智能体回路:取回来的东西会以文字回来 1234567

每一支箭头都在运送文字。角色标签一路活到模型里面,但它们标的是回合,不是作者,而且三处控制全都在盒子外面。

  1. 五个来源。只有第一个是做这个应用的人写的。另外四个来自正在打字的人、写下某个文件的人,或者拥有应用碰过的某个站点的人。图片也算,因为模型会读图里的文字。
  2. 一个模板把它们拼起来,并给每个回合挂上角色标签。这些标签是真的,而且会一路活到 token 序列里。它们标的是回合,不是回合里那段文字是谁写的。
  3. 上下文窗口是一个长度上限,不是一个仓库。当对话超出它,就必须扔掉一些东西。大多数应用会把系统提示词钉住,从中间丢弃或者做摘要;粗糙的那些从顶上丢,把它一起丢掉。
  4. 模型把它当成一条序列来读。每个 token 只读它前面的所有内容,读不到后面的,所以放在前面的文字会带着后面的一切走。它预测一个 token,接上去,然后再跑一遍。
  5. 回答出来时没有来源。如果它引用了某个来源,那条引用是读了被投毒文本的同一次前向过程写出来的。那是一句声明,不是保管链。
  6. 它要么被渲染出来,要么变成一次工具调用。渲染会在你的浏览器里执行 markdown、链接和图片。工具调用则伸向应用并不拥有的东西。
  7. 两条路都会绕回来。给你看过的东西以历史的形式回来,工具取回的东西以新文字的形式回来,而下一次请求,一开始就带着更多没有人担保的材料。

4. 万恶之源的那一个缺陷

再看一眼图里的模型方框。角色标签进去了,也从另一头出来了,但那块琥珀色的文档没有:它被折进了绿色的 user 回合里,而在模型内部,已经没有任何东西说明那是一个陌生人写的。

角色是真实存在的。现代 API 把 system、user、assistant、tool 当作分开的字段接收,它们会以分隔符 token 的形式一路活到 token 序列里。活不下来的,是任何比一个回合更细的东西。

检索到的文档没有属于自己的角色。它被贴进某个 user 回合里,或者某个 tool 回合里,所以等模型读到它的时候,它的分量恰好等于把它包进去的那个回合。工具取回来的东西也一样:外壳和攻击者的网站,是同一个标签底下的同一团东西。

而且角色只是一种倾向,不是一种权限。模型被训练成把 system 的指令看得比 user 的重,大多数时候这个训练是管用的。但那是从例子里学来的倾向,不是运行时强制执行的规则,所以一条足够理直气壮的指令,哪怕待在工具的返回里,照样可能赢。指令和数据,依然是同一种材料。

所以真正存在的控制,都站在这个盒子的前面或者后面:输入过滤、检索白名单、输出扫描、工具确认、沙箱。那些试图在里面工作的,比如指令层级训练,本身也是倾向,而倾向是会被掰弯的。因此真正有用的问题从来不是“这个模型安全吗”。而是:攻击者能在这些箭头里的哪一支上写字,以及当他写下去的时候,盒子的另一头连着什么。

这就是整场游戏:角色标签标的是回合,不是作者,所以以数据身份进来的文字,可以像指令一样起作用。这就是提示词注入,而几乎其他所有攻击都建立在它之上。

5. 那么漏洞都在哪儿?

上面每一层都有自己对应的漏洞。用大白话讲,这就是 OWASP LLM Top 10:

对应的漏洞
你的输入提示词注入:你的文字被当成命令执行。
模型越狱(突破它的安全限制);如果做过微调,还能泄露训练数据。
文档 / RAG给文档投毒,让模型照着文档里的指令执行(间接注入)。
工具诱导它调用本不该用的工具,或攻击工具的输入(SQLi、SSRF、执行代码)。
被展示的回答不安全的输出处理:应用把回答当成 HTML/SQL 直接执行,于是有了 XSS 等一系列问题。

6. 风险取决于应用本身

同一个回答,在一个应用里没问题,在另一个应用里可能就是灾难。所以开测之前先问:这个应用是干什么用的?在这里什么才算“出问题”?

应用什么算“出问题”
故事 / 游戏生成器就要天马行空的创意输出,几乎怎么都行。
内部 HR 或客服机器人必须照实说,编造一条并不存在的政策就是漏洞。
公司对外的邮件撰写助手要诚实又符合品牌调性,写出粗鲁或不实的内容就是漏洞。

通常你想要的是模型的智能(好的语言与推理能力),而不是它的知识:它应当基于你提供的数据来回答,答不上来就说“我不知道”。

两个要丢掉的误区。(1)“AI 风险不过是科幻片里机器人造反那一套。”不对,真正的风险此刻就在眼前:你的机器人今天就可能泄露数据、给出有害回答,或者让公司吃官司。(2)“模型越大越聪明就越安全。”跑分再高也说明不了它在你这个应用里有多安全。要测的是你的应用,而不是排行榜。

参考来源:OWASP Top 10 for LLM Apps、PortSwigger Web LLM attacks、MITRE ATLAS。接下来:先看“术语”标签页把词搞懂,再看“方法论”了解整体计划。