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://img.shields.io/badge/tests-54%20passed-brightgreen.svg)](tests/)
[![CI](https://img.shields.io/badge/CI-GitHub%20Actions-blue.svg)](.github/workflows/tests.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

---

## ๆ•ˆๆžœๆผ”็คบ

็ป™ไธ€ไธช็›ฎๆ ‡๏ผŒAgent ่‡ชๅทฑ่ง„ๅˆ’ใ€่‡ชๅทฑๅ†ณๅฎšๆฏไธ€ๆญฅๅšไป€ไนˆ๏ผš

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

```
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 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
```

`--deny-private` ๆ‹ฆๆˆช `127.`ใ€`10.`ใ€`172.16-31.`ใ€`192.168.`ใ€`169.254.`โ€”โ€”่ฟ™ๆก่ง„ๅˆ™ๅœจๆ‰ซๅ†…็ฝ‘ๆ—ถ่ฆๆณจๆ„ๅ…ณๆމใ€‚

### 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/<your-username>/secagent.git
cd secagent
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

### ้…็ฝฎ

```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/          # 54 ไธชๆต‹่ฏ•
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 ่ง„ๅˆ’ๅฑ‚