文章目录
- [EGATS 规划器架构详解](#EGATS 规划器架构详解)
-
- [一、EGATS 算法概述](#一、EGATS 算法概述)
-
- [1.1 什么是 EGATS?](#1.1 什么是 EGATS?)
- [1.2 核心组件关系图](#1.2 核心组件关系图)
- 二、攻击树数据结构
-
- [2.1 AttackNode(攻击节点)](#2.1 AttackNode(攻击节点))
- [2.2 AttackTree(攻击树)](#2.2 AttackTree(攻击树))
- [2.3 节点类型详解](#2.3 节点类型详解)
- 三、TDI(任务难度指数)计算
-
- [3.1 TDIScore 结构](#3.1 TDIScore 结构)
- [3.2 TDI 计算流程](#3.2 TDI 计算流程)
- [3.3 TDI 可视化](#3.3 TDI 可视化)
- [四、UCB (上置信界) 节点选择策略](#四、UCB (上置信界) 节点选择策略)
-
- [4.1 UCB (上置信界) 公式详解](#4.1 UCB (上置信界) 公式详解)
- [4.2 UCB (上置信界) 实现代码](#4.2 UCB (上置信界) 实现代码)
- [4.3 UCB (上置信界) 决策过程示例](#4.3 UCB (上置信界) 决策过程示例)
- [五、EGATS 主循环流程](#五、EGATS 主循环流程)
-
- [5.1 完整流程图](#5.1 完整流程图)
- [5.2 主循环代码实现](#5.2 主循环代码实现)
- 六、反向传播机制
-
- [6.1 反向传播原理](#6.1 反向传播原理)
- [6.2 反向传播示例](#6.2 反向传播示例)
- 七、剪枝机制
-
- [7.1 剪枝条件](#7.1 剪枝条件)
- [7.2 剪枝可视化](#7.2 剪枝可视化)
- 八、模式选择(BFS/DFS/Hybrid)
-
- [8.1 模式选择器](#8.1 模式选择器)
- [8.2 模式对比](#8.2 模式对比)
- 九、横向移动(Pivot)机制
-
- [9.1 Pivot 子树创建](#9.1 Pivot 子树创建)
- [9.2 凭证传播](#9.2 凭证传播)
- 十、研究源码的方法论总结
-
- [10.1 阅读顺序建议](#10.1 阅读顺序建议)
- [10.2 理解复杂代码的技巧](#10.2 理解复杂代码的技巧)
-
- [技巧 1:从调用链入手](#技巧 1:从调用链入手)
- [技巧 2:关注数据流](#技巧 2:关注数据流)
- [技巧 3:理解设计模式](#技巧 3:理解设计模式)
- [技巧 4:结合测试用例](#技巧 4:结合测试用例)
- [10.3 调试技巧](#10.3 调试技巧)
- 十一、完整公式详解
-
- 概述
- [11.1 TDI(任务难度指数)详细计算](#11.1 TDI(任务难度指数)详细计算)
-
- [11.1.1 四个维度的计算公式](#11.1.1 四个维度的计算公式)
- [11.1.2 TDI 综合计算公式](#11.1.2 TDI 综合计算公式)
- [11.1.3 TDI 计算示例](#11.1.3 TDI 计算示例)
- [11.1.4 TDI 权重配置](#11.1.4 TDI 权重配置)
- [11.2 UCB(上置信界)详细计算](#11.2 UCB(上置信界)详细计算)
-
- [11.2.1 UCB 公式详解](#11.2.1 UCB 公式详解)
- [11.2.2 UCB 三项分解](#11.2.2 UCB 三项分解)
- [11.2.3 UCB 计算示例](#11.2.3 UCB 计算示例)
- [11.3 反向传播详细计算](#11.3 反向传播详细计算)
-
- [11.3.1 指数平滑公式](#11.3.1 指数平滑公式)
- [11.3.2 反向传播完整流程](#11.3.2 反向传播完整流程)
- [11.3.3 反向传播示例](#11.3.3 反向传播示例)
- [11.4 剪枝机制完整公式](#11.4 剪枝机制完整公式)
-
- [11.4.1 剪枝条件](#11.4.1 剪枝条件)
- [11.4.2 剪枝阈值配置](#11.4.2 剪枝阈值配置)
- [11.4.3 剪枝决策表](#11.4.3 剪枝决策表)
- [11.5 模式选择完整公式](#11.5 模式选择完整公式)
-
- [11.5.1 模式选择逻辑](#11.5.1 模式选择逻辑)
- [11.5.2 模式选择决策表](#11.5.2 模式选择决策表)
- [11.6 凭证传播机制](#11.6 凭证传播机制)
-
- [11.6.1 凭证相关性判断](#11.6.1 凭证相关性判断)
- [11.6.2 凭证重新评估流程](#11.6.2 凭证重新评估流程)
- [11.7 完整公式速查表](#11.7 完整公式速查表)
- 附录:相关文件索引
EGATS 规划器架构详解
一、EGATS 算法概述
1.1 什么是 EGATS?
EGATS (Evidence-Guided Attack Tree Search) - 证据引导的攻击树搜索,是一种结合了蒙特卡洛树搜索 (MCTS) 和启发式评估的规划算法。
python
# 核心组件概览
┌─────────────────────────────────────────────────────────────┐
│ EGATSPlanner │
│ ┌──────────────┬──────────────┬──────────────┬────────────┐│
│ │ TDA │ UCB │ Backprop │ Pruning ││
│ │ (任务难度评估) │(节点选择策略) │(反向传播) │ (剪枝) ││
│ └──────────────┴──────────────┴──────────────┴────────────┘│
│ ↓ ↓ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Attack Tree (攻击树) │ │
│ │ Root → Children → Leaves │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 核心组件关系图
EGATSPlanner
TDAComputer
UCB Selector
Backpropagation
Pruning
Pivot Manager
Mode Selector
TDIScore 计算
节点选择 UCB 公式
奖励反向传播
剪枝决策
横向移动子树
BFS/DFS/Hybrid 模式
二、攻击树数据结构
2.1 AttackNode(攻击节点)
位于 excalibur/planner/models.py
python
class AttackNode(BaseModel):
"""
攻击树中的单个节点,代表渗透测试中的一个观察、假设或动作。
核心属性:
- id: 节点唯一标识符 (8 字符短 ID)
- node_type: 节点类型 (OBSERVATION/HYPOTHESIS/ACTION)
- status: 生命周期状态 (PENDING/ACTIVE/COMPLETED/PRUNED/FAILED)
- promise_score: UCB 承诺分数 φ(n),基于历史奖励
- tdi: 任务难度指数,包含 4 个加权维度
- visit_count: 节点被访问的次数(用于 UCB)
- success_count/failure_count: 成功/失败计数
"""
2.2 AttackTree(攻击树)
python
class AttackTree(BaseModel):
"""
完整的攻击树,包含所有节点和根节点引用。
核心属性:
- root_id: 根节点的 ID
- nodes: {node_id: AttackNode} 映射表
- total_actions: 已执行的总动作数(用于 UCB)
- budget_remaining: 剩余预算次数
"""
2.3 节点类型详解
| 类型 | 说明 | 使用场景 |
|---|---|---|
OBSERVATION |
观察节点 | 信息收集、端口扫描结果 |
HYPOTHESIS |
假设节点 | 基于证据的推测(如"可能存在 SQL 注入") |
ACTION |
动作节点 | 要执行的操作(如"运行 sqlmap") |
三、TDI(任务难度指数)计算
3.1 TDIScore 结构
位于 excalibur/planner/models.py:87
python
class TDIScore(BaseModel):
"""
四个加权维度:
- horizon: 视野深度(从根节点到该节点的深度)权重 0.3
- success_rate: 成功率(拉普拉斯平滑后)权重 0.2
- context_load: 上下文负载(token 预算利用率)权重 0.2
- evidence_confidence: 证据置信度权重 0.3
计算公式:
TDI = w_h*H + w_e*(1-E) + w_c*C + w_s*(1-S)
"""
3.2 TDI 计算流程
python
# excalibur/planner/tda.py:46
def compute_tdi(self, node, tree, context_load=0.0) -> TDIScore:
"""
1. 计算 horizon:depth / max_depth(归一化深度)
2. 计算 success_rate:(success + 1) / (total_visits + 2)
3. 获取 context_load:当前 token 预算利用率
4. 计算 evidence_confidence:沿路径的平均证据级别
5. 组合成 TDIScore
"""
3.3 TDI 可视化
python
# 示例:TDI 值分解
TDIScore(
horizon=0.6, # 深度适中
success_rate=0.75, # 成功率较高
context_load=0.4, # 上下文负载中等
evidence_confidence=0.8, # 证据较可靠
value=0.43 # 综合难度指数(越低越好)
)
四、UCB (上置信界) 节点选择策略
4.1 UCB (上置信界) 公式详解
python
# UCB(n) = φ(n) + c * √(ln(N) / N_n) - dp * δ(n)
#
# 其中:
# φ(n) = promise_score (承诺分数,基于历史奖励)
# c = exploration_constant (探索常数,默认 1.414 = √2)
# N = 树中已执行的总动作数
# N_n = 节点 n 被访问的次数
# dp = difficulty_penalty (难度惩罚权重,默认 0.5)
# δ(n) = TDI 值(难度指数)
4.2 UCB (上置信界) 实现代码
python
# excalibur/planner/ucb.py:30-67
def select_node(
tree: AttackTree,
exploration_constant: float = 1.414,
difficulty_penalty: float = 0.5,
) -> AttackNode | None:
"""
选择具有最高 UCB 分数的活动叶子节点。
平衡三个因素:
1. Exploitation (利用): 高承诺分数的节点
2. Exploration (探索): 访问次数少的节点获得奖励
3. Difficulty Penalty (难度惩罚): 避免选择过于困难的节点
"""
4.3 UCB (上置信界) 决策过程示例
python
# 假设当前状态:
total_actions = 100 # N
# 候选节点 A(已访问多次,承诺分数高)
node_A = AttackNode(
promise_score=0.8, # φ(n) 较高
visit_count=50, # N_n 较大
tdi=TDIScore(value=0.3) # δ(n) 较低(难度小)
)
# UCB(A) = 0.8 + 1.414 * √(ln(100)/50) - 0.5 * 0.3
# = 0.8 + 1.414 * 0.26 - 0.15
# = 0.8 + 0.37 - 0.15 = 1.02
# 候选节点 B(访问较少,承诺分数中等)
node_B = AttackNode(
promise_score=0.6,
visit_count=10,
tdi=TDIScore(value=0.4)
)
# UCB(B) = 0.6 + 1.414 * √(ln(100)/10) - 0.5 * 0.4
# = 0.6 + 1.414 * 0.58 - 0.2
# = 0.6 + 0.82 - 0.2 = 1.22
# 结果:选择节点 B(探索奖励更高)
五、EGATS 主循环流程
5.1 完整流程图
攻击路径
状态事实
模式指导
兄弟摘要
添加发现
扩展树
剪枝
上下文压缩
Pivot 生成
是
否
开始
选择节点
Select Node
计算 TDI
Compute TDI
选择模式
Select Mode
组装上下文提示
Assemble Context Prompt
攻击路径
主机/服务/凭证
模式指导
兄弟摘要
查询 LLM
Query LLM
处理响应
Process Response
更新树与状态存储
Update Tree & State Store
添加到节点
扩展新节点
反向传播
Backpropagate
更新 n 值
检查条件
Check Conditions
Pruning
Context Comp
Pivot spawn
预算 > 0?
结束
5.2 主循环代码实现
位于 excalibur/core/controller.py:411-603
python
async def _egats_loop(self, initial_task: str) -> dict[str, Any]:
"""
EGATS 规划循环,共 12 个步骤:
1. UCB 选择节点 (select_next_node)
2. 计算 TDI (compute_tdi)
3. 选择模式 (select_mode) - BFS/DFS/LLM 决策
4. 组装上下文提示词 (assemble context)
5. 查询后端 LLM (backend.query)
6. 处理响应并收集发现 (process message)
7. 反向传播结果评估 (backpropagate)
8. 用新发现扩展树的子节点 (expand_tree)
9. 检查剪枝条件 (check_pruning)
10. 检查上下文压缩条件 (compress if needed)
11. 标记当前节点为已完成
12. 循环直到预算耗尽或停止请求
"""
六、反向传播机制
6.1 反向传播原理
python
# excalibur/planner/backpropagation.py:13
def backpropagate(tree, node, outcome, alpha=0.7):
"""
将节点的操作结果沿路径反向传播到根节点。
更新承诺分数 φ(n):
φ(parent) = α * reward + (1-α) * φ(parent)
其中:
- α: 平滑因子(默认 0.7),控制新旧奖励的权重
- reward: 当前结果对应的奖励值
SUCCESS → 1.0
PARTIAL → 0.5
FAILURE → 0.1
"""
6.2 反向传播示例
python
# 初始状态
node_A.promise_score = 0.5 # 中等承诺分数
# 执行后获得 SUCCESS 结果
backpropagate(tree, node_A, outcome=ActionOutcome.SUCCESS, alpha=0.7)
# 更新计算
new_promise = 0.7 * 1.0 + (1-0.7) * 0.5
= 0.7 + 0.15
= 0.85
# node_A.promise_score 从 0.5 提升到 0.85
# 下次 UCB 选择时,该节点会被优先考虑(利用)
七、剪枝机制
7.1 剪枝条件
位于 excalibur/planner/pruning.py
python
# 剪枝决策逻辑
def should_prune(node, prune_threshold=0.8, min_attempts=3):
"""
判断节点是否应该被剪枝:
条件 1: TDI > prune_threshold (难度过高)
条件 2: visit_count >= min_attempts (已充分尝试)
只有同时满足两个条件时才剪枝
"""
7.2 剪枝可视化
python
# 示例:剪枝决策过程
node = AttackNode(
tdi=TDIScore(value=0.85), # TDI > 0.8 (难度高)
visit_count=5, # >= 3 (已充分尝试)
status=NodeStatus.ACTIVE
)
# should_prune(node) → True
# prune_branch(tree, node) → 将该节点及其子树标记为 PRUNED
八、模式选择(BFS/DFS/Hybrid)
8.1 模式选择器
位于 excalibur/planner/mode_selector.py
python
def select_mode(tdi_value, bfs_threshold=0.6, dfs_threshold=0.3):
"""
根据 TDI 值选择探索模式:
- TDI > 0.6: BFS (广度优先) - 快速扫描多个分支
- TDI < 0.3: DFS (深度优先) - 深入挖掘当前路径
- 否则: Hybrid (混合) - 平衡探索和利用
"""
8.2 模式对比
| 模式 | 适用场景 | 特点 |
|---|---|---|
| BFS | TDI 高,需要广泛扫描 | 快速发现新机会,但可能错过深度利用 |
| DFS | TDI 低,路径可靠 | 深入挖掘当前路径,充分利用已知信息 |
| Hybrid | TDI 中等 | 平衡策略,灵活调整 |
九、横向移动(Pivot)机制
9.1 Pivot 子树创建
python
# excalibur/planner/pivot.py:23
def spawn_pivot(tree, host, parent):
"""
当攻陷一个新主机时,创建横向移动子树。
新节点描述:
- type: ACTION (pivot action)
- description: "Pivot to <host> from <parent.description>"
- host: 新攻陷的主机地址
"""
9.2 凭证传播
python
# excalibur/planner/pivot.py:56
def propagate_credentials(tree, credentials):
"""
根据新发现的凭据重新评估被剪枝的节点。
如果新凭据可能使之前困难的节点变得可行,则重新激活它们。
"""
十、研究源码的方法论总结
10.1 阅读顺序建议
bash
# 推荐的文件阅读顺序:
# 第 1 层:入口点和核心架构
1. README.md # 整体概览
2. excalibur/core/controller.py # 中央协调器(主循环)
3. excalibur/planner/egats.py # EGATS 编排器
# 第 2 层:数据模型和核心算法
4. excalibur/planner/models.py # 攻击树数据结构
5. excalibur/planner/ucb.py # UCB 节点选择
6. excalibur/planner/tda.py # TDI 计算
7. excalibur/planner/backpropagation.py # 反向传播
8. excalibur/planner/pruning.py # 剪枝算法
# 第 3 层:辅助组件
9. excalibur/memory/context_assembler.py # 上下文组装
10. excalibur/memory/state_store.py # 状态存储
11. excalibur/planner/mode_selector.py # 模式选择
12. excalibur/planner/pivot.py # 横向移动
10.2 理解复杂代码的技巧
技巧 1:从调用链入手
python
# 找到入口点,追踪执行路径
excalibur/interface/main.py (CLI entry)
↓
excalibur/core/controller.run()
↓
excalibur/core/controller._egats_loop()
↓
excalibur/planner/egats.select_next_node()
技巧 2:关注数据流
python
# 追踪关键数据结构的变化
AttackTree → AttackNode → TDIScore → ActionOutcome
↓ ↓ ↓ ↓
创建树 选择节点 计算难度 评估结果
技巧 3:理解设计模式
- 单例模式 :
EventBus.get() - 观察者模式: 事件总线与 TUI 的解耦通信
- 策略模式: UCB、剪枝、模式选择的可配置算法
- 工厂模式 :
ContextAssembler组装上下文
技巧 4:结合测试用例
bash
# 运行相关测试理解功能
cd tests/unit
python -m pytest test_egats_loop.py -v # EGATS 循环测试
cat test_ucb.py # UCB 算法测试
10.3 调试技巧
python
# 在代码中添加调试输出
import logging
logging.basicConfig(level=logging.DEBUG)
# 或在关键位置添加断点
async def _egats_loop(self, initial_task: str):
# ...
current_node = self._planner.select_next_node(tree)
print(f"Selected node: {current_node.id}, UCB score: {current_node.promise_score}")
# ...
十一、完整公式详解
概述
本节将第十一章的快速参考卡片内容扩展为完整的公式详解,涵盖 EGATS 规划器的所有核心计算公式。
核心组件与公式概览
┌─────────────────────────────────────────────────────────────┐
│ EGATSPlanner │
│ ┌──────────────┬──────────────┬──────────────┬────────────┐│
│ │ TDA │ UCB │ Backprop │ Pruning ││
│ │ (任务难度评估) │(节点选择策略) │(反向传播) │ (剪枝) ││
│ └──────────────┴──────────────┴──────────────┴────────────┘│
│ ↓ ↓ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Attack Tree (攻击树) │ │
│ │ Root → Children → Leaves │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
核心公式速览
| 类别 | 名称 | 完整公式 | 默认参数 |
|---|---|---|---|
| TDI | 综合难度指数 | w_h·H + w_e·(1-E) + w_c·C + w_s·(1-S) |
weights: {h:0.3, e:0.3, c:0.2, s:0.2} |
| TDI | Horizon (视野深度) | depth / max_depth |
- |
| TDI | Success Rate (成功率) | (success + 1) / (visits + 2) (拉普拉斯平滑) |
- |
| TDI | Evidence Confidence | Σ(evidence_level) / path_length |
- |
| UCB | 节点选择评分 | φ(n) + c·√(ln(N)/Nₙ) - dp·δ(n) |
c=1.414, dp=0.5 |
| Backprop | 承诺分数更新 | φ = α·R + (1-α)·φ_old |
α=0.7 |
| Pruning | 剪枝条件 | TDI > threshold AND visits >= min_attempts |
threshold=0.8, min_attempts=3 |
| Mode | BFS 模式阈值 | TDI > 0.6 |
- |
| Mode | DFS 模式阈值 | TDI < 0.3 |
- |
配置参数速查
python
# excalibur/planner/egats.py:39
_DEFAULT_CONFIG = {
"exploration_constant": 1.414, # UCB 探索常数 √2
"difficulty_penalty": 0.5, # TDI 难度惩罚权重
"backprop_alpha": 0.7, # 反向传播平滑因子
"prune_threshold": 0.8, # 剪枝阈值
"min_prune_attempts": 3, # 最小尝试次数
"bfs_threshold": 0.6, # BFS 模式切换阈值
"dfs_threshold": 0.3, # DFS 模式切换阈值
}
11.1 TDI(任务难度指数)详细计算
11.1.1 四个维度的计算公式
| 维度 | 符号 | 计算公式 | 取值范围 | 说明 |
|---|---|---|---|---|
| Horizon (视野深度) | H | depth / max_depth |
[0, 1] | 归一化深度,越深难度越大 |
| Success Rate (成功率) | S | (success_count + 1) / (visit_count + 2) |
[0, 1] | 拉普拉斯平滑避免除零 |
| Context Load (上下文负载) | C | token_used / token_budget |
[0, 1] | Token 预算利用率 |
| Evidence Confidence (证据置信度) | E | Σ(evidence_level) / path_length |
[0, 1] | 路径上所有节点证据级别的平均值 |
11.1.2 TDI 综合计算公式
python
# excalibur/planner/models.py:137-142
def compute_tdi_value(self) -> float:
"""
TDI = w_h·H + w_e·(1-E) + w_c·C + w_s·(1-S)
各项含义:
- w_h·H: 深度带来的难度(越深越难)
- w_e·(1-E): 证据不足带来的难度(证据越少越难)
- w_c·C: 上下文负载带来的难度(token 占用越多越难)
- w_s·(1-S): 成功率低带来的难度(失败多则难)
"""
return (
self.weight_horizon * self.horizon
+ self.weight_evidence * (1.0 - self.evidence_confidence)
+ self.weight_context * self.context_load
+ self.weight_success * (1.0 - self.success_rate)
)
11.1.3 TDI 计算示例
python
# excalibur/planner/tda.py:62-74
node = AttackNode(
success_count=3,
failure_count=1,
visit_count=4,
evidence_level=EvidenceLevel.CONFIRMED # 0.8
)
tree = AttackTree(...) # 包含完整路径信息
tdi = TDAComputer().compute_tdi(node, tree, context_load=0.3)
# 计算过程:
# horizon = depth / max_depth = 3/5 = 0.6
# success_rate = (3+1)/(4+2) = 4/6 = 0.67 (拉普拉斯平滑)
# context_load = 0.3 (传入参数)
# evidence_confidence = 路径上所有节点证据级别的平均值
print(f"TDI: {tdi.value:.3f}")
# 输出示例:TDI: 0.425
11.1.4 TDI 权重配置
python
# excalibur/planner/egats.py:47-52
"tda_weights": {
"horizon": 0.3, # 视野深度权重 - 中等重要性
"evidence": 0.3, # 证据权重 - 高重要性(证据不足会显著增加难度)
"context": 0.2, # 上下文负载权重 - 较低
"success": 0.2, # 成功率权重 - 较低
}
11.2 UCB(上置信界)详细计算
11.2.1 UCB 公式详解
python
# excalibur/planner/ucb.py:37-40
UCB(n) = φ(n) + c · √(ln(N) / Nₙ) - dp · δ(n)
| 符号 | 含义 | 默认值 | 说明 |
|---|---|---|---|
| φ(n) | promise_score (承诺分数) | [0,1] | 基于历史奖励的节点价值估计 |
| c | exploration_constant | 1.414 (=√2) | 探索项权重,控制探索与利用的平衡 |
| N | total_actions | - | 树中已执行的总动作数 |
| Nₙ | visit_count | - | 节点 n 被访问的次数 |
| dp | difficulty_penalty | 0.5 | 难度惩罚权重 |
| δ(n) | TDI 值 | [0,1] | 节点 n 的难度指数 |
11.2.2 UCB 三项分解
python
# excalibur/planner/ucb.py:57-61
for node in candidates:
visits = max(node.visit_count, 1)
# 1. Exploitation (利用项): 基于历史表现
exploitation = node.promise_score
# 2. Exploration (探索项): 访问次数少的节点获得奖励
exploration = c * sqrt(ln(N) / visits)
# 3. Difficulty Penalty (难度惩罚): 高 TDI 的节点被 penalize
difficulty_penalty = dp * tdi_value
ucb = exploitation + exploration - difficulty_penalty
11.2.3 UCB 计算示例
python
# excalibur/planner/ucb.py:57-64
total_actions = 100 # N
# 节点 A:已访问多次,承诺分数高
node_A = AttackNode(
promise_score=0.8, # φ(n) 较高
visit_count=50, # N_n 较大
tdi=TDIScore(value=0.3) # δ(n) 较低(难度小)
)
# UCB(A) = 0.8 + 1.414 * √(ln(100)/50) - 0.5 * 0.3
# = 0.8 + 1.414 * 0.26 - 0.15
# = 0.8 + 0.37 - 0.15 = 1.02
# 节点 B:访问较少,承诺分数中等
node_B = AttackNode(
promise_score=0.6,
visit_count=10,
tdi=TDIScore(value=0.4)
)
# UCB(B) = 0.6 + 1.414 * √(ln(100)/10) - 0.5 * 0.4
# = 0.6 + 1.414 * 0.58 - 0.2
# = 0.6 + 0.82 - 0.2 = 1.22
# 结果:选择节点 B(探索奖励更高)
11.3 反向传播详细计算
11.3.1 指数平滑公式
python
# excalibur/planner/backpropagation.py:31
φ(parent) = α · R + (1-α) · φ_old(parent)
| 符号 | 含义 | 默认值 |
|---|---|---|
| φ(parent) | 更新后的承诺分数 | - |
| α | 平滑因子 | 0.7 |
| R | 当前结果奖励值 | SUCCESS=1.0, PARTIAL=0.5, FAILURE=0.1 |
| φ_old(parent) | 之前的承诺分数 | [0,1] |
11.3.2 反向传播完整流程
python
# excalibur/planner/backpropagation.py:42-51
def backpropagate(tree, node, outcome, alpha=0.7):
path = tree.get_path_to_root(node.id)
reward = outcome.value # 根据结果获取奖励值
for path_node in path:
# 指数平滑更新承诺分数
path_node.promise_score = (
alpha * path_node.promise_score +
(1 - alpha) * reward
)
# 更新访问统计
path_node.visit_count += 1
if outcome == ActionOutcome.SUCCESS:
path_node.success_count += 1
elif outcome == ActionOutcome.FAILURE:
path_node.failure_count += 1
11.3.3 反向传播示例
python
# excalibur/planner/backpropagation.py:46
node_A.promise_score = 0.5 # 初始承诺分数
# 执行后获得 SUCCESS 结果 (reward=1.0)
backpropagate(tree, node_A, outcome=ActionOutcome.SUCCESS, alpha=0.7)
# 更新计算
new_promise = 0.7 * 1.0 + (1-0.7) * 0.5
= 0.7 + 0.15
= 0.85
# node_A.promise_score 从 0.5 提升到 0.85
11.4 剪枝机制完整公式
11.4.1 剪枝条件
python
# excalibur/planner/pruning.py:44-46
def should_prune(node, threshold=0.8, min_attempts=3):
"""
剪枝决策逻辑:
条件 1: TDI > threshold (难度过高)
条件 2: visit_count >= min_attempts (已充分尝试)
只有同时满足两个条件时才剪枝
"""
if node.tdi is None:
return False
return node.tdi.value > threshold and node.visit_count >= min_attempts
11.4.2 剪枝阈值配置
python
# excalibur/planner/egats.py:43-44
"prune_threshold": 0.8, # TDI > 此值考虑剪枝
"min_prune_attempts": 3, # 最小尝试次数后才允许剪枝
11.4.3 剪枝决策表
| TDI 值 | visit_count | should_prune |
|---|---|---|
| > 0.8 | >= 3 | ✅ True (高难度且已充分尝试) |
| > 0.8 | < 3 | ❌ False (虽然难但还需更多尝试) |
| <= 0.8 | >= 3 | ❌ False (难度可接受,保留探索) |
| <= 0.8 | < 3 | ❌ False (难度低且未充分尝试) |
11.5 模式选择完整公式
11.5.1 模式选择逻辑
python
# excalibur/planner/mode_selector.py:42-46
def select_mode(tdi_value, bfs_threshold=0.6, dfs_threshold=0.3):
"""
根据 TDI 值选择探索模式:
- TDI > 0.6: BFS (广度优先) - 快速扫描多个分支
- TDI < 0.3: DFS (深度优先) - 深入挖掘当前路径
- 否则: Hybrid (混合) - 平衡探索和利用
"""
if tdi_value > bfs_threshold:
return "reconnaissance" # BFS 模式
if tdi_value < dfs_threshold:
return "exploitation" # DFS 模式
return "llm_decide" # Hybrid 模式
11.5.2 模式选择决策表
| TDI 值范围 | 返回模式 | 策略说明 |
|---|---|---|
| > 0.6 | reconnaissance (BFS) | 高难度,需要广泛扫描发现更多机会 |
| < 0.3 | exploitation (DFS) | 低难度,专注于已知可行路径的深度利用 |
| [0.3, 0.6] | llm_decide (Hybrid) | 中等难度,让 LLM 根据具体情况决定 |
11.6 凭证传播机制
11.6.1 凭证相关性判断
python
# excalibur/planner/pruning.py:102-117
def _cred_relevant(node, credential):
"""
检查凭据是否可能与被剪枝的节点相关。
使用关键词启发式方法:如果节点的描述提到了
与认证相关的服务,则认为凭据可能相关。
"""
auth_keywords = [
"login", "auth", "ssh", "rdp", "smb",
"ftp", "password", "credential", "winrm"
]
desc_lower = node.description.lower()
return any(kw in desc_lower for kw in auth_keywords)
11.6.2 凭证重新评估流程
python
# excalibur/planner/pruning.py:71-98
def reevaluate_pruned(tree, new_credentials):
"""
重新打开可能受益于新凭据的被剪枝分支。
当发现新凭据时,之前被剪枝的与认证相关的分支
可能变得可行。此函数会重置其状态和统计信息。
"""
reopened = []
if not new_credentials:
return reopened
for node in tree.nodes.values():
# 检查节点是否被剪枝且凭据相关
if (node.status == NodeStatus.PRUNED and
any(_cred_relevant(node, cred) for cred in new_credentials)):
# 重置状态和统计信息
node.status = NodeStatus.PENDING
node.visit_count = 0
node.success_count = 0
node.failure_count = 0
reopened.append(node.id)
return reopened
11.7 完整公式速查表
| 类别 | 名称 | 完整公式 | 默认参数 |
|---|---|---|---|
| TDI | 综合难度指数 | w_h·H + w_e·(1-E) + w_c·C + w_s·(1-S) |
weights: {h:0.3, e:0.3, c:0.2, s:0.2} |
| TDI | Horizon (视野深度) | depth / max_depth |
- |
| TDI | Success Rate (成功率) | (success + 1) / (visits + 2) (拉普拉斯平滑) |
- |
| TDI | Evidence Confidence | Σ(evidence_level) / path_length |
- |
| UCB | 节点选择评分 | φ(n) + c·√(ln(N)/Nₙ) - dp·δ(n) |
c=1.414, dp=0.5 |
| Backprop | 承诺分数更新 | φ = α·R + (1-α)·φ_old |
α=0.7 |
| Pruning | 剪枝条件 | TDI > threshold AND visits >= min_attempts |
threshold=0.8, min_attempts=3 |
| Mode | BFS 模式阈值 | TDI > 0.6 |
- |
| Mode | DFS 模式阈值 | TDI < 0.3 |
- |
附录:相关文件索引
| 文件 | 路径 | 功能 |
|---|---|---|
| EGATSPlanner | excalibur/planner/egats.py:56 |
主编排器 |
| AttackNode | excalibur/planner/models.py:153:153 |
节点数据模型 |
| AttackTree | excalibur/planner/models.py:199:199 |
树数据模型 |
| UCB Selector | excalibur/planner/ucb.py:30 |
节点选择算法 |
| TDA Computer | excalibur/planner/tda.py:46 |
TDI 计算 |
| Backpropagation | excalibur/planner/backpropagation.py:13 |
反向传播 |
| Pruning | excalibur/planner/pruning.py |
剪枝算法 |
| Mode Selector | excalibur/planner/mode_selector.py |
模式选择 |
| Pivot Manager | excalibur/planner/pivot.py:23 |
横向移动 |
| Controller | excalibur/core/controller.py:59 |
主控制器 |