aiptx 2.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +46 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/exploit_agent.py +688 -0
  8. aipt_v2/agents/ptt.py +406 -0
  9. aipt_v2/agents/state.py +168 -0
  10. aipt_v2/app.py +957 -0
  11. aipt_v2/browser/__init__.py +31 -0
  12. aipt_v2/browser/automation.py +458 -0
  13. aipt_v2/browser/crawler.py +453 -0
  14. aipt_v2/cli.py +2933 -0
  15. aipt_v2/compliance/__init__.py +71 -0
  16. aipt_v2/compliance/compliance_report.py +449 -0
  17. aipt_v2/compliance/framework_mapper.py +424 -0
  18. aipt_v2/compliance/nist_mapping.py +345 -0
  19. aipt_v2/compliance/owasp_mapping.py +330 -0
  20. aipt_v2/compliance/pci_mapping.py +297 -0
  21. aipt_v2/config.py +341 -0
  22. aipt_v2/core/__init__.py +43 -0
  23. aipt_v2/core/agent.py +630 -0
  24. aipt_v2/core/llm.py +395 -0
  25. aipt_v2/core/memory.py +305 -0
  26. aipt_v2/core/ptt.py +329 -0
  27. aipt_v2/database/__init__.py +14 -0
  28. aipt_v2/database/models.py +232 -0
  29. aipt_v2/database/repository.py +384 -0
  30. aipt_v2/docker/__init__.py +23 -0
  31. aipt_v2/docker/builder.py +260 -0
  32. aipt_v2/docker/manager.py +222 -0
  33. aipt_v2/docker/sandbox.py +371 -0
  34. aipt_v2/evasion/__init__.py +58 -0
  35. aipt_v2/evasion/request_obfuscator.py +272 -0
  36. aipt_v2/evasion/tls_fingerprint.py +285 -0
  37. aipt_v2/evasion/ua_rotator.py +301 -0
  38. aipt_v2/evasion/waf_bypass.py +439 -0
  39. aipt_v2/execution/__init__.py +23 -0
  40. aipt_v2/execution/executor.py +302 -0
  41. aipt_v2/execution/parser.py +544 -0
  42. aipt_v2/execution/terminal.py +337 -0
  43. aipt_v2/health.py +437 -0
  44. aipt_v2/intelligence/__init__.py +194 -0
  45. aipt_v2/intelligence/adaptation.py +474 -0
  46. aipt_v2/intelligence/auth.py +520 -0
  47. aipt_v2/intelligence/chaining.py +775 -0
  48. aipt_v2/intelligence/correlation.py +536 -0
  49. aipt_v2/intelligence/cve_aipt.py +334 -0
  50. aipt_v2/intelligence/cve_info.py +1111 -0
  51. aipt_v2/intelligence/knowledge_graph.py +590 -0
  52. aipt_v2/intelligence/learning.py +626 -0
  53. aipt_v2/intelligence/llm_analyzer.py +502 -0
  54. aipt_v2/intelligence/llm_tool_selector.py +518 -0
  55. aipt_v2/intelligence/payload_generator.py +562 -0
  56. aipt_v2/intelligence/rag.py +239 -0
  57. aipt_v2/intelligence/scope.py +442 -0
  58. aipt_v2/intelligence/searchers/__init__.py +5 -0
  59. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  60. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  61. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  62. aipt_v2/intelligence/tools.json +443 -0
  63. aipt_v2/intelligence/triage.py +670 -0
  64. aipt_v2/interactive_shell.py +559 -0
  65. aipt_v2/interface/__init__.py +5 -0
  66. aipt_v2/interface/cli.py +230 -0
  67. aipt_v2/interface/main.py +501 -0
  68. aipt_v2/interface/tui.py +1276 -0
  69. aipt_v2/interface/utils.py +583 -0
  70. aipt_v2/llm/__init__.py +39 -0
  71. aipt_v2/llm/config.py +26 -0
  72. aipt_v2/llm/llm.py +514 -0
  73. aipt_v2/llm/memory.py +214 -0
  74. aipt_v2/llm/request_queue.py +89 -0
  75. aipt_v2/llm/utils.py +89 -0
  76. aipt_v2/local_tool_installer.py +1467 -0
  77. aipt_v2/models/__init__.py +15 -0
  78. aipt_v2/models/findings.py +295 -0
  79. aipt_v2/models/phase_result.py +224 -0
  80. aipt_v2/models/scan_config.py +207 -0
  81. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  82. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  83. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  84. aipt_v2/monitoring/prometheus.yml +60 -0
  85. aipt_v2/orchestration/__init__.py +52 -0
  86. aipt_v2/orchestration/pipeline.py +398 -0
  87. aipt_v2/orchestration/progress.py +300 -0
  88. aipt_v2/orchestration/scheduler.py +296 -0
  89. aipt_v2/orchestrator.py +2427 -0
  90. aipt_v2/payloads/__init__.py +27 -0
  91. aipt_v2/payloads/cmdi.py +150 -0
  92. aipt_v2/payloads/sqli.py +263 -0
  93. aipt_v2/payloads/ssrf.py +204 -0
  94. aipt_v2/payloads/templates.py +222 -0
  95. aipt_v2/payloads/traversal.py +166 -0
  96. aipt_v2/payloads/xss.py +204 -0
  97. aipt_v2/prompts/__init__.py +60 -0
  98. aipt_v2/proxy/__init__.py +29 -0
  99. aipt_v2/proxy/history.py +352 -0
  100. aipt_v2/proxy/interceptor.py +452 -0
  101. aipt_v2/recon/__init__.py +44 -0
  102. aipt_v2/recon/dns.py +241 -0
  103. aipt_v2/recon/osint.py +367 -0
  104. aipt_v2/recon/subdomain.py +372 -0
  105. aipt_v2/recon/tech_detect.py +311 -0
  106. aipt_v2/reports/__init__.py +17 -0
  107. aipt_v2/reports/generator.py +313 -0
  108. aipt_v2/reports/html_report.py +378 -0
  109. aipt_v2/runtime/__init__.py +53 -0
  110. aipt_v2/runtime/base.py +30 -0
  111. aipt_v2/runtime/docker.py +401 -0
  112. aipt_v2/runtime/local.py +346 -0
  113. aipt_v2/runtime/tool_server.py +205 -0
  114. aipt_v2/runtime/vps.py +830 -0
  115. aipt_v2/scanners/__init__.py +28 -0
  116. aipt_v2/scanners/base.py +273 -0
  117. aipt_v2/scanners/nikto.py +244 -0
  118. aipt_v2/scanners/nmap.py +402 -0
  119. aipt_v2/scanners/nuclei.py +273 -0
  120. aipt_v2/scanners/web.py +454 -0
  121. aipt_v2/scripts/security_audit.py +366 -0
  122. aipt_v2/setup_wizard.py +941 -0
  123. aipt_v2/skills/__init__.py +80 -0
  124. aipt_v2/skills/agents/__init__.py +14 -0
  125. aipt_v2/skills/agents/api_tester.py +706 -0
  126. aipt_v2/skills/agents/base.py +477 -0
  127. aipt_v2/skills/agents/code_review.py +459 -0
  128. aipt_v2/skills/agents/security_agent.py +336 -0
  129. aipt_v2/skills/agents/web_pentest.py +818 -0
  130. aipt_v2/skills/prompts/__init__.py +647 -0
  131. aipt_v2/system_detector.py +539 -0
  132. aipt_v2/telemetry/__init__.py +7 -0
  133. aipt_v2/telemetry/tracer.py +347 -0
  134. aipt_v2/terminal/__init__.py +28 -0
  135. aipt_v2/terminal/executor.py +400 -0
  136. aipt_v2/terminal/sandbox.py +350 -0
  137. aipt_v2/tools/__init__.py +44 -0
  138. aipt_v2/tools/active_directory/__init__.py +78 -0
  139. aipt_v2/tools/active_directory/ad_config.py +238 -0
  140. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  141. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  142. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  143. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  144. aipt_v2/tools/agents_graph/__init__.py +19 -0
  145. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  146. aipt_v2/tools/api_security/__init__.py +76 -0
  147. aipt_v2/tools/api_security/api_discovery.py +608 -0
  148. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  149. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  150. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  151. aipt_v2/tools/browser/__init__.py +5 -0
  152. aipt_v2/tools/browser/browser_actions.py +238 -0
  153. aipt_v2/tools/browser/browser_instance.py +535 -0
  154. aipt_v2/tools/browser/tab_manager.py +344 -0
  155. aipt_v2/tools/cloud/__init__.py +70 -0
  156. aipt_v2/tools/cloud/cloud_config.py +273 -0
  157. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  158. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  159. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  160. aipt_v2/tools/executor.py +307 -0
  161. aipt_v2/tools/parser.py +408 -0
  162. aipt_v2/tools/proxy/__init__.py +5 -0
  163. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  164. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  165. aipt_v2/tools/registry.py +196 -0
  166. aipt_v2/tools/scanners/__init__.py +343 -0
  167. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  168. aipt_v2/tools/scanners/burp_tool.py +631 -0
  169. aipt_v2/tools/scanners/config.py +156 -0
  170. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  171. aipt_v2/tools/scanners/zap_tool.py +612 -0
  172. aipt_v2/tools/terminal/__init__.py +5 -0
  173. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  174. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  175. aipt_v2/tools/terminal/terminal_session.py +449 -0
  176. aipt_v2/tools/tool_processing.py +108 -0
  177. aipt_v2/utils/__init__.py +17 -0
  178. aipt_v2/utils/logging.py +202 -0
  179. aipt_v2/utils/model_manager.py +187 -0
  180. aipt_v2/utils/searchers/__init__.py +269 -0
  181. aipt_v2/verify_install.py +793 -0
  182. aiptx-2.0.7.dist-info/METADATA +345 -0
  183. aiptx-2.0.7.dist-info/RECORD +187 -0
  184. aiptx-2.0.7.dist-info/WHEEL +5 -0
  185. aiptx-2.0.7.dist-info/entry_points.txt +7 -0
  186. aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
  187. aiptx-2.0.7.dist-info/top_level.txt +1 -0
aipt_v2/runtime/vps.py ADDED
@@ -0,0 +1,830 @@
1
+ """
2
+ VPS Runtime for AIPT v2
3
+ =======================
4
+
5
+ Remote execution runtime via SSH for running security tools on a VPS.
6
+ Provides automatic tool installation, command execution, and result retrieval.
7
+
8
+ Architecture:
9
+ Local AIPTX <--SSH--> VPS (Security Tools)
10
+ | |
11
+ Orchestrator Tool Execution
12
+ | |
13
+ Result Parser <--SCP-- JSON Results
14
+
15
+ Usage:
16
+ runtime = VPSRuntime(host="1.2.3.4", user="ubuntu", key_path="~/.ssh/id_rsa")
17
+ await runtime.connect()
18
+ await runtime.ensure_tools_installed()
19
+ stdout, stderr, code = await runtime.execute(sandbox_id, "nmap -sV target.com")
20
+ results = await runtime.retrieve_results(sandbox_id)
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import asyncio
26
+ import json
27
+ import os
28
+ import uuid
29
+ import tempfile
30
+ from dataclasses import dataclass, field
31
+ from datetime import datetime
32
+ from pathlib import Path
33
+ from typing import Optional, Dict, Tuple, List, Any
34
+
35
+ try:
36
+ import asyncssh
37
+ ASYNCSSH_AVAILABLE = True
38
+ except ImportError:
39
+ ASYNCSSH_AVAILABLE = False
40
+
41
+ from aipt_v2.utils.logging import logger
42
+ from aipt_v2.config import get_config
43
+
44
+
45
+ # =============================================================================
46
+ # Tool Definitions - Security tools to install on VPS
47
+ # =============================================================================
48
+
49
+ VPS_TOOLS = {
50
+ # Phase 1: RECON
51
+ "recon": {
52
+ "subfinder": {"install": "go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest", "check": "subfinder -version"},
53
+ "assetfinder": {"install": "go install -v github.com/tomnomnom/assetfinder@latest", "check": "assetfinder -h 2>&1 | head -1"},
54
+ "amass": {"install": "go install -v github.com/owasp-amass/amass/v4/...@master", "check": "amass -version"},
55
+ "httpx": {"install": "go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest", "check": "httpx -version"},
56
+ "nmap": {"install": "apt-get install -y nmap", "check": "nmap --version | head -1"},
57
+ "waybackurls": {"install": "go install -v github.com/tomnomnom/waybackurls@latest", "check": "waybackurls -h 2>&1 | head -1"},
58
+ "theHarvester": {"install": "pip3 install theHarvester", "check": "theHarvester -h 2>&1 | head -1"},
59
+ "dnsrecon": {"install": "pip3 install dnsrecon", "check": "dnsrecon -h 2>&1 | head -1"},
60
+ "wafw00f": {"install": "pip3 install wafw00f", "check": "wafw00f -h 2>&1 | head -1"},
61
+ "whatweb": {"install": "apt-get install -y whatweb", "check": "whatweb --version"},
62
+ "dnsx": {"install": "go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest", "check": "dnsx -version"},
63
+ "katana": {"install": "go install -v github.com/projectdiscovery/katana/cmd/katana@latest", "check": "katana -version"},
64
+ },
65
+ # Phase 2: SCAN
66
+ "scan": {
67
+ "nuclei": {"install": "go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest && nuclei -update-templates", "check": "nuclei -version"},
68
+ "nikto": {"install": "apt-get install -y nikto", "check": "nikto -Version"},
69
+ "wpscan": {"install": "gem install wpscan", "check": "wpscan --version"},
70
+ "ffuf": {"install": "go install -v github.com/ffuf/ffuf/v2@latest", "check": "ffuf -V"},
71
+ "gobuster": {"install": "go install -v github.com/OJ/gobuster/v3@latest", "check": "gobuster version"},
72
+ "dirsearch": {"install": "pip3 install dirsearch", "check": "dirsearch -h 2>&1 | head -1"},
73
+ "sslscan": {"install": "apt-get install -y sslscan", "check": "sslscan --version"},
74
+ "testssl": {"install": "git clone --depth 1 https://github.com/drwetter/testssl.sh.git /opt/testssl", "check": "test -f /opt/testssl/testssl.sh && echo 'installed'"},
75
+ "gitleaks": {"install": "go install github.com/gitleaks/gitleaks/v8@latest", "check": "gitleaks version"},
76
+ "trufflehog": {"install": "pip3 install trufflehog", "check": "trufflehog --version 2>&1 | head -1"},
77
+ "trivy": {"install": "curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin", "check": "trivy --version"},
78
+ "feroxbuster": {"install": "curl -sL https://raw.githubusercontent.com/epi052/feroxbuster/main/install-nix.sh | bash -s /usr/local/bin", "check": "feroxbuster --version"},
79
+ },
80
+ # Phase 3: EXPLOIT
81
+ "exploit": {
82
+ "sqlmap": {"install": "apt-get install -y sqlmap", "check": "sqlmap --version"},
83
+ "commix": {"install": "pip3 install commix", "check": "commix --version 2>&1 | head -1"},
84
+ "xsstrike": {"install": "pip3 install xsstrike", "check": "xsstrike -h 2>&1 | head -1"},
85
+ "hydra": {"install": "apt-get install -y hydra", "check": "hydra -h 2>&1 | head -1"},
86
+ "searchsploit": {"install": "git clone https://gitlab.com/exploit-database/exploitdb.git /opt/exploitdb && ln -sf /opt/exploitdb/searchsploit /usr/local/bin/", "check": "searchsploit -h 2>&1 | head -1"},
87
+ "metasploit": {"install": "curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > /tmp/msfinstall && chmod 755 /tmp/msfinstall && /tmp/msfinstall", "check": "msfconsole -v"},
88
+ "john": {"install": "apt-get install -y john", "check": "john --version"},
89
+ "hashcat": {"install": "apt-get install -y hashcat", "check": "hashcat --version"},
90
+ },
91
+ # Phase 4: POST-EXPLOIT
92
+ "post_exploit": {
93
+ "linpeas": {"install": "curl -sL https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh -o /opt/linpeas.sh && chmod +x /opt/linpeas.sh", "check": "test -f /opt/linpeas.sh && echo 'installed'"},
94
+ "pspy": {"install": "curl -sL https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64 -o /opt/pspy64 && chmod +x /opt/pspy64", "check": "test -f /opt/pspy64 && echo 'installed'"},
95
+ },
96
+ # API Security
97
+ "api": {
98
+ "arjun": {"install": "pip3 install arjun", "check": "arjun -h 2>&1 | head -1"},
99
+ "kiterunner": {"install": "go install github.com/assetnote/kiterunner/cmd/kr@latest", "check": "kr -h 2>&1 | head -1"},
100
+ "jwt_tool": {"install": "pip3 install jwt_tool", "check": "jwt_tool -h 2>&1 | head -1"},
101
+ },
102
+ # Network
103
+ "network": {
104
+ "masscan": {"install": "apt-get install -y masscan", "check": "masscan --version"},
105
+ "rustscan": {"install": "cargo install rustscan || (wget https://github.com/RustScan/RustScan/releases/latest/download/rustscan_2.1.1_amd64.deb && dpkg -i rustscan_2.1.1_amd64.deb)", "check": "rustscan --version"},
106
+ "naabu": {"install": "go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest", "check": "naabu -version"},
107
+ },
108
+ }
109
+
110
+
111
+ @dataclass
112
+ class VPSSandboxInfo:
113
+ """Information about a VPS execution context."""
114
+ sandbox_id: str
115
+ created_at: datetime = field(default_factory=datetime.now)
116
+ working_dir: str = "/tmp/aiptx"
117
+ results_dir: str = "/tmp/aiptx/results"
118
+ host: str = ""
119
+ is_local: bool = False
120
+ url: str = ""
121
+
122
+
123
+ class VPSRuntime:
124
+ """
125
+ VPS Runtime for remote command execution via SSH.
126
+
127
+ Features:
128
+ - Automatic tool installation
129
+ - Parallel command execution
130
+ - Result retrieval via SCP
131
+ - Connection pooling for performance
132
+ - Automatic reconnection on failure
133
+ """
134
+
135
+ def __init__(
136
+ self,
137
+ host: Optional[str] = None,
138
+ user: Optional[str] = None,
139
+ key_path: Optional[str] = None,
140
+ port: int = 22,
141
+ results_dir: str = "/var/tmp/aiptx_results",
142
+ ):
143
+ """
144
+ Initialize VPS runtime.
145
+
146
+ Args:
147
+ host: VPS hostname or IP
148
+ user: SSH username
149
+ key_path: Path to SSH private key
150
+ port: SSH port
151
+ results_dir: Remote directory for results
152
+ """
153
+ if not ASYNCSSH_AVAILABLE:
154
+ raise ImportError(
155
+ "asyncssh is required for VPS runtime. "
156
+ "Install with: pip install aiptx[full] or pip install asyncssh"
157
+ )
158
+
159
+ # Load from config if not provided
160
+ config = get_config()
161
+ self.host = host or config.vps.host
162
+ self.user = user or config.vps.user
163
+ self.key_path = key_path or config.vps.key_path
164
+ self.port = port or config.vps.port
165
+ self.results_dir = results_dir or config.vps.results_dir
166
+
167
+ # Expand key path
168
+ if self.key_path:
169
+ self.key_path = str(Path(self.key_path).expanduser().resolve())
170
+
171
+ # Connection state
172
+ self._conn: Optional[asyncssh.SSHClientConnection] = None
173
+ self._sandboxes: Dict[str, VPSSandboxInfo] = {}
174
+ self._connected = False
175
+ self._tools_installed = False
176
+
177
+ async def connect(self) -> bool:
178
+ """
179
+ Establish SSH connection to VPS.
180
+
181
+ Returns:
182
+ True if connection successful
183
+ """
184
+ if not self.host:
185
+ raise ValueError("VPS host not configured. Run 'aiptx setup' or set VPS_HOST.")
186
+
187
+ if not self.key_path or not Path(self.key_path).exists():
188
+ raise ValueError(f"SSH key not found: {self.key_path}")
189
+
190
+ try:
191
+ logger.info("Connecting to VPS", host=self.host, user=self.user, port=self.port)
192
+
193
+ self._conn = await asyncssh.connect(
194
+ self.host,
195
+ port=self.port,
196
+ username=self.user,
197
+ client_keys=[self.key_path],
198
+ known_hosts=None, # Skip host key verification (for flexibility)
199
+ )
200
+
201
+ self._connected = True
202
+ logger.info("Connected to VPS successfully", host=self.host)
203
+
204
+ # Create results directory
205
+ await self._run_command(f"mkdir -p {self.results_dir}")
206
+
207
+ return True
208
+
209
+ except Exception as e:
210
+ logger.error("Failed to connect to VPS", host=self.host, error=str(e))
211
+ raise ConnectionError(f"Failed to connect to VPS {self.host}: {e}")
212
+
213
+ async def disconnect(self) -> None:
214
+ """Close SSH connection."""
215
+ if self._conn:
216
+ self._conn.close()
217
+ await self._conn.wait_closed()
218
+ self._conn = None
219
+ self._connected = False
220
+ logger.info("Disconnected from VPS", host=self.host)
221
+
222
+ async def _run_command(
223
+ self,
224
+ command: str,
225
+ timeout: int = 300,
226
+ check: bool = False,
227
+ ) -> Tuple[str, str, int]:
228
+ """
229
+ Run command on VPS.
230
+
231
+ Args:
232
+ command: Shell command to execute
233
+ timeout: Command timeout in seconds
234
+ check: Raise exception on non-zero exit
235
+
236
+ Returns:
237
+ Tuple of (stdout, stderr, exit_code)
238
+ """
239
+ if not self._connected or not self._conn:
240
+ await self.connect()
241
+
242
+ try:
243
+ result = await asyncio.wait_for(
244
+ self._conn.run(command, check=check),
245
+ timeout=timeout
246
+ )
247
+
248
+ return (
249
+ result.stdout or "",
250
+ result.stderr or "",
251
+ result.exit_status or 0
252
+ )
253
+
254
+ except asyncio.TimeoutError:
255
+ logger.warning("Command timed out on VPS", command=command[:50], timeout=timeout)
256
+ return "", f"Command timed out after {timeout}s", 124
257
+ except Exception as e:
258
+ logger.error("Command failed on VPS", command=command[:50], error=str(e))
259
+ return "", str(e), 1
260
+
261
+ async def check_tool_installed(self, tool_name: str) -> bool:
262
+ """Check if a tool is installed on VPS."""
263
+ stdout, stderr, code = await self._run_command(f"which {tool_name} 2>/dev/null || command -v {tool_name} 2>/dev/null")
264
+ return code == 0 and len(stdout.strip()) > 0
265
+
266
+ async def get_installed_tools(self) -> Dict[str, bool]:
267
+ """Get status of all security tools on VPS."""
268
+ results = {}
269
+
270
+ for category, tools in VPS_TOOLS.items():
271
+ for tool_name, tool_info in tools.items():
272
+ check_cmd = tool_info.get("check", f"which {tool_name}")
273
+ stdout, stderr, code = await self._run_command(check_cmd, timeout=10)
274
+ results[tool_name] = code == 0
275
+
276
+ return results
277
+
278
+ async def install_tool(self, tool_name: str, category: str = None) -> bool:
279
+ """
280
+ Install a specific tool on VPS.
281
+
282
+ Args:
283
+ tool_name: Name of tool to install
284
+ category: Tool category (recon, scan, exploit, etc.)
285
+
286
+ Returns:
287
+ True if installation successful
288
+ """
289
+ # Find tool definition
290
+ tool_info = None
291
+ for cat, tools in VPS_TOOLS.items():
292
+ if tool_name in tools:
293
+ tool_info = tools[tool_name]
294
+ break
295
+
296
+ if not tool_info:
297
+ logger.warning(f"Unknown tool: {tool_name}")
298
+ return False
299
+
300
+ install_cmd = tool_info["install"]
301
+ check_cmd = tool_info.get("check", f"which {tool_name}")
302
+
303
+ # Check if already installed
304
+ stdout, stderr, code = await self._run_command(check_cmd, timeout=10)
305
+ if code == 0:
306
+ logger.info(f"Tool already installed: {tool_name}")
307
+ return True
308
+
309
+ # Install
310
+ logger.info(f"Installing tool: {tool_name}")
311
+ stdout, stderr, code = await self._run_command(
312
+ f"sudo {install_cmd}",
313
+ timeout=600 # 10 minute timeout for installation
314
+ )
315
+
316
+ if code != 0:
317
+ logger.error(f"Failed to install {tool_name}", stderr=stderr[:200])
318
+ return False
319
+
320
+ # Verify installation
321
+ stdout, stderr, code = await self._run_command(check_cmd, timeout=10)
322
+ success = code == 0
323
+
324
+ if success:
325
+ logger.info(f"Successfully installed: {tool_name}")
326
+ else:
327
+ logger.error(f"Tool installed but verification failed: {tool_name}")
328
+
329
+ return success
330
+
331
+ async def ensure_tools_installed(
332
+ self,
333
+ categories: Optional[List[str]] = None,
334
+ tools: Optional[List[str]] = None,
335
+ parallel: int = 4,
336
+ ) -> Dict[str, bool]:
337
+ """
338
+ Ensure required security tools are installed on VPS.
339
+
340
+ Args:
341
+ categories: List of categories to install (recon, scan, exploit, etc.)
342
+ tools: Specific tools to install (overrides categories)
343
+ parallel: Number of parallel installations
344
+
345
+ Returns:
346
+ Dict mapping tool names to installation status
347
+ """
348
+ # First, set up base dependencies
349
+ logger.info("Setting up VPS base dependencies...")
350
+
351
+ setup_script = """
352
+ export DEBIAN_FRONTEND=noninteractive
353
+ apt-get update -qq
354
+ apt-get install -y -qq git curl wget python3-pip golang-go ruby-full build-essential libssl-dev libffi-dev
355
+
356
+ # Set up Go path
357
+ export GOPATH=$HOME/go
358
+ export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin
359
+ echo 'export GOPATH=$HOME/go' >> ~/.bashrc
360
+ echo 'export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin' >> ~/.bashrc
361
+ mkdir -p $GOPATH/bin
362
+ """
363
+
364
+ await self._run_command(f"sudo bash -c '{setup_script}'", timeout=300)
365
+
366
+ # Determine which tools to install
367
+ tools_to_install = []
368
+
369
+ if tools:
370
+ tools_to_install = tools
371
+ elif categories:
372
+ for cat in categories:
373
+ if cat in VPS_TOOLS:
374
+ tools_to_install.extend(VPS_TOOLS[cat].keys())
375
+ else:
376
+ # Install all tools
377
+ for cat_tools in VPS_TOOLS.values():
378
+ tools_to_install.extend(cat_tools.keys())
379
+
380
+ # Install tools in parallel batches
381
+ results = {}
382
+
383
+ for i in range(0, len(tools_to_install), parallel):
384
+ batch = tools_to_install[i:i + parallel]
385
+ tasks = [self.install_tool(tool) for tool in batch]
386
+ batch_results = await asyncio.gather(*tasks, return_exceptions=True)
387
+
388
+ for tool, result in zip(batch, batch_results):
389
+ if isinstance(result, Exception):
390
+ results[tool] = False
391
+ logger.error(f"Failed to install {tool}: {result}")
392
+ else:
393
+ results[tool] = result
394
+
395
+ self._tools_installed = True
396
+
397
+ # Summary
398
+ installed = sum(1 for v in results.values() if v)
399
+ failed = sum(1 for v in results.values() if not v)
400
+ logger.info(f"Tool installation complete: {installed} installed, {failed} failed")
401
+
402
+ return results
403
+
404
+ async def create_sandbox(
405
+ self,
406
+ working_dir: Optional[str] = None,
407
+ **kwargs
408
+ ) -> VPSSandboxInfo:
409
+ """
410
+ Create a VPS execution context (sandbox).
411
+
412
+ Args:
413
+ working_dir: Working directory on VPS
414
+
415
+ Returns:
416
+ VPSSandboxInfo with sandbox details
417
+ """
418
+ if not self._connected:
419
+ await self.connect()
420
+
421
+ sandbox_id = f"vps-{uuid.uuid4().hex[:8]}"
422
+ work_dir = working_dir or f"/tmp/aiptx/{sandbox_id}"
423
+ results_dir = f"{work_dir}/results"
424
+
425
+ # Create directories on VPS
426
+ await self._run_command(f"mkdir -p {work_dir} {results_dir}")
427
+
428
+ info = VPSSandboxInfo(
429
+ sandbox_id=sandbox_id,
430
+ working_dir=work_dir,
431
+ results_dir=results_dir,
432
+ host=self.host,
433
+ url=f"ssh://{self.user}@{self.host}:{self.port}",
434
+ )
435
+
436
+ self._sandboxes[sandbox_id] = info
437
+ logger.info("Created VPS sandbox", sandbox_id=sandbox_id, host=self.host)
438
+
439
+ return info
440
+
441
+ async def execute(
442
+ self,
443
+ sandbox_id: str,
444
+ command: str,
445
+ timeout: int = 300,
446
+ env: Optional[Dict[str, str]] = None,
447
+ save_output: bool = True,
448
+ ) -> Tuple[str, str, int]:
449
+ """
450
+ Execute command in VPS sandbox.
451
+
452
+ Args:
453
+ sandbox_id: Sandbox identifier
454
+ command: Shell command to execute
455
+ timeout: Command timeout in seconds
456
+ env: Additional environment variables
457
+ save_output: Save output to results directory
458
+
459
+ Returns:
460
+ Tuple of (stdout, stderr, exit_code)
461
+ """
462
+ if sandbox_id not in self._sandboxes:
463
+ raise ValueError(f"Unknown sandbox: {sandbox_id}")
464
+
465
+ sandbox = self._sandboxes[sandbox_id]
466
+
467
+ # Build command with environment
468
+ env_prefix = ""
469
+ if env:
470
+ env_prefix = " ".join(f"{k}={v}" for k, v in env.items()) + " "
471
+
472
+ # Add Go path to environment
473
+ full_command = f"""
474
+ export PATH=$PATH:$HOME/go/bin:/usr/local/go/bin
475
+ cd {sandbox.working_dir}
476
+ {env_prefix}{command}
477
+ """
478
+
479
+ logger.debug(
480
+ "Executing on VPS",
481
+ sandbox_id=sandbox_id,
482
+ command=command[:100] + "..." if len(command) > 100 else command,
483
+ )
484
+
485
+ stdout, stderr, code = await self._run_command(full_command, timeout=timeout)
486
+
487
+ # Save output to results directory
488
+ if save_output:
489
+ output_id = uuid.uuid4().hex[:8]
490
+ output_file = f"{sandbox.results_dir}/output_{output_id}.json"
491
+ output_data = {
492
+ "command": command,
493
+ "stdout": stdout,
494
+ "stderr": stderr,
495
+ "exit_code": code,
496
+ "timestamp": datetime.now().isoformat(),
497
+ }
498
+ await self._run_command(
499
+ f"echo '{json.dumps(output_data)}' > {output_file}",
500
+ timeout=10
501
+ )
502
+
503
+ return stdout, stderr, code
504
+
505
+ async def retrieve_results(
506
+ self,
507
+ sandbox_id: str,
508
+ local_dir: Optional[str] = None,
509
+ ) -> Path:
510
+ """
511
+ Retrieve results from VPS to local machine.
512
+
513
+ Args:
514
+ sandbox_id: Sandbox identifier
515
+ local_dir: Local directory to save results
516
+
517
+ Returns:
518
+ Path to local results directory
519
+ """
520
+ if sandbox_id not in self._sandboxes:
521
+ raise ValueError(f"Unknown sandbox: {sandbox_id}")
522
+
523
+ sandbox = self._sandboxes[sandbox_id]
524
+
525
+ # Default local directory
526
+ if local_dir is None:
527
+ local_dir = Path(f"./results/{sandbox_id}")
528
+ else:
529
+ local_dir = Path(local_dir)
530
+
531
+ local_dir.mkdir(parents=True, exist_ok=True)
532
+
533
+ # Use SCP to retrieve results
534
+ logger.info("Retrieving results from VPS", sandbox_id=sandbox_id, local_dir=str(local_dir))
535
+
536
+ async with self._conn.start_sftp_client() as sftp:
537
+ # List remote files
538
+ try:
539
+ files = await sftp.listdir(sandbox.results_dir)
540
+
541
+ for filename in files:
542
+ remote_path = f"{sandbox.results_dir}/{filename}"
543
+ local_path = local_dir / filename
544
+
545
+ await sftp.get(remote_path, str(local_path))
546
+ logger.debug(f"Retrieved: {filename}")
547
+
548
+ logger.info(f"Retrieved {len(files)} files from VPS")
549
+
550
+ except Exception as e:
551
+ logger.error(f"Failed to retrieve results: {e}")
552
+
553
+ return local_dir
554
+
555
+ async def destroy_sandbox(self, sandbox_id: str) -> None:
556
+ """
557
+ Destroy VPS sandbox and cleanup.
558
+
559
+ Args:
560
+ sandbox_id: Sandbox identifier
561
+ """
562
+ if sandbox_id not in self._sandboxes:
563
+ return
564
+
565
+ sandbox = self._sandboxes[sandbox_id]
566
+
567
+ # Cleanup remote directory
568
+ await self._run_command(f"rm -rf {sandbox.working_dir}", timeout=30)
569
+
570
+ del self._sandboxes[sandbox_id]
571
+ logger.info("Destroyed VPS sandbox", sandbox_id=sandbox_id)
572
+
573
+ async def run_scan(
574
+ self,
575
+ target: str,
576
+ scan_type: str = "full",
577
+ tools: Optional[List[str]] = None,
578
+ ) -> Dict[str, Any]:
579
+ """
580
+ Run a complete scan on target using VPS.
581
+
582
+ Args:
583
+ target: Target URL or IP
584
+ scan_type: Type of scan (quick, standard, full)
585
+ tools: Specific tools to use
586
+
587
+ Returns:
588
+ Dict with scan results
589
+ """
590
+ sandbox = await self.create_sandbox()
591
+ results = {
592
+ "target": target,
593
+ "scan_type": scan_type,
594
+ "sandbox_id": sandbox.sandbox_id,
595
+ "started_at": datetime.now().isoformat(),
596
+ "findings": [],
597
+ "tool_outputs": {},
598
+ }
599
+
600
+ try:
601
+ # Determine tools to run based on scan type
602
+ if tools:
603
+ tools_to_run = tools
604
+ elif scan_type == "quick":
605
+ tools_to_run = ["nmap", "httpx", "nuclei"]
606
+ elif scan_type == "standard":
607
+ tools_to_run = ["nmap", "httpx", "nuclei", "ffuf", "nikto", "sslscan"]
608
+ else: # full
609
+ tools_to_run = [
610
+ "subfinder", "httpx", "nmap", "nuclei", "nikto",
611
+ "ffuf", "sslscan", "whatweb", "wafw00f"
612
+ ]
613
+
614
+ # Run each tool
615
+ for tool in tools_to_run:
616
+ logger.info(f"Running {tool} on {target}")
617
+
618
+ cmd = self._get_tool_command(tool, target, sandbox.results_dir)
619
+ if cmd:
620
+ stdout, stderr, code = await self.execute(
621
+ sandbox.sandbox_id,
622
+ cmd,
623
+ timeout=600
624
+ )
625
+
626
+ results["tool_outputs"][tool] = {
627
+ "stdout": stdout,
628
+ "stderr": stderr,
629
+ "exit_code": code,
630
+ }
631
+
632
+ # Retrieve results
633
+ local_results = await self.retrieve_results(sandbox.sandbox_id)
634
+ results["local_results_path"] = str(local_results)
635
+ results["completed_at"] = datetime.now().isoformat()
636
+
637
+ finally:
638
+ await self.destroy_sandbox(sandbox.sandbox_id)
639
+
640
+ return results
641
+
642
+ def _get_tool_command(self, tool: str, target: str, output_dir: str) -> Optional[str]:
643
+ """Get command for running a specific tool."""
644
+ commands = {
645
+ "nmap": f"nmap -sV -sC -oA {output_dir}/nmap_{target.replace('.', '_')} {target}",
646
+ "subfinder": f"subfinder -d {target} -o {output_dir}/subfinder.txt",
647
+ "httpx": f"echo {target} | httpx -json -o {output_dir}/httpx.json",
648
+ "nuclei": f"nuclei -u {target} -json -o {output_dir}/nuclei.json",
649
+ "nikto": f"nikto -h {target} -o {output_dir}/nikto.txt",
650
+ "ffuf": f"ffuf -u {target}/FUZZ -w /usr/share/wordlists/dirb/common.txt -o {output_dir}/ffuf.json -of json",
651
+ "sslscan": f"sslscan {target} > {output_dir}/sslscan.txt",
652
+ "whatweb": f"whatweb {target} --log-json={output_dir}/whatweb.json",
653
+ "wafw00f": f"wafw00f {target} -o {output_dir}/wafw00f.txt",
654
+ "gobuster": f"gobuster dir -u {target} -w /usr/share/wordlists/dirb/common.txt -o {output_dir}/gobuster.txt",
655
+ "dirsearch": f"dirsearch -u {target} --json-report={output_dir}/dirsearch.json",
656
+ }
657
+
658
+ return commands.get(tool)
659
+
660
+ async def cleanup_all(self) -> int:
661
+ """Cleanup all sandboxes and disconnect."""
662
+ count = len(self._sandboxes)
663
+
664
+ for sandbox_id in list(self._sandboxes.keys()):
665
+ await self.destroy_sandbox(sandbox_id)
666
+
667
+ await self.disconnect()
668
+
669
+ return count
670
+
671
+
672
+ # =============================================================================
673
+ # VPS Setup Script Generator
674
+ # =============================================================================
675
+
676
+ def generate_vps_setup_script(
677
+ categories: Optional[List[str]] = None,
678
+ include_wordlists: bool = True,
679
+ ) -> str:
680
+ """
681
+ Generate a bash script for setting up a VPS with security tools.
682
+
683
+ Args:
684
+ categories: Tool categories to include (default: all)
685
+ include_wordlists: Include common wordlists
686
+
687
+ Returns:
688
+ Bash script as string
689
+ """
690
+ script = '''#!/bin/bash
691
+ # =============================================================================
692
+ # AIPTX VPS Setup Script
693
+ # =============================================================================
694
+ # This script installs security tools for penetration testing.
695
+ # Run as root or with sudo.
696
+ #
697
+ # Usage: curl -sL https://raw.githubusercontent.com/aiptx/aipt_v2/main/scripts/setup-vps.sh | sudo bash
698
+ # =============================================================================
699
+
700
+ set -e
701
+ export DEBIAN_FRONTEND=noninteractive
702
+
703
+ echo "[*] AIPTX VPS Setup Starting..."
704
+ echo "[*] This may take 10-30 minutes depending on your VPS."
705
+
706
+ # =============================================================================
707
+ # Base Dependencies
708
+ # =============================================================================
709
+ echo "[+] Installing base dependencies..."
710
+ apt-get update -qq
711
+ apt-get install -y -qq \\
712
+ git curl wget unzip \\
713
+ python3 python3-pip python3-venv \\
714
+ golang-go ruby-full gem \\
715
+ build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev \\
716
+ nmap nikto sqlmap hydra john hashcat masscan \\
717
+ jq tmux screen htop
718
+
719
+ # =============================================================================
720
+ # Go Setup
721
+ # =============================================================================
722
+ echo "[+] Setting up Go environment..."
723
+ export GOPATH=$HOME/go
724
+ export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin
725
+ mkdir -p $GOPATH/bin
726
+
727
+ cat >> ~/.bashrc << 'EOF'
728
+ export GOPATH=$HOME/go
729
+ export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin
730
+ EOF
731
+
732
+ # =============================================================================
733
+ # Security Tools
734
+ # =============================================================================
735
+ '''
736
+
737
+ cats = categories or list(VPS_TOOLS.keys())
738
+
739
+ for category in cats:
740
+ if category not in VPS_TOOLS:
741
+ continue
742
+
743
+ script += f'\necho "[+] Installing {category.upper()} tools..."\n'
744
+
745
+ for tool_name, tool_info in VPS_TOOLS[category].items():
746
+ install_cmd = tool_info["install"]
747
+ # Escape single quotes for bash
748
+ install_cmd = install_cmd.replace("'", "'\\''")
749
+ script += f"echo ' - Installing {tool_name}...'\n"
750
+ script += f"{install_cmd} || echo ' [!] Failed to install {tool_name}'\n"
751
+
752
+ if include_wordlists:
753
+ script += '''
754
+ # =============================================================================
755
+ # Wordlists
756
+ # =============================================================================
757
+ echo "[+] Setting up wordlists..."
758
+ mkdir -p /usr/share/wordlists
759
+
760
+ # SecLists
761
+ if [ ! -d "/usr/share/wordlists/SecLists" ]; then
762
+ git clone --depth 1 https://github.com/danielmiessler/SecLists.git /usr/share/wordlists/SecLists
763
+ fi
764
+
765
+ # Common wordlists links
766
+ ln -sf /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt /usr/share/wordlists/common.txt
767
+ ln -sf /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt /usr/share/wordlists/medium.txt
768
+ ln -sf /usr/share/wordlists/SecLists/Passwords/Common-Credentials/10k-most-common.txt /usr/share/wordlists/passwords.txt
769
+ '''
770
+
771
+ script += '''
772
+ # =============================================================================
773
+ # AIPTX Results Directory
774
+ # =============================================================================
775
+ echo "[+] Creating AIPTX directories..."
776
+ mkdir -p /var/tmp/aiptx_results
777
+ chmod 700 /var/tmp/aiptx_results
778
+
779
+ # =============================================================================
780
+ # Complete
781
+ # =============================================================================
782
+ echo ""
783
+ echo "=============================================="
784
+ echo "[*] AIPTX VPS Setup Complete!"
785
+ echo "=============================================="
786
+ echo ""
787
+ echo "Installed tools can be verified with:"
788
+ echo " which nmap nuclei subfinder httpx ffuf"
789
+ echo ""
790
+ echo "Ready for AIPTX connection."
791
+ echo "=============================================="
792
+ '''
793
+
794
+ return script
795
+
796
+
797
+ # =============================================================================
798
+ # Convenience Functions
799
+ # =============================================================================
800
+
801
+ _default_vps_runtime: Optional[VPSRuntime] = None
802
+
803
+
804
+ async def get_vps_runtime() -> VPSRuntime:
805
+ """Get or create the default VPS runtime instance."""
806
+ global _default_vps_runtime
807
+ if _default_vps_runtime is None:
808
+ _default_vps_runtime = VPSRuntime()
809
+ await _default_vps_runtime.connect()
810
+ return _default_vps_runtime
811
+
812
+
813
+ async def run_on_vps(command: str, timeout: int = 300) -> Tuple[str, str, int]:
814
+ """
815
+ Convenience function to run a command on VPS.
816
+
817
+ Args:
818
+ command: Shell command to execute
819
+ timeout: Command timeout
820
+
821
+ Returns:
822
+ Tuple of (stdout, stderr, exit_code)
823
+ """
824
+ runtime = await get_vps_runtime()
825
+ sandbox = await runtime.create_sandbox()
826
+
827
+ try:
828
+ return await runtime.execute(sandbox.sandbox_id, command, timeout)
829
+ finally:
830
+ await runtime.destroy_sandbox(sandbox.sandbox_id)