metatron-pentest-assistant

AI-powered penetration testing assistant using local LLM (metatron-qwen via Ollama) on Parrot OS Linux

22 stars

Best use case

metatron-pentest-assistant is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

AI-powered penetration testing assistant using local LLM (metatron-qwen via Ollama) on Parrot OS Linux

Teams using metatron-pentest-assistant should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/metatron-pentest-assistant/SKILL.md --create-dirs "https://raw.githubusercontent.com/Aradotso/trending-skills/main/skills/metatron-pentest-assistant/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/metatron-pentest-assistant/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How metatron-pentest-assistant Compares

Feature / Agentmetatron-pentest-assistantStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

AI-powered penetration testing assistant using local LLM (metatron-qwen via Ollama) on Parrot OS Linux

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# METATRON Penetration Testing Assistant

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

METATRON is a CLI-based AI penetration testing assistant that runs entirely locally — no cloud, no API keys. It orchestrates recon tools (nmap, whois, whatweb, curl, dig, nikto), feeds results to a locally running fine-tuned LLM (`metatron-qwen` via Ollama), and stores all findings in MariaDB with full scan history, vulnerability tracking, and PDF/HTML export.

---

## Architecture Overview

```
metatron.py     ← CLI entry point, main menu, scan orchestration
db.py           ← MariaDB CRUD (history, vulns, fixes, exploits, summary)
tools.py        ← Recon tool runners (nmap, whois, whatweb, curl, dig, nikto)
llm.py          ← Ollama interface, agentic loop, AI tool dispatch
search.py       ← DuckDuckGo search + CVE lookup (no API key)
Modelfile       ← Custom metatron-qwen model config
```

**Database spine:** every scan creates a `sl_no` in `history`; all other tables link via `sl_no`.

---

## Installation

### 1. Clone and set up Python environment

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

### 2. Install system recon tools

```bash
sudo apt install nmap whois whatweb curl dnsutils nikto
```

### 3. Install Ollama and pull base model

```bash
curl -fsSL https://ollama.com/install.sh | sh

# 8GB+ RAM:
ollama pull huihui_ai/qwen3.5-abliterated:9b

# <8GB RAM — use 4b and edit Modelfile FROM line accordingly:
ollama pull huihui_ai/qwen3.5-abliterated:4b
```

### 4. Build the custom metatron-qwen model

```bash
ollama create metatron-qwen -f Modelfile
ollama list   # verify metatron-qwen appears
```

**Modelfile** (the repo ships this — key parameters):
```
FROM huihui_ai/qwen3.5-abliterated:9b
PARAMETER num_ctx 16384
PARAMETER temperature 0.7
PARAMETER top_k 10
PARAMETER top_p 0.9
```

To use 4b instead, edit `Modelfile`:
```
FROM huihui_ai/qwen3.5-abliterated:4b
```
Then rebuild: `ollama create metatron-qwen -f Modelfile`

### 5. Set up MariaDB

```bash
sudo systemctl start mariadb
sudo systemctl enable mariadb
mysql -u root
```

```sql
CREATE DATABASE metatron;
CREATE USER 'metatron'@'localhost' IDENTIFIED BY '123';
GRANT ALL PRIVILEGES ON metatron.* TO 'metatron'@'localhost';
FLUSH PRIVILEGES;
EXIT;
```

Create all tables:
```bash
mysql -u metatron -p123 metatron < schema.sql
```

Or manually (paste from README schema block). The 5 tables:
- `history` — one row per scan session (spine)
- `vulnerabilities` — findings per session
- `fixes` — remediation per vulnerability
- `exploits_attempted` — exploit attempts per session
- `summary` — raw scan + full AI analysis dump

---

## Running METATRON

METATRON requires **two terminals**:

**Terminal 1 — Load model into memory:**
```bash
ollama run metatron-qwen
# Wait for >>> prompt before proceeding
```

**Terminal 2 — Launch the assistant:**
```bash
cd ~/METATRON
source venv/bin/activate
python metatron.py
```

### Main Menu Flow

```
[1] New Scan      → enter target IP/domain → select tools → AI analyzes → saved to DB
[2] View History  → browse past scans → view/edit/delete/export
[3] Exit
```

### New Scan — Tool Selection

```
[1] nmap
[2] whois
[3] whatweb
[4] curl headers
[5] dig DNS
[6] nikto
[a] Run all (except nikto)
[n] Run all + nikto (slow, thorough)
```

### Exporting Reports

From **View History → select scan → export**:
- `PDF` — professional vulnerability report
- `HTML` — browser-viewable report

---

## Code Examples

### Programmatically run a scan and save to DB (`db.py` patterns)

```python
import mysql.connector

def get_db_connection():
    return mysql.connector.connect(
        host="localhost",
        user="metatron",
        password="123",
        database="metatron"
    )

def create_scan_session(target: str) -> int:
    """Create a new history entry, return sl_no."""
    from datetime import datetime
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute(
        "INSERT INTO history (target, scan_date, status) VALUES (%s, %s, %s)",
        (target, datetime.now(), "active")
    )
    conn.commit()
    sl_no = cursor.lastrowid
    cursor.close()
    conn.close()
    return sl_no

def save_vulnerability(sl_no: int, vuln_name: str, severity: str,
                       port: str, service: str, description: str) -> int:
    """Save a vulnerability finding, return vuln id."""
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute(
        """INSERT INTO vulnerabilities
           (sl_no, vuln_name, severity, port, service, description)
           VALUES (%s, %s, %s, %s, %s, %s)""",
        (sl_no, vuln_name, severity, port, service, description)
    )
    conn.commit()
    vuln_id = cursor.lastrowid
    cursor.close()
    conn.close()
    return vuln_id

def save_fix(sl_no: int, vuln_id: int, fix_text: str, source: str = "AI"):
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute(
        "INSERT INTO fixes (sl_no, vuln_id, fix_text, source) VALUES (%s, %s, %s, %s)",
        (sl_no, vuln_id, fix_text, source)
    )
    conn.commit()
    cursor.close()
    conn.close()

def save_summary(sl_no: int, raw_scan: str, ai_analysis: str, risk_level: str):
    from datetime import datetime
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute(
        """INSERT INTO summary (sl_no, raw_scan, ai_analysis, risk_level, generated_at)
           VALUES (%s, %s, %s, %s, %s)""",
        (sl_no, raw_scan, ai_analysis, risk_level, datetime.now())
    )
    conn.commit()
    cursor.close()
    conn.close()

def get_scan_history():
    """Retrieve all scan sessions."""
    conn = get_db_connection()
    cursor = conn.cursor(dictionary=True)
    cursor.execute("SELECT * FROM history ORDER BY scan_date DESC")
    rows = cursor.fetchall()
    cursor.close()
    conn.close()
    return rows

def get_vulnerabilities_for_scan(sl_no: int):
    conn = get_db_connection()
    cursor = conn.cursor(dictionary=True)
    cursor.execute(
        "SELECT * FROM vulnerabilities WHERE sl_no = %s", (sl_no,)
    )
    rows = cursor.fetchall()
    cursor.close()
    conn.close()
    return rows
```

### Running recon tools (`tools.py` patterns)

```python
import subprocess

def run_nmap(target: str) -> str:
    """Run nmap service/version scan."""
    result = subprocess.run(
        ["nmap", "-sV", "-sC", "-T4", target],
        capture_output=True, text=True, timeout=120
    )
    return result.stdout + result.stderr

def run_whois(target: str) -> str:
    result = subprocess.run(
        ["whois", target],
        capture_output=True, text=True, timeout=30
    )
    return result.stdout

def run_whatweb(target: str) -> str:
    result = subprocess.run(
        ["whatweb", "-a", "3", target],
        capture_output=True, text=True, timeout=60
    )
    return result.stdout

def run_curl_headers(target: str) -> str:
    result = subprocess.run(
        ["curl", "-I", "-L", "--max-time", "15", target],
        capture_output=True, text=True, timeout=20
    )
    return result.stdout

def run_dig(target: str) -> str:
    result = subprocess.run(
        ["dig", target, "ANY"],
        capture_output=True, text=True, timeout=15
    )
    return result.stdout

def run_nikto(target: str) -> str:
    """Slow but thorough web scanner."""
    result = subprocess.run(
        ["nikto", "-h", target],
        capture_output=True, text=True, timeout=300
    )
    return result.stdout

def run_selected_tools(target: str, selections: list) -> dict:
    """
    selections: list of tool names, e.g. ['nmap', 'whois', 'dig']
    Returns dict of {tool_name: output}
    """
    tool_map = {
        'nmap': run_nmap,
        'whois': run_whois,
        'whatweb': run_whatweb,
        'curl': run_curl_headers,
        'dig': run_dig,
        'nikto': run_nikto,
    }
    results = {}
    for tool in selections:
        if tool in tool_map:
            print(f"[*] Running {tool} on {target}...")
            try:
                results[tool] = tool_map[tool](target)
            except subprocess.TimeoutExpired:
                results[tool] = f"[TIMEOUT] {tool} timed out"
            except Exception as e:
                results[tool] = f"[ERROR] {tool}: {e}"
    return results
```

### Querying Ollama LLM (`llm.py` patterns)

```python
import requests
import json

OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL_NAME = "metatron-qwen"

def query_llm(prompt: str, stream: bool = True) -> str:
    """Send prompt to metatron-qwen, return full response."""
    payload = {
        "model": MODEL_NAME,
        "prompt": prompt,
        "stream": stream
    }
    response = requests.post(OLLAMA_URL, json=payload, stream=stream)
    
    if not stream:
        return response.json().get("response", "")
    
    full_response = ""
    for line in response.iter_lines():
        if line:
            chunk = json.loads(line)
            token = chunk.get("response", "")
            print(token, end="", flush=True)
            full_response += token
            if chunk.get("done"):
                break
    print()
    return full_response

def build_pentest_prompt(target: str, scan_results: dict) -> str:
    """Build the analysis prompt from scan results."""
    combined = "\n\n".join(
        f"=== {tool.upper()} ===\n{output}"
        for tool, output in scan_results.items()
    )
    return f"""You are an expert penetration tester analyzing scan results for: {target}

SCAN RESULTS:
{combined}

Provide a structured analysis covering:
1. VULNERABILITIES FOUND — name, severity (Critical/High/Medium/Low), port, service, description
2. EXPLOIT SUGGESTIONS — specific tools or techniques for each vulnerability
3. RECOMMENDED FIXES — actionable remediation steps
4. OVERALL RISK LEVEL — Critical / High / Medium / Low

Format vulnerabilities as:
VULN: <name> | SEVERITY: <level> | PORT: <port> | SERVICE: <service>
DESC: <description>
FIX: <remediation>
"""

def analyze_target(target: str, scan_results: dict) -> str:
    prompt = build_pentest_prompt(target, scan_results)
    print("\n[🤖] metatron-qwen analyzing...\n")
    return query_llm(prompt)
```

### DuckDuckGo search and CVE lookup (`search.py` patterns)

```python
from duckduckgo_search import DDGS

def search_exploits(query: str, max_results: int = 5) -> list:
    """Search DuckDuckGo for exploit info — no API key needed."""
    with DDGS() as ddgs:
        results = list(ddgs.text(query, max_results=max_results))
    return results

def lookup_cve(cve_id: str) -> list:
    """Look up a CVE identifier."""
    query = f"{cve_id} vulnerability exploit details"
    return search_exploits(query)

def search_service_vulns(service: str, version: str) -> list:
    query = f"{service} {version} known vulnerabilities CVE exploit"
    return search_exploits(query)

# Usage example:
# results = lookup_cve("CVE-2021-44228")
# results = search_service_vulns("Apache", "2.4.49")
```

### Full scan pipeline (end-to-end)

```python
from tools import run_selected_tools
from llm import analyze_target
from db import (create_scan_session, save_vulnerability,
                save_fix, save_summary)

def run_full_scan(target: str, tools: list = None):
    if tools is None:
        tools = ['nmap', 'whois', 'whatweb', 'curl', 'dig']
    
    # 1. Create DB session
    sl_no = create_scan_session(target)
    print(f"[+] Scan session #{sl_no} created for {target}")
    
    # 2. Run recon
    scan_results = run_selected_tools(target, tools)
    raw_scan = "\n\n".join(f"{k}:\n{v}" for k, v in scan_results.items())
    
    # 3. AI analysis
    ai_output = analyze_target(target, scan_results)
    
    # 4. Parse and save (simplified — real parser in llm.py)
    # Save summary
    save_summary(sl_no, raw_scan, ai_output, risk_level="High")
    
    print(f"\n[✓] Results saved to database (sl_no={sl_no})")
    return sl_no, ai_output

# Run it:
# sl_no, analysis = run_full_scan("192.168.1.1", ['nmap', 'whois'])
```

---

## Common Patterns

### Check if Ollama model is running before scan

```python
import requests

def check_ollama_ready(model: str = "metatron-qwen") -> bool:
    try:
        resp = requests.get("http://localhost:11434/api/tags", timeout=5)
        models = [m["name"] for m in resp.json().get("models", [])]
        return any(model in m for m in models)
    except Exception:
        return False

if not check_ollama_ready():
    print("[!] metatron-qwen not found. Run: ollama run metatron-qwen")
    exit(1)
```

### Query scan history

```python
from db import get_db_connection

def get_full_scan_report(sl_no: int) -> dict:
    conn = get_db_connection()
    cursor = conn.cursor(dictionary=True)
    
    cursor.execute("SELECT * FROM history WHERE sl_no = %s", (sl_no,))
    history = cursor.fetchone()
    
    cursor.execute("SELECT * FROM vulnerabilities WHERE sl_no = %s", (sl_no,))
    vulns = cursor.fetchall()
    
    cursor.execute("SELECT * FROM summary WHERE sl_no = %s", (sl_no,))
    summary = cursor.fetchone()
    
    cursor.close()
    conn.close()
    
    return {"history": history, "vulnerabilities": vulns, "summary": summary}
```

### Add a custom recon tool

```python
# In tools.py — add your tool function:
def run_gobuster(target: str, wordlist: str = "/usr/share/wordlists/dirb/common.txt") -> str:
    result = subprocess.run(
        ["gobuster", "dir", "-u", f"http://{target}", "-w", wordlist],
        capture_output=True, text=True, timeout=180
    )
    return result.stdout

# Register it in the tool_map in run_selected_tools():
tool_map['gobuster'] = run_gobuster
```

---

## Troubleshooting

### `metatron-qwen` not found / connection refused
```bash
# Terminal 1: ensure model is loaded
ollama run metatron-qwen
# Should show >>> prompt

# Verify Ollama API is reachable
curl http://localhost:11434/api/tags
```

### Out of memory when running 9b model
```bash
# Switch to 4b: edit Modelfile first line:
# FROM huihui_ai/qwen3.5-abliterated:4b
ollama create metatron-qwen -f Modelfile
```

### MariaDB connection error
```bash
sudo systemctl status mariadb
sudo systemctl start mariadb

# Verify credentials work:
mysql -u metatron -p123 metatron -e "SHOW TABLES;"
```

### `mysql.connector` not found
```bash
source venv/bin/activate
pip install mysql-connector-python
```

### nmap requires root for SYN scan
```bash
sudo nmap -sV -sC -T4 <target>
# Or use TCP connect scan (no root needed):
nmap -sT -sV <target>
```

### Nikto timeout
Nikto is slow by design. Either use `[a]` (all without nikto) or increase the subprocess timeout in `tools.py`:
```python
result = subprocess.run(["nikto", "-h", target],
                        capture_output=True, text=True,
                        timeout=600)  # 10 minutes
```

### Slow AI responses
The 9b model needs time to load. If response is slow after the first query, it's still loading. Subsequent queries will be faster. Ensure no other GPU/memory-heavy processes are running.

---

## Configuration Reference

| Setting | Location | Default | Notes |
|---|---|---|---|
| DB host | `db.py` | `localhost` | Change for remote DB |
| DB user | `db.py` | `metatron` | Match SQL user created |
| DB password | `db.py` | `123` | Change in production |
| DB name | `db.py` | `metatron` | |
| Ollama URL | `llm.py` | `http://localhost:11434` | |
| Model name | `llm.py` | `metatron-qwen` | Must match `ollama list` |
| Context window | `Modelfile` | `16384` | Increase for large scans |
| Temperature | `Modelfile` | `0.7` | Lower = more deterministic |

> **Security note:** For production use, replace the hardcoded DB password with an environment variable: `os.environ.get("METATRON_DB_PASSWORD", "123")`

---

## Legal Disclaimer

METATRON is for **educational purposes and authorized penetration testing only**. Only scan systems you own or have explicit written permission to test. Unauthorized scanning is illegal.

Related Skills

shannon-ai-pentester

22
from Aradotso/trending-skills

Autonomous white-box AI pentester for web applications and APIs using source code analysis and live exploit execution

picoclaw-ai-assistant

22
from Aradotso/trending-skills

Ultra-lightweight AI assistant in Go that runs on $10 hardware with <10MB RAM, supporting multiple LLM providers, tools, and single-binary deployment across RISC-V, ARM, MIPS, and x86.

gstack-workflow-assistant

22
from Aradotso/trending-skills

Team of specialist AI workflows for Claude Code with CEO review, engineering planning, code review, shipping, QA testing, and browser automation

copaw-ai-assistant

22
from Aradotso/trending-skills

Personal AI assistant framework supporting multiple chat channels (DingTalk, Feishu, QQ, Discord, etc.) with extensible skills, local/cloud deployment, and cron scheduling.

cairn-ai-pentest

22
from Aradotso/trending-skills

AI-automated penetration testing and general problem-solving system that achieved unique AK (All Killed) in Tencent Cloud Hackathon intelligent penetration challenge

```markdown

22
from Aradotso/trending-skills

---

zeroboot-vm-sandbox

22
from Aradotso/trending-skills

Sub-millisecond VM sandboxes for AI agents using copy-on-write KVM forking via Zeroboot

yourvpndead-vpn-detection

22
from Aradotso/trending-skills

Android app that detects VPN/proxy servers (VLESS/xray/sing-box) via local SOCKS5 vulnerability, exposing exit IPs and server configs without root

xata-postgres-platform

22
from Aradotso/trending-skills

Expert skill for Xata open-source cloud-native Postgres platform with copy-on-write branching, scale-to-zero, and Kubernetes deployment

x-mentor-skill-nuwa

22
from Aradotso/trending-skills

AI-powered X (Twitter) content strategy skill that distills methodologies from 6 top creators + open-source algorithm data into actionable writing, growth, and monetization guidance.

wx-favorites-report

22
from Aradotso/trending-skills

End-to-end pipeline to extract, decrypt, and visualize WeChat Mac favorites from encrypted SQLite DB into an interactive HTML report.

wterm-web-terminal

22
from Aradotso/trending-skills

Web terminal emulator with Zig/WASM core, DOM rendering, and React/vanilla JS bindings