PentestGPT-v2:A Good LLM Agent for RW Pentest

1. 论文信息与核心问题

论文:What Makes a Good LLM Agent for Real-world Penetration Testing?
链接:arXiv:2602.17622
PDF:https://arxiv.org/pdf/2602.17622

这篇论文问的是:什么样的 LLM Agent 才能做真实世界的自动化渗透测试?

它的核心观点可以概括成一句话:

自动化渗透 Agent 的难点,不只是把工具调对,而是把渗透过程建模成一个带证据、状态和回溯的搜索问题。

普通 ReAct Agent 更像一条线:

1
Think -> Act -> Observe -> Think -> Act -> ...

PentestGPT v2 则更接近攻击树搜索:

1
收集证据 -> 生成假设 -> 执行动作 -> 更新状态 -> 评估路径 -> 深入 / 回溯 / 剪枝

2. 两类失败:执行失败和路径失败

论文把现有 Pentest Agent 的失败分成两类。

第一类是 Type A:工具、知识、执行能力不足。比如工具参数写错、输出解析失败、不知道某个 CVE 的利用方式,或者没有正确调用 Metasploit、Impacket、sqlmap、ffuf 这类工具。

这类问题偏工程,可以通过 typed tool、RAG、parser、precondition / postcondition 缓解。它关心的是:Agent 能不能把动作执行对?

第二类是 Type B:复杂任务中的路径选择失败。比如侦察不足就开始利用、exploit 失败后反复重试、不会回到其他端口、拿到新凭证后不会重新访问旧资源,或者长上下文里忘掉关键状态。

这类问题更接近真实渗透的核心难点。它关心的是:Agent 知不知道当前路线是否还值得继续?

论文真正想解决的是 Type B。因为真实渗透不是单步命令生成,而是多阶段、不确定、需要回溯的搜索过程。

3. PentestGPT v2 的三个核心模块

PentestGPT v2 的设计可以压缩成三块:

模块 解决的问题
Tool and Skill Layer 动作能不能稳定执行
TDA + EGATS Planner 当前攻击路径是否值得继续
Memory Subsystem 长链任务中的状态如何保留

PentestGPT v2 architecture

左边输入攻击目标,中间用 TDA-EGATS 做路径规划,再通过 Tool Layer 执行动作,Memory 负责保存状态。

需要注意的是,PentestGPT v2 是 Python 实现的 单 Agent、多模块架构。Tool Layer、TDA-EGATS Planner 和 Memory Subsystem 是同一个 Agent 内部的功能模块,而不是多个相互协作的独立 Agent。

3.1 Tool Layer:让 LLM 选择动作,而不是手写命令

普通 Agent 经常让 LLM 直接拼 shell:

1
2
nmap -sV -p- 10.10.10.5
ffuf -u http://10.10.10.5/FUZZ -w wordlist.txt

PentestGPT v2 的做法是把工具封装成 typed interface:

1
2
3
4
scan_ports(target, ports, mode)
web_fuzz(url, wordlist, extensions)
check_smb(target, credential)
kerberoast(domain, dc_ip, credential)

每个接口都可以带输入 schema、输出 schema、precondition、postcondition、parser 和 error handler。这样 LLM 只负责选择高层动作,参数校验、命令执行和输出解析交给工具层。

1
2
LLM 负责决定做什么
Tool Layer 负责保证动作怎么做

这一步主要解决 Type A:把动作执行对。

3.2 TDA-EGATS:给路径打分,再更新攻击树

TDA 是 Task Difficulty Assessment,EGATS 是 Evidence-Guided Attack Tree Search。这两个机制可以放在一起看:TDA 负责评估当前路径,EGATS 负责根据评估结果更新攻击树。

攻击树不是一串线性的命令历史,而是一组候选攻击分支。每条分支上会混合出现三类信息:

1
2
3
Observation: 已确认的事实,例如端口、服务、用户名、凭证
Hypothesis: 待验证的攻击假设,例如某版本可能存在漏洞
Action: 已执行或可执行的动作,例如扫描、爆破、利用、提权

TDA 主要看四个信号:

1
2
3
4
Horizon Estimation: 当前路径离目标还有多远
Evidence Confidence: 当前证据是否足够强
Context Load: 上下文是否已经过载
Historical Success: 类似路径过去是否成功

这些信号会汇总成 TDI, Task Difficulty Index。TDI 越低,说明这条路径越值得继续深入;TDI 越高,说明继续投入的收益越低,应该考虑补侦察、回溯或剪枝。

最后服务于一个问题:

当前这条攻击路径,现在还值不值得继续投入?

TDI 作为路径难度和优先级信号反馈给 EGATS。EGATS 再用这个信号调整搜索策略:难度低、证据强的分支会被优先深入;难度高、证据弱的分支会转回侦察;连续失败且 TDI 持续升高的分支会被降权或剪枝。

例如,只发现端口开放时,证据很弱,更适合继续侦察;PoC 能触发或者拿到凭证时,证据变强,可以继续利用;如果某个分支连续失败,EGATS 就会降低它的优先级或者直接剪枝。拿到新凭证后,之前因为缺少身份而走不通的旧分支也可以被重新激活。

这里的核心流程是:

1
2
3
维护多条候选路径
-> 用 TDA 评估路径难度和证据强度
-> 用 EGATS 决定继续、回溯、剪枝或重新激活分支

和普通 ReAct loop 最大的区别在于:ReAct 通常只根据当前 observation 生成下一步动作,而 PentestGPT v2 会维护多条候选路径,并持续比较这些路径的证据强度、剩余难度和历史失败情况。

3.3 Memory:把关键事实从 prompt 里拿出来

Memory Subsystem 保存的不是普通聊天记录,而是结构化渗透状态:

1
2
3
4
5
6
hosts
services
credentials
sessions
vulnerabilities
attack tree nodes

例如:

1
2
3
4
5
host: 10.10.10.5
service: 445/smb
credential: alice:Password123
session: low-priv shell on web01
vulnerability: PHP type juggling candidate

这些状态会被攻击树节点引用,并在需要时重新注入上下文。它的作用是:

1
2
3
4
关键事实持久化
当前路径按需取回
旧分支可以被重新激活
上下文压缩后状态不丢

这对 AD、多主机、多凭证场景尤其重要。因为域内渗透高度依赖凭证复用、session 管理和横向移动,如果 Agent 忘掉前面拿到的身份,后续路径就会断掉。

4. Falafel 案例:从爆破切到 type juggling

论文里比较直观的案例是 HTB Falafel。

HTB Falafel exploration comparison

旧版 PentestGPT 在拿到 hash 后,持续沿着爆破方向尝试。这个方向看起来合理,但投入很多次仍然没有结果。

PentestGPT v2 的行为不同:

1
2
3
4
当前路径多次失败
历史成功率下降
证据强度不足
继续爆破的收益降低

于是它没有一直卡在 hash cracking 上,而是转向另一个攻击假设:PHP type juggling。

这个例子可以很好地说明 PentestGPT v2 的技术重点:它不是单纯让 LLM 更会写命令,而是让 Agent 根据证据和历史结果调整搜索方向。

真实渗透里的很多进展都来自 pivot。比如从 Web 转到 SMB,从弱口令转到配置泄露,从单机提权转到域内横向。Agent 如果不会评估路线价值,就很容易在一个看似合理但实际无效的方向上耗尽预算。

5. 技术启发

这篇论文比较有价值的地方,是把 Pentest Agent 的问题拆成了三个层次:

1
2
3
执行可靠性:动作能不能做对
路径搜索:方向值不值得继续
状态管理:关键事实会不会丢

普通 Agent 把渗透测试看成一串工具调用:

1
看到服务 -> 调工具 -> 看输出 -> 再调工具

PentestGPT v2 把它看成搜索问题:

1
2
3
4
5
维护攻击树
评估路径难度
根据证据选择方向
失败后回溯和剪枝
关键状态进入外部记忆

这篇论文给自动化渗透 Agent 提供了一个更合理的抽象:

在可复用攻击模式空间里,Agent 的关键能力是证据驱动的搜索、回溯和状态管理。