Skip to main content
Glama
README.md
# SecAgent 🔐

> 基于 **MCP (Model Context Protocol)** 的自䞻安党评䌰 Agent —— 把真实的 Kali 安党工具封装成 MCP Server让 LLM **星匏规划**、并/䞲行调甚工具、分层记忆发现、映射 MITRE ATT&CK、自劚生成报告。
>
> **安党䌘先**䟵入匏操䜜默讀需芁人工批准工具调甚党皋审计支持目标癜名单䞎私眑访问管控。

[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
[![MCP](https://img.shields.io/badge/MCP-1.9.4-green.svg)](https://modelcontextprotocol.io/)
[![tests](https://github.com/RicardoMLu777/secagent/actions/workflows/tests.yml/badge.svg)](https://github.com/RicardoMLu777/secagent/actions/workflows/tests.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

> [!WARNING]
> **仅限授权测试。** SecAgent 䌚执行真实的端口扫描、目圕爆砎䞎 SQL 泚入检测。请只圚自有资产、持有乊面授权的目标或本地靶场䞭䜿甚。未授权扫描圚倚数叞法蟖区属于违法行䞺。诊见文末 [Disclaimer](#disclaimer)。

---

## 效果挔瀺

给䞀䞪目标Agent 自己规划、自己决定每䞀步做什么

```bash
$ python secagent.py --target 192.168.1.10 --report out/report.md --policy allow
```

> 这里甚 `--policy allow` 是因䞺挔瀺环境是明确授权的本地靶场。默讀暡匏是 `ask`䌚对每䞀步䟵入匏操䜜匹出人工确讀——见䞋方[安党暡型](#安党暡型)。

```
╭────────────────────────────── plan ──────────────────────────────╮
│ Plan for 192.168.1.10:                                           │
│   ○ 1. Probe the target to confirm it is live (http_probe)        │
│   ○ 2. Inspect HTTP security headers (check_security_headers)     │
│   ○ 3. Review robots.txt for hidden paths (check_robots)          │
│   ○ 4. Enumerate sensitive directories (ffuf_dirs) [intrusive]    │
│   ○ 5. Port/service scan (nmap_scan) [intrusive]                  │
│   ○ 6. Consolidate into a risk assessment                         │
╰──────────────────────────────────────────────────────────────────╯

step 1 · reasoning
  → nmap_server__nmap_scan {"target": "192.168.1.10"}
     ✓ 22/tcp open ssh OpenSSH 8.2p1 / 80/tcp open http nginx 1.18.0

step 2 · reasoning
  running 3 tool calls in parallel          ← 并行执行
  → httpx_server__http_probe {"url": "http://192.168.1.10"}
  → httpx_server__check_security_headers {"url": "http://192.168.1.10"}
  → httpx_server__check_robots {"url": "http://192.168.1.10"}
     ✓ status 200, server nginx/1.18.0
     ✓ missing: content-security-policy, x-frame-options (4/6)
     ✓ interesting: /admin, /backup

step 3 · reasoning
  → ffuf_server__ffuf_dirs {"url": "http://192.168.1.10/FUZZ"}
     ✓ 7 hits: /admin (301), /backup.zip (200), ...

ATT&CK: T1046, T1592, T1083
report written: out/report.md
```

生成的报告包含 **执行计划 / ATT&CK 映射 / 配眮匱点 / Agent 结论**

```markdown
# SecAgent Assessment Report

**Steps used:** 5   **Tool calls:** 11

## Summary
- Open ports: 22, 80
- Services: ssh, nginx 1.18.0
- Missing security headers: content-security-policy, x-frame-options

## Plan execution
| # | Task | Status | Intrusive |
|---|------|--------|-----------|
| 1 | Probe the target | done | no |
...

## MITRE ATT&CK techniques observed
| ID | Technique | Tactic |
|----|-----------|--------|
| T1046 | Network Service Discovery | Discovery |
| T1592 | Gather Victim Host Information | Reconnaissance |
| T1083 | File and Directory Discovery | Discovery |

## Configuration weaknesses
- **content-security-policy** — No CSP: reflected XSS has no browser-level mitigation.

## Agent report
### Findings
...
```

---

## 架构

```
┌──────────────────────────────────────────────────────────┐
│                      SecAgent                            │
│                                                          │
│   ┌──────────────┐        ┌──────────────────────────┐   │
│   │   Planner    │───────▶│   ReAct Execution Loop   │   │
│   │              │        │                          │   │
│   │ 1. plan()    │        │  think → call → observe  │   │
│   │ 2. revise()  │◀───3────│  (parallel tool calls)   │   │
│   └──────────────┘  steps └────────────┬─────────────┘   │
│                                        │                 │
│                          ┌─────────────┮─────────────┐   │
│                          │      Tiered Memory        │   │
│                          │  raw observations +       │   │
│                          │  distilled findings       │   │
│                          └───────────────────────────┘   │
│                                        │                 │
│            ┌─────────────┮─────────────┐                 │
│            │  Policy Gate              │                 │
│            │  deny / ask / allow       │                 │
│            └─────────────┬─────────────┘                 │
│            ┌─────────────┮─────────────┐                 │
│            │  ATT&CK Mapper + Report   │                 │
│            │  + SQLite History         │                 │
│            └───────────────────────────┘                 │
└──────────────────────────┬───────────────────────────────┘
                           │ MCP protocol (stdio)
     ┌────────────┬────────┎───────┬────────────┐
     ▌            ▌                ▌            ▌
┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐
│  nmap    │ │  httpx   │ │  sqlmap   │ │   ffuf   │
│ 2 tools  │ │ 3 tools  │ │  3 tools  │ │  1 tool  │
└────┬─────┘ └────┬─────┘ └─────┬─────┘ └────┬─────┘
     ▌            ▌             ▌            ▌
   nmap       httpx+re     sqlmap       ffuf
```

### 暡块职莣

| 暡块 | 文件 | 职莣 |
|------|------|------|
| **Planner** | `agent/planner.py` | Plan-and-Execute䞀次性分解目标 + 每 3 步重规划 |
| **ReAct Core** | `agent/core.py` | 掚理→调甚工具→观察埪环支持并行工具调甚 |
| **MCP Manager** | `agent/mcp_client.py` | MCP Server 生呜呚期、工具发现、呜名空闎隔犻 |
| **Memory** | `agent/memory.py` | 双层记忆原始观察有预算+ 结构化发现 |
| **ATT&CK Mapper** | `agent/attack_map.py` | 发现 → MITRE ATT&CK 技术 ID + 配眮匱点诎明 |
| **Policy** | `agent/policy.py` | 工具分级、目标癜名单、人工批准闚控 |
| **Store** | `agent/store.py` | SQLite 持久化 + 历次扫描对比 |
| **Retry** | `agent/retry.py` | 瞬时错误指数退避重试 |
| **Report** | `agent/report.py` | 枲染 Markdown / JSON 报告 |

---

## 安党暡型

自䞻 Agent 执行真实的攻击工具最倧的风险是它自己决定去做什么。SecAgent 甚䞉层纊束解决这䞪问题。

### 1. 工具分级 — 䟵入匏操䜜默讀需芁人工批准

```python
PASSIVE_TOOLS   = {"http_probe", "check_security_headers", "check_robots"}
INTRUSIVE_TOOLS = {"nmap_scan", "nmap_vuln_scan", "sqlmap_scan",
                   "sqlmap_dump", "ffuf_dirs", ...}
```

```bash
$ python secagent.py --target 192.168.1.10 --policy ask

step 2 · reasoning
  → sqlmap_server__sqlmap_scan {"url": "http://192.168.1.10/news.php?id=1"}

╭──────────────────── ⚠ approval required ────────────────────╮
│ sqlmap_scan                                                 │
│ {"url": "http://192.168.1.10/news.php?id=1"}                │
│                                                             │
│ 'sqlmap_scan' sends intrusive traffic and needs approval    │
╰─────────────────────────────────────────────────────────────╯
  Allow this action? [y/N]
```

䞉种暡匏

| 暡匏 | 被劚工具 | 䟵入工具 | 适甚场景 |
|------|---------|---------|---------|
| `passive` | ✅ 自劚攟行 | ❌ 䞀埋拒绝 | 生产环境的只读䟊察 |
| `ask`默讀 | ✅ 自劚攟行 | ⚠ 匹窗等人工确讀 | 垞规林透测试 |
| `allow` | ✅ | ✅ | 明确授权的靶场 / 红队挔练 |

**未配眮批准人时默讀拒绝**fail closed——这是刻意的避免"配眮挏了"变成"党攟行"。

被拒绝的调甚䌚以结构化 JSON 反銈给暡型并附䞊指匕

```json
{
  "blocked": true,
  "tool": "sqlmap_server__sqlmap_scan",
  "reason": "'sqlmap_scan' sends intrusive traffic and needs approval",
  "guidance": "This action was blocked by the engagement policy. Do not retry it."
}
```

暡型拿到这䞪䞍䌚死埪环重试而是蜬向被劚手段或圚报告里诎明需芁授权。

### 2. 目标管控 — 癜名单 + 私眑保技

```bash
# 只允讞指定域名越界䞀埋拒绝
python secagent.py --target x --scope 'example\.com' --scope 'testsite\.org'

# 犁止访问回环/内眑地址防 SSRF 匏的误操䜜
python secagent.py --target x --deny-private

# 圻底犁甚某䞪工具
python secagent.py --target x --deny-tools sqlmap_dump ffuf_dirs
```

`--scope` 按 **hostname 党匹配**䞍是子䞲匹配`example\.com` 䞍䌚攟行 `example.com.attacker.net` 或 `evilexample.com`。芁攟行子域需星匏写出 `--scope '.*\.example\.com'`。

`--deny-private` 拊截 `127.0.0.0/8`、`10.0.0.0/8`、`172.16.0.0/12`、`192.168.0.0/16`、`169.254.0.0/16` 侎 `::1`。刀断䟝据是 IP 字面量因歀 `10.example.com` 这类域名䞍䌚被误䌀。这条规则圚扫内眑时芁泚意关掉。

### 3. 党铟路审计

每次工具调甚郜记圕决策䞎理由

```bash
$ python secagent.py --target x --policy ask --json | jq '.tool_audit'
[
  {"step": 1, "tool": "httpx_server__http_probe",
   "decision": "allow", "reason": "passive reconnaissance"},
  {"step": 2, "tool": "sqlmap_server__sqlmap_scan",
   "decision": "ask-denied",
   "reason": "'sqlmap_scan' sends intrusive traffic and needs approval..."}
]
```

审计日志同时萜库可以回溯"这次评䌰到底跑过什么、谁批的"。

---

## 快速匀始

### 环境芁求

- Python 3.11+
- Linuxnmap / sqlmap / ffuf 需芁猺倱的工具䌚被自劚跳过
- 䞀䞪 OpenAI 兌容的 LLM API

```bash
sudo apt install nmap sqlmap ffuf
```

### 安装

```bash
git clone https://github.com/RicardoMLu777/secagent.git
cd secagent
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

### 甹 Docker 跑䞍想装工具铟时甚这䞪

镜像里已经垊奜 nmap / sqlmap / ffuf宿䞻机䞍需芁任䜕安党工具

```bash
docker build -t secagent .

# Linux--network host 让扫描胜到蟟䜠的靶场眑段
docker run --rm --network host --env-file .env secagent --target 192.168.1.10

# 想留䞀仜报告出来
docker run --rm --network host --env-file .env -v "$PWD/out:/app/out" \
  secagent --target 192.168.1.10 --report out/report.md
```

镜像内以非 root 甚户运行。`--deny-private` 默讀**关闭**扫内眑靶场䞍甚额倖倄理。

### 配眮

```bash
cp .env.example .env
# 猖蟑 .env填入 DEEPSEEK_API_KEY
```

兌容任意 OpenAI 协议端点

```bash
SECAGENT_BASE_URL=https://api.deepseek.com/v1   # DeepSeek
SECAGENT_BASE_URL=https://api.openai.com/v1     # OpenAI
SECAGENT_BASE_URL=http://localhost:11434/v1     # Ollama 本地
```

### 运行

```bash
# 给目标自劚规划
python secagent.py --target 192.168.1.10

# 自然语蚀目标
python secagent.py "审计 example.com 的安党倎配眮和敏感路埄"

# 蟓出报告文件
python secagent.py --target example.com --report out/example.md

# 加蜜党郚 MCP Server
python secagent.py --target x --all-servers

# 关闭规划/并行对比实验甚
python secagent.py --target x --no-planner --no-parallel

# JSON 蟓出䟿于集成到 CI
python secagent.py --target x --json
```

---

## MCP 工具枅单

### `nmap_server.py`

| 工具 | 诎明 | ATT&CK |
|------|------|--------|
| `nmap_scan` | 端口扫描 + 服务版本识别 | T1046 |
| `nmap_vuln_scan` | NSE 挏掞脚本扫描 | T1595 |

### `httpx_server.py`

| 工具 | 诎明 | ATT&CK |
|------|------|--------|
| `http_probe` | 状态码、响应倎、标题、技术指纹 | T1592 |
| `check_security_headers` | 6 䞪关键安党倎猺倱审计 | — |
| `check_robots` | robots.txt 解析标记敏感路埄 | T1590 |

### `sqlmap_server.py`

| 工具 | 诎明 | ATT&CK |
|------|------|--------|
| `sqlmap_scan` | SQL 泚入检测 | T1190 |
| `sqlmap_tables` | 枚䞟数据库衚 | — |
| `sqlmap_dump` | 富出衚数据需星匏指定库衚 | T1213 |

### `ffuf_server.py`

| 工具 | 诎明 | ATT&CK |
|------|------|--------|
| `ffuf_dirs` | 目圕/文件爆砎自垊迷䜠字兞 | T1083 |

---

## 讟计芁点

### 1. 星匏规划 vs 纯 ReAct

纯 ReAct 的问题暡型蟹想蟹做容易圚细节里打蜬。SecAgent 拆成䞀阶段

```python
# 阶段䞀无工具环境䞋的纯规划暡型䞍䌚忍䞍䜏盎接匀火
plan = planner.plan(objective, available_tools)

# 阶段二垊计划执行
result = await agent.run(objective, plan=plan)

# 阶段䞉每 3 步让 planner 倍栞可 continue / revise / done
action, plan = planner.revise(objective, plan, findings_so_far)
```

规划调甚**䞍挂工具**这是关键——暡型只胜思考 `做什么`䞍胜盎接 `做`。

### 2. 并行工具调甚

暡型䞀蜮返回倚䞪 tool_calls 时甚 `asyncio.gather` 并发执行

```python
if self.parallel and len(parsed) > 1:
    results = await asyncio.gather(
        *(mcp.call(tc.function.name, args) for tc, args in parsed),
        return_exceptions=True,
    )
```

无䟝赖的调甚http_probe + check_headers + check_robots䞀蜮搞定实测省 40%+ 时闎。

### 3. 双层记忆

倧倚数 Agent 把党郚工具蟓出塞进 context埈快就爆了

```python
# 第䞀层原始观察有长床预算超长截断
observations = [Observation(step=1, tool="nmap_scan", result="...")]

# 第二层结构化事实甚正则从原始蟓出抜取
findings = {
    "open_ports": {"22", "80"},
    "services": {"ssh", "nginx 1.18.0"},
    "missing_headers": {"content-security-policy"},
    "interesting_paths": {"/admin", "/backup"},
    "flags": set(),
}
```

每蜮只泚入 **摘芁 + 最近 2 条观察**而非党量历史。

### 4. 工具呜名空闎

倚䞪 Server 可胜有同名工具统䞀加前猀

```
nmap_server__nmap_scan
httpx_server__http_probe
```

### 5. 安党加固

- 所有系统呜什甚 **list 圢匏**调甚䞍经 shell并圚参数层面过滀元字笊
  ```python
  if re.search(r"[;&|`$><\n]", target):
      return "error: invalid characters in target"
  ```
- `sqlmap_dump` 的库名/衚名/列名党郚正则癜名单校验
- System prompt 明确 Rules of Engagement只对授权目标操䜜、䌘先非䟵入、䞍䌪造蟓出

---

## 历史䞎对比

每次评䌰自劚萜库SQLite默讀 `~/.secagent/engagements.db`可以回溯和对比同䞀䞪目标的历次扫描。

```bash
# 查看历史
$ python secagent.py history --target example.com

         Engagement history
┏━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ ID ┃ Target     ┃ Started             ┃ Steps ┃ Calls ┃ Flags              ┃
┡━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ 7  │ example.com│ 2026-09-17T14:20:11 │ 6     │ 14    │ flag{new_finding}  │
│ 3  │ example.com│ 2026-09-10T09:02:44 │ 5     │ 11    │ -                  │
└────┮────────────┮─────────────────────┮───────┮───────┮────────────────────┘

# 对比䞀次扫描
$ python secagent.py diff 3 7

example.com  #3 (2026-09-10T09:02:44) → #7 (2026-09-17T14:20:11)
  + ports: 8080
  - headers: x-frame-options
  + flags: flag{new_finding}
  = services: no change (4)

# 所有评䌰过的目标
$ python secagent.py targets
```

对比绎床匀攟端口、服务版本、猺倱的安党倎、敏感路埄、Flag。

关掉持久化甚 `--no-store`或指定库路埄 `--db /path/to.db`。

---

## 容错

工具调甚遇到眑络抖劚、超时、5xx 时自劚重试指数退避 + 抖劚最倚 3 次

```python
TRANSIENT_MARKERS = (
    "timeout", "connection refused", "connection reset",
    "502 bad gateway", "503 service unavailable", "rate limit", ...
)
```

只有**瞬时错误**才重试——遇到"目标䞍可蟟"这类确定性倱莥盎接返回䞍做无谓等埅。重试过皋䌚打印 `↻ retry 1` 让䜿甚者看到。

调敎次数`retry_attempts=5`构造参数。

---

## CI

掚送到 `main` 自劚觊发 GitHub Actions

```yaml
matrix: python 3.11 / 3.12 / 3.13
  - pytest tests/          # 单元测试
lint:
  - ruff check .           # E/F/W 规则
  - compileall             # 字节码猖译检查
```

CI 曟经抓到过䞀䞪真 bug`ffuf_server.py` 里 `ext` 变量名写错应䞺 `exts`静态检查盎接暎露。这就是把 lint 攟进 CI 的价倌。

---

## 扩展新的 MCP Server

圚 `mcp_servers/` 䞋按暡板新建即可运行时䌚自劚发现

```python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import TextContent, Tool

app = Server("myserver")

@app.list_tools()
async def list_tools() -> list[Tool]:
    return [Tool(
        name="my_tool",
        description="What this tool does",
        inputSchema={"type": "object", "properties": {...}, "required": [...]},
    )]

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    return [TextContent(type="text", text=json.dumps(result))]

async def main():
    async with stdio_server() as (r, w):
        await app.run(r, w, app.create_initialization_options())
```

```bash
python secagent.py --target X --servers nmap_server.py myserver.py
```

**掚荐扩展方向**`nuclei_server.py`、`nikto_server.py`、`gobuster_server.py`、`hydra_server.py`

---

## 项目结构

```
secagent/
├── agent/
│   ├── __init__.py
│   ├── core.py           # ReAct 䞻埪环 + 并行执行
│   ├── planner.py        # Plan-and-Execute 规划层
│   ├── mcp_client.py     # MCP Server 生呜呚期䞎工具发现
│   ├── memory.py         # 双层记忆原始观察 + 结构化发现
│   ├── attack_map.py     # 发现 → MITRE ATT&CK 映射
│   ├── policy.py         # 工具分级、癜名单、审批闚控
│   ├── store.py          # SQLite 持久化䞎历次对比
│   ├── retry.py          # 瞬时错误指数退避
│   └── report.py         # Markdown / JSON 报告枲染
├── mcp_servers/
│   ├── nmap_server.py    # 端口扫描 / NSE
│   ├── httpx_server.py   # HTTP 探测 / 安党倎 / robots
│   ├── sqlmap_server.py  # 泚入检测 / 库衚枚䞟 / 富出
│   └── ffuf_server.py    # 目圕爆砎
├── tests/                # 单元测试
├── .github/workflows/tests.yml
├── secagent.py           # CLI 入口
├── requirements.txt
├── .env.example
├── Dockerfile
├── LICENSE
└── README.md
```

---

## 安党修倍记圕

记圕本项目自己被审计出来的问题及修倍方匏。

### `--scope` 癜名单可被绕过已修倍

早期实现甚 `re.search(pattern, target)` 对敎䞪目标字笊䞲做子䞲匹配`--scope 'example\.com'` 䌚攟行以䞋目标

| 目标 | 䞺什么胜绕过 |
|---|---|
| `http://example.com.attacker.net` | 授权域名䜜䞺攻击者域名的前猀出现 |
| `http://evilexample.com` | 授权域名䜜䞺子䞲出现 |
| `http://example.com@attacker.net` | `@` 前是 userinfo真实 host 是 `attacker.net` |
| `https://attacker.net/?next=example.com` | 子䞲出现圚 query 里 |

现圚改䞺先 `urlsplit` 提取 hostname再 `re.fullmatch` 党匹配回園测试见 `tests/test_policy_scope.py`。

同䞀次审计还发现 `--deny-private` 甚字笊䞲正则刀断䌚把 `10.example.com`、`notlocalhost.com` 误刀䞺私眑地址已改甚 `ipaddress` 刀断 IP 字面量。

> 教训**校验点选错䜍眮比䞍做校验曎危险**——它给䜠的是虚假的安党感。

---

## 已知局限

诚实记圕蟹界䞍做过床承诺。

1. **䞍解析 DNS** —— `--deny-private` 只刀断 IP 字面量。若某䞪域名解析到 `192.168.x.x`DNS rebinding 䞀类手法字笊䞲层拊䞍䜏。正确做法是圚建立连接前对解析结果再校验䞀次圓前未实现。
2. **工具蟓出解析䟝赖正则** —— `memory.py` 从原始蟓出䞭抜取端口、服务、路埄等事实。工具版本升级改变蟓出栌匏时抜取可胜倱莥降级策略是保留原始观察、攟匃结构化字段䞍䞭断执行。
3. **未对抗 prompt injection** —— 劂果被扫描目标返回的 banner 或页面内容里嵌入了指什暡型的规划可胜被污染。目前䟝赖 policy 层兜底越界目标䌚被拒绝䜆没有蟓入䟧的隔犻䞎净化。
4. **单机单进皋** —— 没有任务队列、没有并发目标隔犻。定䜍是单次授权评䌰的蟅助工具䞍是扫描平台。
5. **规划莚量受暡型胜力圱响** —— 换甚小暡型时计划可胜过于保守或重倍。`--no-planner` 可以退回纯 ReAct 做对比实验。

---

## 后续计划

- [ ] 解析后 IP 校验堵䜏 DNS rebinding 路埄
- [ ] 目标响应内容䞎指什䞊䞋文隔犻做 prompt injection 防技
- [ ] 新增 `nuclei_server.py`暡板化挏掞检测
- [ ] 报告支持 SARIF 蟓出䟿于接入 CI
- [ ] 附䞀仜本地靶场DVWA / OWASP Juice Shop的端到端倍现指南

---

## Disclaimer

本项目仅甚于**获埗明确授权的安党测试**、教孊䞎安党研究。

䜿甚者须确保

- 对目标拥有所有权或持有乊面的林透测试授权
- 遵守所圚地法埋法规——圚䞭囜境内未经授权对计算机信息系统进行扫描、探测或获取数据可胜违反《䞭华人民共和囜眑络安党法》及《刑法》第二癟八十五条
- 䞍将本工具甚于任䜕未授权目标。

工具内眮的审批闚控、目标癜名单䞎私眑管控是**降䜎误操䜜风险的讟计**䞍构成䜿甚授权的替代。䜜者䞍对任䜕滥甚行䞺及由歀产生的后果承担莣任。

圚本地靶场练习氞远是正确的第䞀步。