preemware/OPFORA
GitHub: preemware/OPFORA
OPFORA 是一个基于 LangGraph 和 Deep Agents 构建的自主攻击型安全智能体,能够无人值守地解决 HTB 级别 CTF 靶机并测试 Web 应用安全漏洞。
Stars: 8 | Forks: 0
# OPFORA
自主攻击型安全 agent。能够无人值守地解决 HTB 级别的 CTF 靶机,测试 Web 应用的 OWASP 级别问题,通过阅读互联网信息来为其推理提供基础。基于 LangGraph + Deep Agents 构建。
**它不是红队替代品。** 不对抵抗现代 EDR 的 OPSEC 做出任何承诺,不对社会工程学做出任何承诺,也不对自主闭合防御闭环做出任何承诺。
## 一段话简介
由一个读取结构化发现结果并决定下一步操作的主 agent 协调的一小部分 subagent(Surface、Exploit、PostEx 和 Analyst)。所有攻击工具都部署在 MCP server 之后 —— `surface`(侦察 + Web)、`exploit`(payload + 传递)、`postex`(枚举 + 提权)、`browser`(Playwright)、`shell`(tmux 会话)、`episodes`(基于 Postgres 的日志)。三种任务模式(`ctf`、`lab`、`engagement`)具有不同的 prompt 和 HITL 策略。由 middleware 强制执行的确定性交战规则 门控 —— 模型绝不自行决定目标是否在范围内。
## 已攻破的靶机
OPFORA 已无人值守拿下 root 权限的 [HackTheBox](https://www.hackthebox.com/) 机器:
Bounty · Connected · DevArea · Devhub · Helix · Monteverde · Nibbles · Optimum · Querier · Resolute · SmartHIRE · Silentium · Support · WingData · Reactor · Kobold
使用 **`opfora engage`** 无人值守运行其中任何一台 —— 当配置规范包含 `htb:` 块时,它会通过 HTB API 启动靶机,解决问题,提交 flag,并销毁靶机([详情](#htb--hackthebox-auto-provisioning))。
**不要盲目相信这个列表 —— 请自行复现。** 这些声明记录在
[`benchmark/claims.yaml`](benchmark/claims.yaml) 中,并与本地生成的
构件进行核对,而不是仅凭文字说明:
```
opfora benchmark list # available suites
opfora benchmark run htb-retired-small # spawns/solves/tears down, writes a metrics artifact
opfora benchmark run xbow-full --sample 30 # XBEN pass@1 estimate + 95% CI, ~1/3 the cost of all 104
opfora benchmark verify # re-derive claims.yaml from benchmark/results/ (exit 1 if any unbacked)
opfora benchmark report # aggregate metrics across all runs
```
只有当 `benchmark/results/` 中提交/生成的结果证明其有效时(获取了 root 权限,且 flag 被 HTB 本身接受),
`verify` 才会将每项声明报告为 VERIFIED —— 否则为 UNVERIFIED。全新克隆 -> 在你运行之前一切均为
UNVERIFIED,这正是其目的所在。`report` 会汇总每次运行的关键指标:初始立足点
获取率、root/admin 获取率、平均成本、平均时间、工具调用、人工干预、
RoE 拦截、卡死检测器激活次数以及阻止的重复失败操作(每一个
数字都可追溯到 episode 日志、Redis 或运行记录 —— 参见 [`benchmark/bench.py`](benchmark/bench.py))。
**客观的能力画像:** 获取初始立足点(靶机上的一个 shell)在这里是一个几乎被解决的问题 —— 侦察 -> 漏洞 -> exploit 在广泛的目标范围内能可靠生效。**提权则时好时坏。** 有些靶机可以直接提权到 root;另一些则在提权链上停滞不前(钻牛角尖走错了路、不明显的横向跳跃、特定环境下的技巧),这也是目前大部分正在进行的工作所聚焦的领域。
## 快速开始
**实战快速路径** —— 针对单个目标,无需了解整个平台。在执行
`pip install -e .`(下文的步骤 1)并将 provider 密钥添加到 `.env` 之后:
```
opfora doctor # check Docker, keys, datastores, MCP health
opfora setup # write .env + build images (one time)
opfora quickstart 10.129.245.50 # minimal stack up + engage that target
```
`quickstart` 仅启动必要的组件(postgres、redis、gateway 以及
surface/shell/episodes MCP server —— 不包含 Neo4j、LiteLLM proxy 或 Web UI),编写
规范并开始执行任务。使用 `opfora up --minimal` 可以在不执行任务的情况下启动该精简技术栈,
或者使用 `opfora up` 启动完整技术栈。随时运行 `opfora doctor`
来诊断出现故障的环境配置。
**完整手动设置:**
```
# 0. 复制 env 并进行编辑
cp .env.example .env
# 1. 将 Python 后端安装到 venv 中
# 需要 Python 3.11+。如果 `python3` 版本较旧,请先安装 3.11 或 3.12
# (例如 `brew install python@3.12`)并在下文中进行替换。
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
# 2. 启动 management plane
docker compose -f infra/docker-compose.yml up -d
# 3a. (本地开发) 在 ops network 上启动 DVWA / Juice Shop
docker compose -f infra/docker-compose.yml -f infra/docker-compose.ops.yml \
--profile dev-targets up -d
# 3b. (HTB / 外部) 直接跳过 — `opfora engage` 会根据你 spec 中的 `vpn_config:` 字段自动启动
# VPN sidecar。
# (只能选择 3a 或 VPN overlay 中的一项 — 它们是互斥的,
# 因为 `network_mode: service:vpn` 与 ops-net 互斥。)
# 4. 运行它
opfora init # one-time onboarding
# HackTheBox:一个 `htb:` 块会让 `engage` 为你 SPAWN 靶机,解决它,
# 提交 flags,并将其销毁。不需要目标 IP。
# (需要在 .env 中配置 HTB_TOKEN — 参见 Engagement spec 中的 “htb”。)
opfora engage docs/examples/htb-challenge.yaml
# 已存在的目标(本地 VM、你 SPAWN 的靶机、客户端 IP):
opfora engage docs/examples/metasploitable.yaml --profile eco
```
规范驱动目标:带有 `htb:` 块时,`engage` 会通过 HTB API 配置机器,因此你无需手动提供每次启动的 IP;如果没有该块,它将针对你提供并管理的目标运行。
CLI 会将每个 subagent 的输出(带有颜色区分)流式传输到你的终端。Web 仪表板(可选)位于 http://localhost:3000。
### 完整记录(`--debug-log`)
`engage`、`attach` 和 `resume` 都接受 `--debug-log ` 参数,该参数以 JSON Lines(每行一个事件)格式记录 agent 的**完整过程** —— 每一次工具调用、工具结果和模型消息:
```
opfora engage docs/examples/metasploitable.yaml --debug-log logs/run.jsonl
# 或者捕获一个正在运行的 engagement:
opfora attach --debug-log logs/run.jsonl
```
这是一次运行的完整机器可读记录 —— 非常适合用于事后分析、回放发生的过程,或者交给 LLM 来询问“它为什么在这里失败了?”。该文件是**追加模式**的(每次 attach 都会添加一个 `_debug_meta` 分隔符,因此重新挂载永远不会覆盖之前的捕获内容)。事件**仅在挂载时被捕获**:如果你分离了,请使用 `--debug-log` 重新挂载以恢复记录。
### VPN 流程
VPN 挎载模式:单个 `vpn` 容器持有 OpenVPN 隧道,攻击型 MCP server 通过 `network_mode: "service:vpn"` 加入其网络 namespace。从 `nmap`、`curl`、Playwright 或已落地的 shell 发出的每一个出站数据包都会通过该隧道路由。
- **`.ovpn` 在任务 YAML 中声明。** 将 `vpn_config:` 设置为一个路径(绝对路径,或相对于规范文件的路径)—— `opfora engage` 会解析它并在启动前带起 VPN 挎载容器。解析优先级:`--vpn` CLI 标志 > `VPN_FILE` 环境变量 > 规范中的 `vpn_config:`。
- 每个 compose 栈只有一个 VPN —— 要切换目标,请更改规范中的 `vpn_config:` 并重新运行 `opfora engage`。当挂载源发生变化时,Compose 会重新创建挎载容器。
- 当 VPN 覆盖层处于活动状态时,`ops-net` 上的本地开发目标(DVWA、Juice Shop)将无法从 MCP 容器访问。请在本地开发或 VPN 之间二选一,不能同时使用。
- 传入 `--skip-vpn` 可以保持 compose 原样不动(当挎载容器已经使用正确的 .ovpn 启动,或者在非 VPN 运行时使用)。
**HTB 自动 VPN(无需 `.ovpn` 文件)。** 对于 `htb:` 运行,你可以完全跳过 `vpn_config:`:将其留空,`opfora engage` 会在运行时从 HTB API 获取实验环境隧道。CLI 会启动攻击型 MCP 并让它们共享 VPN namespace,并且一旦靶机启动,gateway 就会下载机器的 `.ovpn` 并将其推送到沙箱中 —— 无需你自己下载或管理文件。
- 自动 VPN **仅在规范包含 `htb:` 且没有 `vpn_config`** 时被选用。如果设置了 `vpn_config:`(或者 `--vpn` / `VPN_FILE` 指向一个文件),CLI 会采用该静态路径,如果缺少该 `.ovpn` 则会报错 —— 因此要使用自动 VPN,请确保这三个都没有设置(如果 shell 中还残留着 `VPN_FILE`,请执行 `unset VPN_FILE`)。
- 需要在 `.env` 中设置 `HTB_TOKEN`(用于 API 下载)。`HTB_AUTO_VPN` 默认开启;将其设置为 `0` 可禁用。
## 任务规范
任务由传递给 `opfora engage .yaml` 的单个 YAML 文件描述。模板位于 [`docs/examples/`](docs/examples/) 中。一个全功能示例:
```
name: htb-checkpoint # label for the engagement (required)
mode: ctf # ctf | lab | engagement (required)
targets: # hostnames or CIDRs in scope
- 10.129.245.50
objective: "root flag" # what "done" means (free text)
expected_flags: 2 # user + root — see below
budget_usd: 5.0 # hard cost cap for the run
profile: eco # eco | max | test (model tiers)
autonomy: standard # observe | assist | standard | aggressive-lab | engagement-safe
vpn_config: ../../client.ovpn # .ovpn path (absolute, or relative to this file)
# Operator briefing — 原样折叠到 agent 的开场消息中。
# 自由文本形式的 pre-engagement 上下文:scope 提示、内部 hostname、
# 已知的良好 foothold 路径、“不要触碰 X”。对于初始 creds,请使用 `credentials`。
notes: |
Assumed-breach start. The DC re-randomizes per spawn — re-derive any
recovered secret each run rather than reusing an old value.
# Assumed-breach / 提供的 credentials。持久注入到 orchestrator
# 和 offensive-subagent 的 system prompts 中,以便 agent 从一开始就使用它们,
# 而不是试图发现或破解它已经拥有的内容。
credentials:
- username: alex.turner
secret: "Checkpoint2024!"
kind: password # password | hash | ssh-key | token | api-key
service: smb # ssh | smb | winrm | http | mysql | domain | ... (optional)
host: dc01 # scope to one host (optional)
notes: domain account for authenticated enum + lateral movement (optional)
# Rules of engagement。在 ctf/lab 模式下,scope 会从 `targets` 自动推导,
# 因此你通常可以省略此项。在 `engagement` 模式下为必填项(已签署的 RoE)。
roe:
allowed_hosts: ["*.corp.local"] # exact or wildcard hostnames
allowed_networks: ["10.10.0.0/16"]# CIDRs
blocked_hosts: ["10.10.0.5"] # never touch, even if in an allowed range
self_hosts: ["10.10.14.0/23"] # your LHOST/VPN/staging — exempt from scope checks
blocked_ports: [3389]
allowed_techniques: ["*"] # "*" or categories: recon, exploit, postex, ...
blocked_techniques: []
destructive_requires_approval: true
signed_document_path: ./roe.pdf # REQUIRED for `engagement` mode
signed_by: "Jane Client"
signed_at: 2026-06-01T00:00:00Z
```
### 字段
| 字段 | 必需 | 默认值 | 说明 |
|---|---|---|---|
| `name` | 是 | — | 任务标签(用于报告 + `opfora ls`)。 |
| `mode` | 是 | — | `ctf` \| `lab` \| `engagement` —— 参见[三种模式](#three-modes)。 |
| `targets` | 是* | `[]` | 主机名或 CIDR;在 ctf/lab 模式下,它们还会作为 RoE 白名单的种子。*当设置了 `htb` 时为可选 —— 启动的靶机 IP 会自动为你填充。 |
| `objective` | 否 | `"root"` | 编排器努力达成的自由文本目标。 |
| `expected_flags` | 否 | 未设置 | 设置后(例如 HTB 的 user+root 对应 `2`),确定性门控会强制在该数量的 flag 被记录后进行分析师交接。对于多主机实验环境请保持未设置。 |
| `budget_usd` | 否 | `10.0` | `budget_guard` 在 80% 时警告,在 95% 时硬性停止。 |
| `profile` | 否 | `eco` | 模型层级 —— 参见 [Profiles](#profiles)。CLI 上的 `--profile` 会覆盖此项。 |
| `autonomy` | 否 | 模式默认值 | 显式信任姿态 —— 参见 [Autonomy](#autonomy)。CLI 上的 `--autonomy` 会在此次运行中覆盖此项。 |
| `vpn_config` | 否 | 无 | 指向 `.ovpn` 的路径;`opfora engage` 会带起 VPN 挎载容器。优先级:`--vpn` > `VPN_FILE` 环境变量 > 此项。 |
| `notes` | 否 | `""` | 操作员简报 —— 见下文。 |
| `credentials` | 否 | `[]` | 假定突破凭证 —— 见下文。 |
| `htb` | 否 | 无 | HackTheBox 自动配置(启动/销毁)。设置后,`opfora engage` 会自动配置靶机 —— 见下文。 |
| `roe` | 否¹ | 自动 | 交战规则。¹在 `engagement` 模式下必需(需提供 `signed_document_path`)。 |
### Autonomy
在规范中设置 `autonomy:` 或在某次运行中覆盖它:
```
opfora engage spec.yaml --autonomy observe
```
| 等级 | 行为 |
|---|---|
| `observe` | 仅进行组织、总结和建议。面向目标的操作会被阻止。 |
| `assist` | 被动侦察只能在 HITL 批准后运行;exploit/后渗透类别被阻止。 |
| `standard` | 侦察和其他安全的工作流步骤自动运行;exploit、凭证、横向移动、数据访问、持久化和规避类别需要 HITL 批准。 |
| `aggressive-lab` | 针对实验/靶机(CTF/lab)使用的完全自主。 |
| `engagement-safe` | 针对安全测试的严格 HITL,适用于 exploit、凭证、横向移动、数据访问、持久化和规避类别。 |
### `notes` — 操作员简报
作为 **OPERATOR BRIEFING** 块逐字传递给 agent 初始消息的自由文本。用于 agent 在开始前应该知道的、非凭证类的任何信息:范围提示、内部主机名、一个已知良好的初始立足点路径以跳过重新推导、“靶机每次启动都会重新随机化”等。它会传达给编排器,编排器会将相关部分中继到 subagent 的任务简报中。
### `credentials` — 假定突破访问
任务开始时拥有的一系列凭证(就像真实的“假定突破”渗透测试一样)。与 `notes` 不同,这些信息会**持久地**展示在编排器和攻击型 subagent 的系统 prompt 中(系统 prompt 不会在长时间的运行中被摘要掉),告诉 agent 在发现或破解新凭证之前先*使用*它已持有的凭证。
| 子字段 | 必需 | 说明 |
|---|---|---|
| `username` | 是 | 账户名。 |
| `secret` | 否 | 密码、NTLM hash、密钥材料、token。对于仅提示用户名的情况请省略。 |
| `kind` | 否(`password`) | `password` \| `hash` \| `ssh-key` \| `token` \| `api-key`。 |
| `service` | 否 | `ssh` \| `smb` \| `winrm` \| `http` \| `mysql` \| `domain` \| …… —— 使用位置。 |
| `host` | 否 | 将凭证范围限定在某一台主机。 |
| `notes` | 否 | 自由文本(例如“属于 docker 组”)。 |
### `htb` — HackTheBox 自动配置
添加一个 `htb:` 块,让目标通过 HTB API **自动启动、解决并销毁**,而不是提供一个需要你手动启动/重置的静态 `targets:` IP。这完全由规范驱动 —— `opfora engage` 检测到 `htb:` 块就会自动配置靶机;无需单独的命令:
```
opfora engage docs/examples/htb-challenge.yaml
```
```
name: htb-support
mode: ctf
expected_flags: 2
htb:
machine: Support # HTB machine name or numeric id (required)
teardown: on_complete # on_complete | on_success | never
submit_flags: true # POST captured flags to HTB to confirm the solve
difficulty: 5 # 1..10 rating sent with each flag
# reset_before: false # reset the box to a clean state before the run
# kind: retired # active | retired | release | starting_point (auto-detected if unset)
# spawn_timeout_s: 180 # how long to wait for the box to get an IP
vpn_config: ../machines_us-3.ovpn
# 没有 `targets:` — SPAWN 的靶机的 IP 会自动填入
```
配置在 **gateway 端运行** —— `/eng` 端点会检测到 `htb:` 块并包围这次运行,因此 CLI *和* Web 仪表板都能仅凭规范获取配置信息。每次运行的生命周期:**解析 -> 启动 -> 等待 IP -> 针对其运行一次任务 -> 提交捕获的 flag -> 销毁。**
| `htb:` 子字段 | 必需 | 默认值 | 说明 |
|---|---|---|---|
| `machine` | 是 | — | HTB 机器名称或数字 id。 |
| `kind` | 否 | 自动 | `active` \| `retired` \| `release` \| `starting_point`;如果未设置则会自动检测。 |
| `teardown` | 否 | `on_complete` | `on_complete`(总是),`on_success`(仅在解决时),或 `never`。 |
| `submit_flags` | 否 | `true` | 将每个捕获的 flag 提交给 HTB(`own`)以确认解题成功。 |
| `difficulty` | 否 | `5` | HTB 提交 flag 时要求的 1-10 评分。 |
| `reset_before` | 否 | `false` | 在开始前将机器重置为干净状态。 |
| `spawn_timeout_s` | 否 | `180` | 等待靶机获取 IP 的最长时间。 |
说明:
- **需要 `HTB_TOKEN`**(HTB 账户 -> *App Tokens*)位于 `.env` 中 —— **gateway** 会读取它(compose 中的 `env_file: ../.env`),因为配置是在 gateway 端进行的。如果账户上已经启动了另一台不同的机器,会先终止该机器(HTB 只允许一个活跃靶机)。
- VPN 由 CLI 在运行前带起(`vpn_config` / `--vpn` / `VPN_FILE`)—— gateway 无法控制挎载容器 —— 且 HTB 靶机只能通过实验环境的 VPN 访问。**请使用 TCP `.ovpn`**(见 [VPN 流程](#vpn-flow))。
- 销毁通过 `htb.teardown` 进行**规范驱动**(`on_complete` / `on_success` / `never`);通常的 `--profile` / `--skip-vpn` / `--debug-log` 依然适用。
- **HTB 运行是原子的:** Ctrl-C 会取消运行,且 gateway 依然会销毁机器 —— 而针对静态目标的 `engage` 会暂停以等待 `opfora resume`。规范中的 `htb:` 块会选择此行为:包含该块时,gateway 会在 HTB 启动 -> flag 提交 -> 销毁的流程中包裹运行;如果没有,它将针对你提供并管理的目标运行。
## 三种模式
| 模式 | 用途 | RoE | HITL |
|---|---|---|---|
| `ctf` | HTB 单机 | 根据目标自动生成 | 无 —— 放手施为 |
| `lab` | 多主机实验环境(Pro Labs、PG) | 根据目标自动生成 | 仅限横向移动 |
| `engagement` | 授权的真实测试 | 需要签名文档 | 所有破坏性操作 |
模板请参见 [`docs/examples/`](docs/examples/)。
## Profiles
模式决定*姿态*;profiles 决定*模型*。Profiles 独立于
模式 —— 在 CLI 上使用 `--profile` 可覆盖规范中的值。Autonomy
级别可以在不更改模式的情况下,进一步收紧或放宽 HITL 行为。
### 各角色、各 profile 的层级
| Profile | Orchestrator | Surface | Exploit | PostEx | Analyst | Researcher | AD¹ |
|---|---|---|---|---|---|---|---|
| `eco` (默认) | HIGH | MID | HIGH | MID | MID | MID | HIGH |
| `max` | HIGH | HIGH | HIGH | HIGH | HIGH | HIGH | HIGH |
| `test` | LOW | LOW | LOW | LOW | LOW | LOW | LOW |
| `qwen` | 所有角色开启 `qwen/qwen3.7-max`(通过 OpenRouter) | | | | | | |
| `gpt` | 所有角色开启 `gpt-5.5` | | | | | | |
¹ AD 专家(通过 `MCP_AD_URL` 启用)沿用 Exploit 层级。
² `qwen` 和 `gpt` 是单模型 profiles —— 每一个角色都使用同一个模型,用于
脱离基于 Anthropic 优先的分层默认设置的成本/评估运行。
层级映射位于 [`src/agent/models.py`](src/agent/models.py);LiteLLM
路由链位于 [`infra/litellm-config.yaml`](infra/litellm-config.yaml)。
### 层级 -> 模型映射
| 层级 | Anthropic (首选) | OpenAI (备选) | Google (备选) | 本地备选 |
|---|---|---|---|---|
| **HIGH** | `claude-opus-4-8` | `gpt-5.5` | `gemini-3-pro` | — |
| **MID** | `claude-sonnet-5` | `gpt-5.4-mini` | `gemini-flash` | — |
| **LOW** | `claude-haiku-4-5` | `gpt-5.4-nano` | — | `qwen3-32b` (Ollama) |
默认情况下,agent 会通过 LiteLLM proxy 路由所有的模型调用(需要
`LITELLM_MASTER_KEY`)。这会激活
[`infra/litellm-config.yaml`](infra/litellm-config.yaml) 中的备选链,外加 Redis 响应
缓存、支出/预算追踪以及 Langfuse 可观测性,并且会路由每一个
模型,包括 `qwen`/OpenRouter profile。
设置 `OPFORA_USE_LITELLM=false` 可以直接调用每个 provider 的 SDK —— 这
保留了 Anthropic 原生的 prompt 缓存(在重度依赖 Opus 的运行中更便宜),但是
上面的备选链将失效(首选方案的宕机会通过
每次调用的重试来处理,而不是 provider 故障转移),并且 `qwen` 将直接与 OpenRouter 通信。
### 为什么这样选择
- **Orchestrator 和 Exploit 在 `eco` 中保持 HIGH**(且 AD 专家沿用 Exploit 层级,因此它也是 HIGH)。这些承载着核心的负载推理。特别是降低 Exploit 层级会导致在困难靶机上的静默失败 —— 错误的 payload、无法链式执行的阶段、放弃了一条原本可行的路径。
- **`eco` 的下限是 MID,绝不为 LOW。** `eco` 相对于 `max` 节省成本的方式是在非关键角色上运行 MID(Sonnet),而不是降级到 LOW(Haiku)—— Haiku 会搞砸 PostEx 提权分类,因此 LOW 专门保留给 `test` profile。
- **Surface、PostEx、Analyst 和 Researcher 在 `eco` 中运行 MID。** Surface 主要是工具编排;PostEx 是一旦 shell 落地后的 shell 循环(提权*分类*仍然会经过 HIGH 的 Orchestrator);Analyst 是一次性的报告生成;Researcher 的深度阅读非常昂贵 —— 当某台机器需要进行艰难的 CVE 挖掘时,请使用 `--profile max` 升级它。
- **`max` 用于你输不起的任务。** 真实的客户测试、新颖的目标,以及任何推理质量比单步成本更重要的场合。
- **`test` 的存在是为了让 CI 不会让任何人破产。** 不要将其指向真实目标;LOW 层级的模型会漏掉更高层级能捕捉到的东西。
### 订阅认证(Claude Code / Codex)
不想给 OPFORA 提供原始 API 密钥?使用与 Claude Code / Codex 相同的 OAuth 流程通过 provider 的**订阅**登录 —— 随后 `opfora` 将使用该 token 进行认证(Anthropic 可以直接使用 Claude Code 的公共客户端)。仅限 Direct-SDK 路径(`OPFORA_USE_LITELLM=false`)。完整步骤见
[docs/subscription-auth.md](docs/subscription-auth.md)。
### 自适应思考(exploit/postex)
在 `.env` 中设置 `OPFORA_THINKING_EFFORT`(`low | medium | high | xhigh | max`)
以便为两个重度推理的 subagent(Exploit、PostEx)在每一步提供自适应思考;未设置时(默认)则不带此功能运行。设置了级别后,
[`model_arg_for(...)`](src/agent/models.py) 会赋予这些 subagent 一个
启用了思考功能的 Anthropic 模型,其努力程度将被限制在层级支持的范围内
(Sonnet 最高为 `high`;Haiku / 非 Anthropic 层级保持普通模式)。思考机制使得
模型能够在行动之间进行审慎思考(重试前先诊断),而不是
条件反射式地触发下一个工具调用 —— 这种条件反射式的循环正是导致
昂贵重试绕路的原因。请从 `high` 开始并进行相应调整。
### 预算控制
`budget_guard` middleware 会追踪每次任务的支出,在 80% 时警告,在 95% 时硬性停止。请实事求是地在规范中设置 `budget_usd`:
- 在 `eco` 下解决单个 HTB 简单靶机:通常为 $0.50 – $2
- 在 `eco` 下解决 HTB 困难靶机:$3 – $10
- 在 `eco` 下解决 10 台主机的实验环境:$20 – $60
- 在 `max` 下进行外部任务:按范围而非按靶机做预算(对于相同的攻击面,通常是 `eco` 费率的 5-10 倍)
基准测试聚合器([`benchmark/aggregate.py`](benchmark/aggregate.py))会追踪多次运行中每台机器的中位数成本,因此任何偏移都会在趋势线中显现出来。
## 架构
```
┌────────── management-net ──────────┐
│ Next.js ─── FastAPI gateway │
│ │ │
│ ├── Postgres (episodes + checkpoints)
│ ├── Neo4j (derived graph)
│ ├── Redis (UI pubsub)
│ ├── ETL worker (log → graph)
│ ├── LiteLLM (model router)
│ └── MCP servers
└──────────────────┬─────────────────┘
│ docker socket
▼
┌──────────── ops-net (isolated) ────┐
│ kali-sandbox ── targets/VPN ── │
└────────────────────────────────────┘
```
沙箱仅通过 `episodes` MCP server 向管理平面回写数据。沙箱内部没有直接的数据库连接。
## Web 仪表板
CLI 是主要界面;仪表板用于观察已经在运行的任务。它是可选的 —— docker-compose 中的 `web` 服务位于一个 profile 之后,这样无头模式的运行就不需要支付构建成本。
### 启动它
```
# 启动 web dashboard(也会启动它所需的 gateway)
opfora web # add --build on first run
# 原始 compose 等效操作 — management stack 加上 web service
docker compose -f infra/docker-compose.yml --profile web up -d
# 或者,与 dev 目标一起
docker compose \
-f infra/docker-compose.yml \
-f infra/docker-compose.ops.yml \
--profile web --profile dev-targets up -d
```
然后打开 。
### 页面
| 路径 | 显示内容 |
|---|---|
| `/` | 索引 + 快捷链接 |
| `/engagements` | gateway 知道的每一个任务的列表(基于文件系统支持) |
| `/engagements/` | 详细视图 —— 实验进度、活跃 shell、发现结果(按严重程度着色)、完整的 episode 时间线 |
| `/engagements//shell` | 任务中任何 tmux 会话的只读流。轮询时间约为 1.5 秒 |
| `/engagements//graph` | Neo4j 衍生的投影图:主机、带版本号的服务、凭证、CVE |
| `/hitl` | 所有任务中待处理的 HITL 批准。可以接受/拒绝,并提供可选的指导意见 |
| `/stuck` | 待处理的 `StuckReport` 升级请求。输入提示,点击“Resume with this guidance” |
| `/skills` | 来自 `skill_proposer` middleware 提议的技能。每个草稿都有 Markdown 预览 |
仪表板刻意保持极简 —— 等宽字体、暗色主题,除了 Next.js 内置的之外没有客户端路由器。一切都通过 `NEXT_PUBLIC_GATEWAY_URL`(默认为 `http://localhost:8000`)与 FastAPI gateway 通信。
### 本地开发(迭代仪表板)
```
cd web
npm install
NEXT_PUBLIC_GATEWAY_URL=http://localhost:8000 npm run dev
```
`/engagements//shell` 和 `/hitl` 是轮询 gateway 的客户端组件;`/engagements/` 和 `/engagements//graph` 是在请求时获取数据的服务器端组件。如果页面是空白的,请检查 gateway 是否可达(`curl http://localhost:8000/healthz`)—— 仪表板页面会捕获获取失败并渲染为空状态,而不是抛出错误。
## 仓库布局
```
src/
├── agent/ # orchestrator, modes, subagents, middleware, prompts
├── mcp_servers/ # surface, exploit, postex, browser, shell, episodes, research, ad
├── etl/ # episode → Neo4j projection
├── gateway/ # FastAPI gateway (CLI + dashboard talk to this)
├── cli/ # Typer CLI (the `opfora` command)
└── schemas/ # pydantic models
skills/ # progressive-disclosure SKILL.md files
infra/ # docker compose, Dockerfiles, postgres init, litellm config
benchmark/ # ci_easy.py + nightly_full.py
tests/unit/ # RoE gate, schemas, middleware state
docs/examples/ # spec templates
```
## RoE 门控
这是设计中拒绝妥协的唯一一点。确定性的 middleware 会从每个工具调用的参数中提取主机/IP/URL,与 `ipaddress.ip_network` 匹配,阻止任何不在列表内的事物。模型绝不决定范围。
测试位于 [`tests/unit/test_roe_gate.py`](tests/unit/test_roe_gate.py)。
## 网络安全防护 / 验证计划
Anthropic 模型携带**实时的网络安全防护** —— 这是一个服务器端的分类器,
可以在遇到攻击安全内容(exploit 传递、反向 shell、RCE)时返回
`stop_reason: "refusal"` 以及 `stop_details.category: "cyber"`。在未经验证的组织上,这些拒绝是**间歇性的**:
一次运行可能成功落地 shell,随后却有约 10-15%后续 exploit 回合被拒绝,这表现为
空的“截断”回合,以及一个从不输出其结构化结果的 subagent。现在
CLI 会显式提示每一次拒绝(`⚠ model refused …`),而不是让它看起来像静默停滞。
这**不是** agent 可以通过 prompt 绕过的东西,我们也不尝试去绕过 ——
这是一种安全机制。对于授权的攻击性安全用途(渗透测试任务、CTF 实验环境、安全研究),合法的解锁方式是 Anthropic 的**网络验证计划**:申请将你的组织/密钥列入白名单。拒绝消息本身的
`explanation` 字段附带了申请表的链接,并且该计划记录在
。
在验证通过之前,预计 exploit/postex subagent 上会出现间歇性的拒绝。
## 开发
```
# 设置 venv (Python 3.11+)
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
# 单元测试(无需 Docker)
.venv/bin/pytest tests/unit/
# Lint
.venv/bin/ruff check src/
.venv/bin/mypy src/
```
对于完整的集成循环,你需要 Docker + VPN 配置。
## 技能编写
团队可以将本地的实战技术编码为位于 `skills///SKILL.md` 下的技能。
单数的 `skill` 命令用于本地开发;复数的 `skills`
命令用于审查 agent 提议的草稿。
```
opfora skill new surface/my-skill
opfora skill test surface/my-skill
opfora skill lint
opfora skill pack
```
`skill test` 和 `skill lint` 会验证必需的 frontmatter/部分、命令
安全标签、预期的输入/输出、工具引用、陈旧的 `skills/...`
路径,以及以未知二进制文件或工具开头的命令片段。`skill
pack` 会写入一个包含活跃技能的 `.tar.gz` 包,以便跨团队共享。
## 这不是什么
营销层面上的客观范围声明:
- **不是红队替代品。** 没有针对 EDR 的 OPSEC。没有社会工程学。没有闭合防御闭环。
- **卡死检测是一项 UX 特性,而不是一个 bug。** 约 20-30% 的靶机需要提示;agent 会升级发送一个结构化的 `StuckReport`,以便操作员可以用一个问题来解答,而不是看着它苦干两个小时。
- **技能循环是双向的** —— agent 提议新的实战技术,操作员审查并合并。没有任何东西会自动合并到活跃的技能树中。
## 许可证
[AGPL-3.0](LICENSE)。
标签:AI智能体, CISA项目, DLL 劫持, Web报告查看器, 大语言模型, 密码管理, 搜索引擎查询, 测试用例, 特征检测, 红队评估, 网络调试, 自动化, 请求拦截, 逆向工具