Repository navigation
Tools Reference
53 tools registered in ToolRegistry in the full image (28 core + idor, cmd_inject, replay, graphql, deserialize, apache_42013, mongo_id, upload; Metasploit and Burp are optional). All tools return ToolResult with metadata["findings"] for HTTP scanners.
from tools.integrations import ToolRegistry
registry = ToolRegistry()
print(registry.available_tools()) # list of available tool names
result = registry.run("nmap", "10.0.0.1")
print(result.success) # True/False
print(result.raw_output) # raw output
print(result.metadata) # structured data per tool@dataclass
class ToolResult:
tool: str
target: str
command: str
raw_output: str
success: bool
error: str = ""
duration: float = 0.0
metadata: dict = field(default_factory=dict)External Model Context Protocol servers are
reached through tools/mcp.py rather than the registry. Configure them with
PENTESTAI_MCP_SERVERS and use the mcp shell command:
mcp list
mcp tools filesystem
mcp call filesystem read_file '{"path":"/tmp/target.txt"}'Tool results follow the MCP content array; text items are printed directly.
nmap — Port scan + service detection
result = registry.run("nmap", "10.0.0.1")
result = registry.run("nmap", "10.0.0.1", ports="80,443,8080", timing="T4")
# metadata: {"services": [{"host","port","service","version"}], "parsed_hosts": [...]}http — HTTP probe + technology detection
result = registry.run("http", "http://10.0.0.1")
# metadata: {"technologies": ["WordPress 6.1"], "working_url": "http://..."}subdomain — Subdomain enumeration via crt.sh + DNS bruteforce
result = registry.run("subdomain", "example.com")
# metadata: {"subdomains": [{"subdomain", "ip", "source"}]}waf_detect — WAF fingerprinting from response headers
result = registry.run("waf_detect", "http://target.com")
# metadata: {"waf": "Cloudflare", "confidence": 0.9}osint — crt.sh passive DNS + basic OSINT
result = registry.run("osint", "example.com")cert_scan — SSL/TLS certificate analysis + SAN harvest
result = registry.run("cert_scan", "10.0.0.1")
# metadata: {"sans": [...], "issuer": "...", "expiry": "..."}browser — Headless Chromium (Playwright): JS rendering, auth flows, screenshots
tool = registry.get("browser")
tool.run("https://app.example.test", action="open")
tool.run("https://app.example.test", action="login",
email_selector="#email", password_selector="#password",
submit_selector="#login", email="u@example.test", password="secret")
tool.run("https://app.example.test/register", action="register",
username="u", password="secret", email="u@example.test", submit=True)
tool.run("https://app.example.test", action="screenshot", path="artifacts/flow.png")
# metadata: {"title","final_url","status","authenticated","screenshot"}action=register fills common required fields (first_name/last_name
defaults) and logs in with the new account after the redirect. Requires
pip install playwright && playwright install chromium (already in the image).
gobuster — Directory/file enumeration
result = registry.run("gobuster", "http://10.0.0.1/", extensions="php,html")
# metadata: {"paths": [{"path","status","size"}], "interesting": [...]}sqlmap — SQL injection testing
result = registry.run("sqlmap", "http://10.0.0.1/login.php", data="user=a&pass=b")
# metadata: {"injections": [...]}nikto — Web vulnerability scanner
result = registry.run("nikto", "http://10.0.0.1/")ssti — Server-Side Template Injection (Jinja2, Twig, Freemarker, ...)
result = registry.run("ssti", "http://10.0.0.1/template?q=test")
# metadata: {"confirmed": {...}, "findings": [{"title","severity","description","exploit_path"}]}xxe — XML External Entity Injection
result = registry.run("xxe", "http://10.0.0.1/api/parse")
# metadata: {"confirmed": [...], "findings": [...]}ssrf — Server-Side Request Forgery (metadata or form-fetch chain)
result = registry.run("ssrf", "http://10.0.0.1/fetch?url=")
result = registry.run("ssrf", "http://10.0.0.1/profile", parameter="avatar_url",
cookies={"session": "..."}, auto_form=True)
# auto_form parses the form, preserves values, discovers localhost-only
# endpoints from HTML comments, and verifies the state change.
# metadata: {"confirmed": {...}, "findings": [...]}graphql — GraphQL introspection + query-argument SQLi
result = registry.run("graphql", "http://10.0.0.1/", query="")
# metadata: {"findings": [...], "endpoint": "...", "field": "...", "arg": "..."}deserialize — YAML/Python deserialization verifier
result = registry.run("deserialize", "http://10.0.0.1/list",
cookie_name="bookmarks", trigger_path="/list")
# Sends a benign os.system payload and reads the flag back from /static/flag.txt.
# success is true only when the flag is retrieved, not merely on cookie presence.xss — XSS verifier with browser execution proof
result = registry.run("xss", "http://10.0.0.1/search?q=test", parameter="q")
result = registry.run("xss", "http://10.0.0.1/search", parameter="name",
method="POST", cookies={"PHPSESSID": "..."})
# metadata: {"confirmed": [...], "findings": [...]}Reflection alone stays a candidate. When Playwright is available the scanner
loads the payload in Chromium and requires a DOM marker or alert() before it
reports a confirmed finding. Authenticated pages can be tested with cookies.
HTML-escaped reflection is never confirmed.
apache_42013 — Apache 2.4.49/2.4.50 traversal to CGI shell
result = registry.run("apache_42013", "http://10.0.0.1/")
# metadata: {"findings": [...]}; success requires uid= or flag outputmongo_id — MongoDB ObjectId prediction / IDOR
result = registry.run("mongo_id", "http://10.0.0.1/",
register_path="/register", profile_path="/profile/")
# Registers a throwaway user, uses the leaked counter distance, and reads the
# first user's profile; success requires the flag.upload — Multipart file-upload verifier
result = registry.run("upload", "http://10.0.0.1/index.php",
field="userfile", filename="pentestai.php")
# Uploads a PHP command shell and reads the flag back; success requires execution.path_traversal — Path traversal / LFI
result = registry.run("path_traversal", "http://10.0.0.1/?file=")
# metadata: {"confirmed": [...], "findings": [...]}jwt_scan — JWT vulnerabilities (alg:none, weak secret)
result = registry.run("jwt_scan", "http://10.0.0.1/api")
# metadata: {"vulnerabilities": [...], "findings": [...]}oauth2_scan — OAuth2 misconfigurations
result = registry.run("oauth2_scan", "http://10.0.0.1")
# metadata: {"issues": [...], "findings": [...]}hydra — Credential bruteforce
result = registry.run("hydra", "10.0.0.1", service="ssh",
userlist=["admin","root"], passlist=["password","123456"])
# metadata: {"credentials_found": [{"host","port","service","username"}]}metasploit — Metasploit RPC module execution
result = registry.run("metasploit", "10.0.0.1",
module="exploit/multi/samba/usermap_script")
# LHOST auto-detected via detect_lhost() (tun0 → eth0 → socket)
# metadata: {"module", "module_type", "response"}burp — Burp Suite REST API integration
result = registry.run("burp", "http://10.0.0.1/", action="scan")ad_enum — LDAP enumeration (users, groups, computers)
result = registry.run("ad_enum", "10.0.0.1",
username="user", password="pass", domain="corp.local")
# metadata: {"users": [...], "groups": [...], "computers": [...]}kerberoast — Kerberoastable service accounts
result = registry.run("kerberoast", "10.0.0.1",
username="user", password="pass", domain="corp.local")
# metadata: {"spns": [...], "hashes": [...]}cred_spray — Credential spraying via CrackMapExec
result = registry.run("cred_spray", "10.0.0.0/24",
username="admin", password="Password1!")privesc — Parse linpeas/winpeas output + AI triage
result = registry.run("privesc", "10.0.0.1", output=linpeas_output)
# metadata: {"vectors": [...], "findings": [...]}aws_recon — AWS metadata + public S3/IAM checks
result = registry.run("aws_recon", "10.0.0.1")gcp_recon — GCP metadata endpoint probing
result = registry.run("gcp_recon", "10.0.0.1")azure_recon — Azure IMDS + public blob checks
result = registry.run("azure_recon", "10.0.0.1")sslscan — SSL/TLS weakness analysis
result = registry.run("sslscan", "10.0.0.1")
# metadata: {"weak_ciphers": [...], "protocols": [...]}For exploits that need a reverse shell, detect_lhost() in tools/msf.py automatically detects an IP reachable from the target:
-
PENTESTAI_LHOSTenv var (explicit override) -
tun0interface (HTB/TryHackMe VPN) -
eth0/ens33(direct connection) - Socket trick to 8.8.8.8
Manual override: export PENTESTAI_LHOST=10.10.14.5
from tools.parsers import NmapParser, GobusterParser, HydraParser
# NmapParser returns list[ParsedHost]
hosts = NmapParser.parse(nmap_output) # auto-detect XML vs text
for host in hosts:
for port in host.open_ports:
print(port.port, port.service, port.version)
service_dicts = [p.to_service_dict(host.ip) for p in host.open_ports]
# GobusterParser returns list[ParsedPath]
paths = GobusterParser.parse(gobuster_output)
interesting = [p for p in paths if p.interesting]
# HydraParser returns list[ParsedCredential]
creds = HydraParser.parse(hydra_output)
for c in creds:
print(c.username, c.service, c.host, c.port)Not tools in ToolRegistry, but shell commands that use the tools above.
orchestrate [target] [--seq]Runs four sub-agents in parallel:
-
ReconSubAgent→ nmap + http + subdomain + cert_scan -
WebSubAgent→ gobuster + waf_detect + SSTI/XXE/SSRF/path_traversal + nikto -
InfraSubAgent→ cert_scan + ad_enum + kerberoast + privesc -
ReportSubAgent→ HTML + Word report
from agents.orchestrator import AgentOrchestrator
orch = AgentOrchestrator(session, scope, llm, registry)
result = orch.run("10.0.0.1", parallel=True)
# result.total_findings, result.total_services, result.summary()ptesProduces two files:
-
*_ptes.json— machine-readable (SIEM, ticketing) -
*_ptes.md— Markdown for the client
from reports.ptes import PTESReportGenerator
gen = PTESReportGenerator(session)
gen.generate_json()
gen.generate_markdown()iso27001Produces *_iso27001.json with Annex A control mapping, risk scoring (1-25), residual risk.
from reports.ptes import ISO27001RiskRegister
gen = ISO27001RiskRegister(session)
gen.generate()marketplace # list all plugins
marketplace search <query> # search
marketplace install <id> # install from GitHub + verify checksum
marketplace uninstall <id> # remove
marketplace info <id> # details
marketplace installed # already installed
marketplace fetch # refresh registryfrom plugins.marketplace import PluginMarketplace
mp = PluginMarketplace()
mp.fetch()
results = mp.search("active directory")
mp.install("ad-suite")