diff --git a/pentestagent/agents/crew/orchestrator.py b/pentestagent/agents/crew/orchestrator.py index ce7e7cf..b35af77 100644 --- a/pentestagent/agents/crew/orchestrator.py +++ b/pentestagent/agents/crew/orchestrator.py @@ -1,7 +1,6 @@ """Crew orchestrator - an agent that manages other agents.""" import json -import platform from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Optional from ...config.constants import DEFAULT_MAX_ITERATIONS @@ -122,16 +121,15 @@ class CrewOrchestrator: f"- {i}" for i in graph_insights ) + # Get runtime environment with detected tools + env = self.runtime.environment + return pa_crew.render( target=self.target or "Not specified", prior_context=self.prior_context or "None - starting fresh", notes_context=notes_context + insights_text, worker_tools=worker_tools_formatted, - environment={ - "os": platform.system(), - "os_version": platform.release(), - "architecture": platform.machine(), - }, + environment=env, ) async def run(self, task: str) -> AsyncIterator[Dict[str, Any]]: diff --git a/pentestagent/agents/prompts/pa_agent.jinja b/pentestagent/agents/prompts/pa_agent.jinja index 4ab9660..1ee6e5d 100644 --- a/pentestagent/agents/prompts/pa_agent.jinja +++ b/pentestagent/agents/prompts/pa_agent.jinja @@ -54,12 +54,25 @@ Do NOT skip calling finish between steps. - OS: {{ environment.os }} ({{ environment.os_version }}) - Architecture: {{ environment.architecture }} - Shell: {{ environment.shell }} -- Available CLI Tools: -{{ environment.available_tools|join(', ') }} -- Output directories: - - loot/notes.json (working notes) - - loot/reports/ (generated reports) - - loot/artifacts/ (screenshots, captured files) +{% endif %} + +## Tools +{% for tool in tools %} +- **{{ tool.name }}**: {{ tool.description }} +{% endfor %} + +{% if environment and environment.available_tools %} +## Available CLI Tools +{% for tool in environment.available_tools %} + • {{ tool.name }}{% if tool.category %} ({{ tool.category }}){% endif %} +{% endfor %} +{% endif %} + +{% if environment %} +## Output Directories +- loot/notes.json (working notes) +- loot/reports/ (generated reports) +- loot/artifacts/ (screenshots, captured files) {% endif %} {% if target %} @@ -70,11 +83,6 @@ Do NOT skip calling finish between steps. Scope: {{ scope | join(', ') }} {% endif %} -## Tools -{% for tool in tools %} -- **{{ tool.name }}**: {{ tool.description }} -{% endfor %} - {% if rag_context %} ## Context {{ rag_context }} diff --git a/pentestagent/agents/prompts/pa_assist.jinja b/pentestagent/agents/prompts/pa_assist.jinja index 5d26763..b1260e2 100644 --- a/pentestagent/agents/prompts/pa_assist.jinja +++ b/pentestagent/agents/prompts/pa_assist.jinja @@ -18,12 +18,25 @@ You are operating in an authorized penetration testing engagement. The user has - OS: {{ environment.os }} ({{ environment.os_version }}) - Architecture: {{ environment.architecture }} - Shell: {{ environment.shell }} -- Available CLI Tools: -{{ environment.available_tools|join(', ') }} -- Output directories: - - loot/notes.json (working notes) - - loot/reports/ (generated reports) - - loot/artifacts/ (screenshots, captured files) +{% endif %} + +## Tools +{% for tool in tools %} +- **{{ tool.name }}**: {{ tool.description }} +{% endfor %} + +{% if environment and environment.available_tools %} +## Available CLI Tools +{% for tool in environment.available_tools %} + • {{ tool.name }}{% if tool.category %} ({{ tool.category }}){% endif %} +{% endfor %} +{% endif %} + +{% if environment %} +## Output Directories +- loot/notes.json (working notes) +- loot/reports/ (generated reports) +- loot/artifacts/ (screenshots, captured files) {% endif %} {% if target %} @@ -34,11 +47,6 @@ You are operating in an authorized penetration testing engagement. The user has Scope: {{ scope | join(', ') }} {% endif %} -## Tools -{% for tool in tools %} -- **{{ tool.name }}**: {{ tool.description }} -{% endfor %} - {% if rag_context %} ## Context {{ rag_context }} diff --git a/pentestagent/agents/prompts/pa_crew.jinja b/pentestagent/agents/prompts/pa_crew.jinja index 6d0a826..aeb4375 100644 --- a/pentestagent/agents/prompts/pa_crew.jinja +++ b/pentestagent/agents/prompts/pa_crew.jinja @@ -37,17 +37,29 @@ You manage agents using these tools: - **synthesize_findings**: Compile all results into a final concise report (call this when done) {% if worker_tools %} -## Worker Agent Capabilities +## Worker Agent Tools Workers have access to the following tools: {{ worker_tools }} +{% endif %} {% if environment.available_tools %} +## Worker Agent CLI Tools Workers also have access to these CLI tools via terminal: -{{ environment.available_tools }} +{% for tool in environment.available_tools %} + • {{ tool.name }}{% if tool.category %} ({{ tool.category }}){% endif %} +{% endfor %} +{% else %} +{% if worker_tools %} +## Worker Agent CLI Tools +No CLI tools detected on this system. {% endif %} {% endif %} -IMPORTANT: When spawning agents, be specific about which tool to use (e.g., "Use mcp_nmap_scan to..." or "Use mcp_metasploit_run_module to..."). Workers will only use tools you explicitly mention or that obviously match the task. +CRITICAL CONSTRAINTS: +- Only spawn agents using tools from the "Worker Agent Capabilities" lists above +- If a CLI tool is required but not listed in available_tools, choose an alternative approach or available tool +- Validate tool availability before spawning agents to avoid failures +- Be specific about which tool to use (e.g., "Use terminal to run nmap..." or "Use browser to navigate...") ## Strategy & Replanning (COA) You are responsible for STRATEGIC adaptation. diff --git a/pentestagent/interface/main.py b/pentestagent/interface/main.py index ac980da..4524e63 100644 --- a/pentestagent/interface/main.py +++ b/pentestagent/interface/main.py @@ -90,6 +90,9 @@ Examples: tools_info = tools_subparsers.add_parser("info", help="Show tool details") tools_info.add_argument("name", help="Tool name") + # tools env + tools_subparsers.add_parser("env", help="Show detected CLI tools in environment") + # MCP subcommand mcp_parser = subparsers.add_parser("mcp", help="Manage MCP servers") mcp_subparsers = mcp_parser.add_subparsers(dest="mcp_command", help="MCP commands") @@ -167,6 +170,39 @@ def handle_tools_command(args: argparse.Namespace): desc = props.get("description", "") console.print(f" [cyan]{name}[/] ({ptype}, {required}): {desc}") + elif args.tools_command == "env": + from ..runtime.runtime import detect_environment + + env = detect_environment() + + console.print("\n[bold]Environment:[/]") + console.print(f" OS: {env.os} ({env.os_version})") + console.print(f" Architecture: {env.architecture}") + console.print(f" Shell: {env.shell}") + + if env.available_tools: + console.print( + f"\n[bold]Detected CLI Tools ({len(env.available_tools)}):[/]" + ) + + # Group by category + by_category = {} + for tool_info in env.available_tools: + if tool_info.category not in by_category: + by_category[tool_info.category] = [] + by_category[tool_info.category].append(tool_info) + + for category in sorted(by_category.keys()): + tools_in_cat = by_category[category] + console.print(f"\n[bold cyan]{category}[/] ({len(tools_in_cat)}):") + for tool_info in sorted(tools_in_cat, key=lambda t: t.name): + console.print(f" • {tool_info.name}") + else: + console.print("\n[yellow]No CLI tools detected[/]") + console.print( + "\n[dim]Tip: Install tools like nmap, curl, git to expand capabilities[/]" + ) + else: console.print("[yellow]Use 'pentestagent tools --help' for commands[/]") diff --git a/pentestagent/interface/tui.py b/pentestagent/interface/tui.py index 03babc2..85a614a 100644 --- a/pentestagent/interface/tui.py +++ b/pentestagent/interface/tui.py @@ -1083,8 +1083,31 @@ Be concise. Use the actual data from notes.""" self.agent.conversation_history.clear() self._add_system("Chat cleared") elif cmd_lower == "/tools": + from ..runtime.runtime import detect_environment + names = [t.name for t in self.all_tools] - self._add_system(f"Tools ({len(names)}): " + ", ".join(names)) + msg = f"Tools ({len(names)}): " + ", ".join(names) + + # Add detected CLI tools + env = detect_environment() + if env.available_tools: + # Group by category + by_category = {} + for tool_info in env.available_tools: + if tool_info.category not in by_category: + by_category[tool_info.category] = [] + by_category[tool_info.category].append(tool_info.name) + + cli_sections = [] + for category in sorted(by_category.keys()): + tools_list = ", ".join(sorted(by_category[category])) + cli_sections.append(f"{category}: {tools_list}") + + msg += f"\n\nCLI Tools ({len(env.available_tools)}):\n" + "\n".join( + cli_sections + ) + + self._add_system(msg) elif cmd_lower in ["/quit", "/exit", "/q"]: self.exit() elif cmd_lower == "/prompt": diff --git a/pentestagent/playbooks/thp3_network.py b/pentestagent/playbooks/thp3_network.py index b4371f5..c2deb87 100644 --- a/pentestagent/playbooks/thp3_network.py +++ b/pentestagent/playbooks/thp3_network.py @@ -11,24 +11,28 @@ class THP3NetworkPlaybook(BasePlaybook): name="Initial Access", objective="Gain initial foothold on the network", techniques=[ - "Password spraying against external services (OWA, VPN)", - "LLMNR/NBT-NS poisoning (Responder)", + "Password spraying against external services", + "Network protocol poisoning attacks", + "Exploit public-facing vulnerabilities", + "Phishing and social engineering", ], ), Phase( name="Enumeration & Privilege Escalation", objective="Map internal network and elevate privileges", techniques=[ - "Active Directory enumeration (PowerView, BloodHound)", - "Identify privilege escalation paths (unquoted paths, weak perms)", - "Credential dumping (Mimikatz, local files)", + "Active Directory and domain enumeration", + "Identify privilege escalation paths and misconfigurations", + "Extract credentials from memory and files", + "Enumerate users, groups, and permissions", ], ), Phase( name="Lateral Movement & Objectives", objective="Move through network to reach high-value targets", techniques=[ - "Lateral movement (WMI, PsExec, DCOM)", + "Lateral movement via remote services", + "Pass-the-hash and pass-the-ticket attacks", "Access high-value targets and data repositories", ], ), diff --git a/pentestagent/playbooks/thp3_recon.py b/pentestagent/playbooks/thp3_recon.py index 3183b72..7861ed8 100644 --- a/pentestagent/playbooks/thp3_recon.py +++ b/pentestagent/playbooks/thp3_recon.py @@ -11,19 +11,21 @@ class THP3ReconPlaybook(BasePlaybook): name="Passive Reconnaissance", objective="Gather information without direct interaction", techniques=[ - "OSINT infrastructure identification (Shodan, Censys)", - "Subdomain discovery (Sublist3r, Amass)", + "OSINT and public infrastructure identification", + "Subdomain and DNS enumeration", "Cloud infrastructure scanning and misconfiguration checks", - "Code repository search for leaked credentials", + "Code repository search for exposed credentials", + "Social media and email harvesting", ], ), Phase( name="Active Reconnaissance", objective="Interact with target to map attack surface", techniques=[ - "Port scanning and service identification (Nmap)", - "Web service screenshotting", - "Email address harvesting", + "Port scanning and service version detection", + "Web technology identification and fingerprinting", + "Service banner grabbing and enumeration", + "SSL/TLS certificate analysis", ], ), ] diff --git a/pentestagent/playbooks/thp3_web.py b/pentestagent/playbooks/thp3_web.py index 8f22311..abfad16 100644 --- a/pentestagent/playbooks/thp3_web.py +++ b/pentestagent/playbooks/thp3_web.py @@ -11,20 +11,24 @@ class THP3WebPlaybook(BasePlaybook): name="Discovery", objective="Understand application attack surface", techniques=[ - "Identify technologies and frameworks (Wappalyzer, BuiltWith)", - "Enumerate endpoints and parameters (Gobuster, Dirbuster)", + "Identify web technologies and frameworks", + "Content discovery and endpoint enumeration", + "Parameter and input point identification", + "Authentication and session mechanism analysis", ], ), Phase( name="Exploitation", objective="Identify and exploit web vulnerabilities", techniques=[ - "Cross-Site Scripting (XSS) (Blind, DOM-based)", - "SQL and NoSQL Injection", - "Deserialization vulnerabilities (Node.js, Java, PHP)", - "Server-Side Template Injection", + "Injection attacks (SQL, NoSQL, Command, LDAP)", + "Cross-Site Scripting (Reflected, Stored, DOM-based)", + "Authentication and authorization bypass", + "Server-Side Template Injection and SSTI", "Server-Side Request Forgery (SSRF)", - "XML External Entity (XXE)", + "Insecure deserialization vulnerabilities", + "XML External Entity (XXE) attacks", + "File inclusion and path traversal", ], ), ] diff --git a/pentestagent/runtime/runtime.py b/pentestagent/runtime/runtime.py index bb9dd52..8623be2 100644 --- a/pentestagent/runtime/runtime.py +++ b/pentestagent/runtime/runtime.py @@ -19,6 +19,8 @@ INTERESTING_TOOLS = { "rustscan", "naabu", "unicornscan", + "zmap", + "arp-scan", ], "web_scan": [ "nikto", @@ -30,12 +32,45 @@ INTERESTING_TOOLS = { "wpscan", "nuclei", "whatweb", + "wfuzz", + "arjun", + "burpsuite", + "zaproxy", + "zap-cli", + ], + "enumeration": [ + "enum4linux", + "enum4linux-ng", + "smbclient", + "smbmap", + "rpcclient", + "ldapsearch", + "snmpwalk", + "snmp-check", + "onesixtyone", + "nbtscan", + "responder", + "impacket-smbclient", + "impacket-GetNPUsers", + "impacket-GetUserSPNs", + "impacket-psexec", + "impacket-wmiexec", + "impacket-dcomexec", + "crackmapexec", + "netexec", + "evil-winrm", + "kerbrute", + "xfreerdp", + "rdesktop", ], "exploitation": [ "msfconsole", + "msfvenom", "searchsploit", "sqlmap", "commix", + "xsser", + "ysoserial", ], "password_attacks": [ "hydra", @@ -43,13 +78,28 @@ INTERESTING_TOOLS = { "john", "hashcat", "crackmapexec", + "netexec", "thc-hydra", + "patator", ], "network_analysis": [ "tcpdump", "tshark", "wireshark", "ngrep", + "ettercap", + "bettercap", + ], + "post_exploitation": [ + "mimikatz", + "pypykatz", + "impacket-secretsdump", + "bloodhound", + "sharphound", + "powerview", + "linpeas", + "winpeas", + "pspy", ], "tunneling": [ "proxychains", @@ -57,6 +107,85 @@ INTERESTING_TOOLS = { "socat", "chisel", "ligolo", + "sshuttle", + "ngrok", + ], + "osint": [ + "theHarvester", + "recon-ng", + "amass", + "subfinder", + "assetfinder", + "sublist3r", + "dnsenum", + "dnsrecon", + "fierce", + ], + "wireless": [ + "aircrack-ng", + "airodump-ng", + "aireplay-ng", + "airmon-ng", + "wifite", + "kismet", + "reaver", + "bully", + "hostapd", + "wpa_supplicant", + ], + "reverse_engineering": [ + "ghidra", + "radare2", + "r2", + "gdb", + "pwndbg", + "gef", + "binwalk", + "foremost", + "exiftool", + "objdump", + "readelf", + "strace", + "ltrace", + ], + "cloud": [ + "aws", + "az", + "gcloud", + "s3scanner", + "cloud_enum", + "ScoutSuite", + "prowler", + "pacu", + "cloudfox", + ], + "forensics": [ + "steghide", + "stegseek", + "volatility", + "volatility3", + "autopsy", + "sleuthkit", + "binwalk", + "foremost", + "scalpel", + "bulk_extractor", + ], + "fuzzing": [ + "boofuzz", + "radamsa", + "afl-fuzz", + "zzuf", + "honggfuzz", + ], + "mobile": [ + "adb", + "apktool", + "jadx", + "frida", + "objection", + "mobsf", + "drozer", ], "utilities": [ "curl", @@ -65,16 +194,35 @@ INTERESTING_TOOLS = { "netcat", "ncat", "ssh", + "telnet", "git", "docker", "kubectl", + "kubeletctl", + "kube-hunter", + "trivy", "jq", "python3", + "python", "perl", "ruby", "gcc", "g++", "make", + "base64", + "openssl", + "xxd", + "strings", + "dig", + "whois", + "host", + "traceroute", + "mtr", + "ping", + "awk", + "sed", + "grep", + "find", ], }