mirror of
https://github.com/GH05TCREW/pentestagent.git
synced 2026-03-07 22:33:38 +00:00
docker: improve safety, UX, and Metasploit MCP defaults
Why: - Persist artifacts to /app/loot so container outputs remain available when mounted. - Avoid mandatory host chown; make chown opt-in via CHOWN_ON_START to prevent accidental ownership changes. - Bind msfrpcd to 127.0.0.1 by default and add EXPOSE_MSF_RPC opt-in to avoid exposing RPC to host network. - Replace crashing assertion on missing default model with a friendly CLI/TUI error path. - Add .dockerignore to reduce build context and avoid copying unnecessary files.
This commit is contained in:
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
||||
venv
|
||||
.venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.git
|
||||
loot
|
||||
dist
|
||||
build
|
||||
*.egg-info
|
||||
third_party/MetasploitMCP
|
||||
venv/
|
||||
venv/*
|
||||
.env
|
||||
runtime/
|
||||
/.pytest_cache
|
||||
81
PR_BODY.md
Normal file
81
PR_BODY.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# MCP: Add Metasploit integration, HexStrike parity, auto-start flags and SSETransport improvements
|
||||
|
||||
## Summary
|
||||
This PR adds a vendored Metasploit MCP integration and brings it to parity with the existing HexStrike MCP integration. It also improves the MCP transport layer (SSE) to reliably handle HTTP/SSE MCP servers that return 202/async responses.
|
||||
|
||||
## Key changes
|
||||
- Add Metasploit MCP support via a `MetasploitAdapter` that can start/stop the vendored `MetasploitMCP` server and optionally start `msfrpcd` for local testing.
|
||||
- Make MCP tool registration automatic: MCP tools are discovered and registered at startup so they appear in the TUI `/tools` view.
|
||||
- Add environment flags to control vendored servers and subtree updates:
|
||||
- `LAUNCH_HEXTRIKE` / `LAUNCH_HEXSTRIKE` — control HexStrike vendored server auto-start behavior
|
||||
- `LAUNCH_METASPLOIT_MCP` — control Metasploit vendored server auto-start behavior
|
||||
- `FORCE_SUBTREE_PULL` — helper for scripts that add/update vendored `third_party` subtrees
|
||||
- Improve HTTP/SSE transport (`SSETransport`) to:
|
||||
- Discover the server's POST endpoint announced over `/sse`
|
||||
- Maintain a persistent SSE listener instead of transient GETs
|
||||
- Correlate pending requests with SSE-delivered responses (supporting 202 Accepted flows)
|
||||
- Wait for endpoint discovery on connect to avoid writer races
|
||||
- Add/update helper scripts (`scripts/add_metasploit_subtree.sh`, `scripts/setup.sh`) to vendor/update the Metasploit subtree and provide optional msfrpcd auto-start during setup.
|
||||
|
||||
## Files touched (high level)
|
||||
- `pentestagent/mcp/metasploit_adapter.py` — new adapter to manage vendored Metasploit MCP and optional msfrpcd.
|
||||
- `pentestagent/mcp/transport.py` — SSETransport enhancements and robustness fixes.
|
||||
- `pentestagent/mcp/manager.py` — LAUNCH env handling, auto-start wiring and connection logic (fixes applied so LAUNCH_* works as expected).
|
||||
- `pentestagent/mcp/mcp_servers.json` — added/updated `metasploit-local` entry in HexStrike-style (`--server http://...`).
|
||||
- `.env.example` — grouped MCP settings; documents `FORCE_SUBTREE_PULL` and LAUNCH flags.
|
||||
- `scripts/add_metasploit_subtree.sh`, `scripts/setup.sh` — vendoring helpers and optional msfrpcd startup.
|
||||
|
||||
(See the full commit set on this branch for exact diffs and additional smaller edits.)
|
||||
|
||||
## Behavior / Usage
|
||||
- Default: vendored MCP entries are present in `pentestagent/mcp/mcp_servers.json` but not started unless configured.
|
||||
- To allow PentestAgent to auto-start vendored MCPs at runtime, set the corresponding `LAUNCH_*` environment variable to a truthy value (e.g. `true`, `1`, `yes`):
|
||||
|
||||
```bash
|
||||
export LAUNCH_METASPLOIT_MCP=true
|
||||
export LAUNCH_HEXTRIKE=true
|
||||
pentestagent
|
||||
```
|
||||
|
||||
When `LAUNCH_METASPLOIT_MCP` is truthy and the manager is started, the manager will attempt to auto-start the vendored Metasploit adapter and connect to it so its tools are registered automatically.
|
||||
|
||||
If you prefer to run the vendored MCP server manually (recommended for debugging), start it separately and then run PentestAgent/TUI. Example:
|
||||
|
||||
```bash
|
||||
python third_party/MetasploitMCP/MetasploitMCP.py --server http://127.0.0.1:7777 \
|
||||
> loot/artifacts/metasploit_mcp.log 2>&1 & disown
|
||||
pentestagent mcp test metasploit-local
|
||||
```
|
||||
|
||||
## How to test
|
||||
1. Pull this branch and install dependencies (see `scripts/setup.sh`).
|
||||
2. Manual test:
|
||||
- Start msfrpcd (or configure `MSF_*` envs to point to an existing Metasploit RPC)
|
||||
- Start the vendored MCP server:
|
||||
|
||||
```bash
|
||||
python third_party/MetasploitMCP/MetasploitMCP.py --server http://127.0.0.1:7777
|
||||
```
|
||||
|
||||
- Run the manager test:
|
||||
|
||||
```bash
|
||||
pentestagent mcp test metasploit-local
|
||||
```
|
||||
|
||||
- Expected: `+ Connected successfully!` and a list of available Metasploit tools.
|
||||
|
||||
3. Auto-start test:
|
||||
- Export `LAUNCH_METASPLOIT_MCP=true` and run `pentestagent` (or the TUI). The manager should auto-start the adapter and register tools so they appear in `/tools`.
|
||||
|
||||
## Security / Notes
|
||||
- Do not commit real passwords or API keys. Use a local `.env` (never committed) to provide secrets like `MSF_PASSWORD`.
|
||||
- The setup helper that may start `msfrpcd` will never invoke `sudo` — it only starts a local msfrpcd process if credentials are present and auto-start is enabled.
|
||||
|
||||
## Follow-ups / Optional improvements
|
||||
- Add `scripts/start_metasploit.sh` to start the vendored MCP detached and capture logs (I can add this in a follow-up PR if desired).
|
||||
- Add a short README section documenting the MCP vendoring workflow and recommended `.env` values for local testing.
|
||||
|
||||
---
|
||||
|
||||
If you'd like any edits to wording or additional testing instructions, tell me what to change and I will update the PR body.
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
context: .
|
||||
dockerfile: Dockerfile.kali
|
||||
container_name: pentestagent-kali
|
||||
privileged: true # Required for VPN and some tools
|
||||
privileged: true # Required for VPN and some tools. NOTE: this is risky on shared hosts; prefer running inside a disposable VM.
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
@@ -31,6 +31,9 @@ services:
|
||||
- PENTESTAGENT_MODEL=${PENTESTAGENT_MODEL}
|
||||
- ENABLE_TOR=${ENABLE_TOR:-false}
|
||||
- INIT_METASPLOIT=${INIT_METASPLOIT:-false}
|
||||
# By default msfrpcd binds to loopback; to intentionally expose Metasploit RPC to the host
|
||||
# set EXPOSE_MSF_RPC=true in your environment. This is NOT recommended on shared machines.
|
||||
- EXPOSE_MSF_RPC=${EXPOSE_MSF_RPC:-false}
|
||||
volumes:
|
||||
- ./loot:/app/loot
|
||||
networks:
|
||||
|
||||
@@ -11,12 +11,12 @@ NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}🔧 PentestAgent Container Starting...${NC}"
|
||||
|
||||
# Start VPN if config provided
|
||||
if [ -f "/vpn/config.ovpn" ]; then
|
||||
# Start VPN if config provided and openvpn is available
|
||||
if [ -f "/vpn/config.ovpn" ] && command -v openvpn >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}📡 Starting VPN connection...${NC}"
|
||||
openvpn --config /vpn/config.ovpn --daemon
|
||||
openvpn --config /vpn/config.ovpn --daemon || echo "openvpn failed to start"
|
||||
sleep 5
|
||||
|
||||
|
||||
# Check VPN connection
|
||||
if ip a show tun0 &>/dev/null; then
|
||||
echo -e "${GREEN}✅ VPN connected${NC}"
|
||||
@@ -25,22 +25,35 @@ if [ -f "/vpn/config.ovpn" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start Tor if enabled
|
||||
if [ "$ENABLE_TOR" = "true" ]; then
|
||||
# Start Tor if enabled and if a service command is available
|
||||
if [ "$ENABLE_TOR" = "true" ] && command -v service >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}🧅 Starting Tor...${NC}"
|
||||
service tor start
|
||||
service tor start || echo "tor service not available"
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# Initialize any databases
|
||||
if [ "$INIT_METASPLOIT" = "true" ]; then
|
||||
# Initialize any databases (guarded)
|
||||
if [ "$INIT_METASPLOIT" = "true" ] && command -v msfdb >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}🗄️ Initializing Metasploit database...${NC}"
|
||||
msfdb init 2>/dev/null || true
|
||||
msfdb init 2>/dev/null || echo "msfdb init failed"
|
||||
fi
|
||||
|
||||
# Create output directory with timestamp
|
||||
OUTPUT_DIR="/output/$(date +%Y%m%d_%H%M%S)"
|
||||
# Ensure persistent output directory lives under /app/loot (mounted by compose)
|
||||
OUTPUT_DIR="/app/loot/$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Optionally chown mounted volume on startup (only when running as root and explicitly enabled)
|
||||
if [ "$(id -u)" = "0" ] && [ "${CHOWN_ON_START,,}" = "true" ]; then
|
||||
# If PUID/PGID supplied use them, otherwise keep default permissions
|
||||
if [ -n "${PUID:-}" ] && [ -n "${PGID:-}" ]; then
|
||||
groupadd -g ${PGID} pentestagent 2>/dev/null || true
|
||||
useradd -u ${PUID} -g ${PGID} -m pentestagent 2>/dev/null || true
|
||||
chown -R ${PUID}:${PGID} /app/loot || true
|
||||
else
|
||||
chown -R pentestagent:pentestagent /app/loot 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
export PENTESTAGENT_OUTPUT_DIR="$OUTPUT_DIR"
|
||||
|
||||
echo -e "${GREEN}📁 Output directory: $OUTPUT_DIR${NC}"
|
||||
|
||||
@@ -389,6 +389,15 @@ def main():
|
||||
|
||||
# If no command provided, default to TUI
|
||||
if args.command is None:
|
||||
# Ensure a default model is configured; provide a friendly error if not
|
||||
if not DEFAULT_MODEL:
|
||||
print("Error: No default model configured (PENTESTAGENT_MODEL).")
|
||||
print("Set PENTESTAGENT_MODEL in .env file or pass --model on the command line.")
|
||||
print(
|
||||
"Example: PENTESTAGENT_MODEL=gpt-5 or PENTESTAGENT_MODEL=claude-sonnet-4-20250514"
|
||||
)
|
||||
return
|
||||
|
||||
run_tui(target=None, model=DEFAULT_MODEL, use_docker=False)
|
||||
return
|
||||
|
||||
|
||||
@@ -1139,9 +1139,21 @@ class PentestAgentTUI(App):
|
||||
await self.runtime.start()
|
||||
|
||||
# LLM
|
||||
# Ensure types for static analysis: runtime and model are set
|
||||
assert self.model is not None
|
||||
assert self.runtime is not None
|
||||
# Validate model/runtime presence and provide a user-friendly error
|
||||
if not self.model:
|
||||
self._add_system(
|
||||
"[!] No model configured. Set PENTESTAGENT_MODEL environment variable or create a .env file (see .env.example)."
|
||||
)
|
||||
self._set_status("error")
|
||||
self._is_initializing = False
|
||||
return
|
||||
|
||||
if not self.runtime:
|
||||
self._add_system("[!] Runtime failed to initialize.")
|
||||
self._set_status("error")
|
||||
self._is_initializing = False
|
||||
return
|
||||
|
||||
llm = LLM(
|
||||
model=self.model,
|
||||
config=ModelConfig(temperature=0.7),
|
||||
|
||||
@@ -154,6 +154,17 @@ if [ "${LAUNCH_METASPLOIT_MCP,,}" = "true" ] && [ -n "${MSF_PASSWORD:-}" ]; then
|
||||
LOG_DIR="loot/artifacts"
|
||||
mkdir -p "$LOG_DIR"
|
||||
MSF_LOG="$LOG_DIR/metasploit_msfrpcd.log"
|
||||
# For safety, bind msfrpcd to loopback by default. To intentionally expose RPC to the host
|
||||
# set EXPOSE_MSF_RPC=true in your environment (not recommended on shared hosts).
|
||||
if [ "${EXPOSE_MSF_RPC,,}" != "true" ]; then
|
||||
if [ "$MSF_SERVER" != "127.0.0.1" ] && [ "$MSF_SERVER" != "localhost" ]; then
|
||||
echo "Warning: MSF_SERVER is set to '$MSF_SERVER' but EXPOSE_MSF_RPC is not true. Overriding to 127.0.0.1 for safety."
|
||||
fi
|
||||
MSF_SERVER=127.0.0.1
|
||||
else
|
||||
echo "EXPOSE_MSF_RPC=true: msfrpcd will bind to $MSF_SERVER and may be reachable from the host network. Ensure you know the risks."
|
||||
fi
|
||||
|
||||
if [ "${MSF_SSL,,}" = "true" ] || [ "${MSF_SSL}" = "1" ]; then
|
||||
"$msfrpcd_cmd" -U "$MSF_USER" -P "$MSF_PASSWORD" -a "$MSF_SERVER" -p "$MSF_PORT" -S >"$MSF_LOG" 2>&1 &
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user