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.
- aipt_v2/__init__.py +110 -0
- aipt_v2/__main__.py +24 -0
- aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
- aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
- aipt_v2/agents/__init__.py +46 -0
- aipt_v2/agents/base.py +520 -0
- aipt_v2/agents/exploit_agent.py +688 -0
- aipt_v2/agents/ptt.py +406 -0
- aipt_v2/agents/state.py +168 -0
- aipt_v2/app.py +957 -0
- aipt_v2/browser/__init__.py +31 -0
- aipt_v2/browser/automation.py +458 -0
- aipt_v2/browser/crawler.py +453 -0
- aipt_v2/cli.py +2933 -0
- aipt_v2/compliance/__init__.py +71 -0
- aipt_v2/compliance/compliance_report.py +449 -0
- aipt_v2/compliance/framework_mapper.py +424 -0
- aipt_v2/compliance/nist_mapping.py +345 -0
- aipt_v2/compliance/owasp_mapping.py +330 -0
- aipt_v2/compliance/pci_mapping.py +297 -0
- aipt_v2/config.py +341 -0
- aipt_v2/core/__init__.py +43 -0
- aipt_v2/core/agent.py +630 -0
- aipt_v2/core/llm.py +395 -0
- aipt_v2/core/memory.py +305 -0
- aipt_v2/core/ptt.py +329 -0
- aipt_v2/database/__init__.py +14 -0
- aipt_v2/database/models.py +232 -0
- aipt_v2/database/repository.py +384 -0
- aipt_v2/docker/__init__.py +23 -0
- aipt_v2/docker/builder.py +260 -0
- aipt_v2/docker/manager.py +222 -0
- aipt_v2/docker/sandbox.py +371 -0
- aipt_v2/evasion/__init__.py +58 -0
- aipt_v2/evasion/request_obfuscator.py +272 -0
- aipt_v2/evasion/tls_fingerprint.py +285 -0
- aipt_v2/evasion/ua_rotator.py +301 -0
- aipt_v2/evasion/waf_bypass.py +439 -0
- aipt_v2/execution/__init__.py +23 -0
- aipt_v2/execution/executor.py +302 -0
- aipt_v2/execution/parser.py +544 -0
- aipt_v2/execution/terminal.py +337 -0
- aipt_v2/health.py +437 -0
- aipt_v2/intelligence/__init__.py +194 -0
- aipt_v2/intelligence/adaptation.py +474 -0
- aipt_v2/intelligence/auth.py +520 -0
- aipt_v2/intelligence/chaining.py +775 -0
- aipt_v2/intelligence/correlation.py +536 -0
- aipt_v2/intelligence/cve_aipt.py +334 -0
- aipt_v2/intelligence/cve_info.py +1111 -0
- aipt_v2/intelligence/knowledge_graph.py +590 -0
- aipt_v2/intelligence/learning.py +626 -0
- aipt_v2/intelligence/llm_analyzer.py +502 -0
- aipt_v2/intelligence/llm_tool_selector.py +518 -0
- aipt_v2/intelligence/payload_generator.py +562 -0
- aipt_v2/intelligence/rag.py +239 -0
- aipt_v2/intelligence/scope.py +442 -0
- aipt_v2/intelligence/searchers/__init__.py +5 -0
- aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
- aipt_v2/intelligence/searchers/github_searcher.py +467 -0
- aipt_v2/intelligence/searchers/google_searcher.py +281 -0
- aipt_v2/intelligence/tools.json +443 -0
- aipt_v2/intelligence/triage.py +670 -0
- aipt_v2/interactive_shell.py +559 -0
- aipt_v2/interface/__init__.py +5 -0
- aipt_v2/interface/cli.py +230 -0
- aipt_v2/interface/main.py +501 -0
- aipt_v2/interface/tui.py +1276 -0
- aipt_v2/interface/utils.py +583 -0
- aipt_v2/llm/__init__.py +39 -0
- aipt_v2/llm/config.py +26 -0
- aipt_v2/llm/llm.py +514 -0
- aipt_v2/llm/memory.py +214 -0
- aipt_v2/llm/request_queue.py +89 -0
- aipt_v2/llm/utils.py +89 -0
- aipt_v2/local_tool_installer.py +1467 -0
- aipt_v2/models/__init__.py +15 -0
- aipt_v2/models/findings.py +295 -0
- aipt_v2/models/phase_result.py +224 -0
- aipt_v2/models/scan_config.py +207 -0
- aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
- aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
- aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
- aipt_v2/monitoring/prometheus.yml +60 -0
- aipt_v2/orchestration/__init__.py +52 -0
- aipt_v2/orchestration/pipeline.py +398 -0
- aipt_v2/orchestration/progress.py +300 -0
- aipt_v2/orchestration/scheduler.py +296 -0
- aipt_v2/orchestrator.py +2427 -0
- aipt_v2/payloads/__init__.py +27 -0
- aipt_v2/payloads/cmdi.py +150 -0
- aipt_v2/payloads/sqli.py +263 -0
- aipt_v2/payloads/ssrf.py +204 -0
- aipt_v2/payloads/templates.py +222 -0
- aipt_v2/payloads/traversal.py +166 -0
- aipt_v2/payloads/xss.py +204 -0
- aipt_v2/prompts/__init__.py +60 -0
- aipt_v2/proxy/__init__.py +29 -0
- aipt_v2/proxy/history.py +352 -0
- aipt_v2/proxy/interceptor.py +452 -0
- aipt_v2/recon/__init__.py +44 -0
- aipt_v2/recon/dns.py +241 -0
- aipt_v2/recon/osint.py +367 -0
- aipt_v2/recon/subdomain.py +372 -0
- aipt_v2/recon/tech_detect.py +311 -0
- aipt_v2/reports/__init__.py +17 -0
- aipt_v2/reports/generator.py +313 -0
- aipt_v2/reports/html_report.py +378 -0
- aipt_v2/runtime/__init__.py +53 -0
- aipt_v2/runtime/base.py +30 -0
- aipt_v2/runtime/docker.py +401 -0
- aipt_v2/runtime/local.py +346 -0
- aipt_v2/runtime/tool_server.py +205 -0
- aipt_v2/runtime/vps.py +830 -0
- aipt_v2/scanners/__init__.py +28 -0
- aipt_v2/scanners/base.py +273 -0
- aipt_v2/scanners/nikto.py +244 -0
- aipt_v2/scanners/nmap.py +402 -0
- aipt_v2/scanners/nuclei.py +273 -0
- aipt_v2/scanners/web.py +454 -0
- aipt_v2/scripts/security_audit.py +366 -0
- aipt_v2/setup_wizard.py +941 -0
- aipt_v2/skills/__init__.py +80 -0
- aipt_v2/skills/agents/__init__.py +14 -0
- aipt_v2/skills/agents/api_tester.py +706 -0
- aipt_v2/skills/agents/base.py +477 -0
- aipt_v2/skills/agents/code_review.py +459 -0
- aipt_v2/skills/agents/security_agent.py +336 -0
- aipt_v2/skills/agents/web_pentest.py +818 -0
- aipt_v2/skills/prompts/__init__.py +647 -0
- aipt_v2/system_detector.py +539 -0
- aipt_v2/telemetry/__init__.py +7 -0
- aipt_v2/telemetry/tracer.py +347 -0
- aipt_v2/terminal/__init__.py +28 -0
- aipt_v2/terminal/executor.py +400 -0
- aipt_v2/terminal/sandbox.py +350 -0
- aipt_v2/tools/__init__.py +44 -0
- aipt_v2/tools/active_directory/__init__.py +78 -0
- aipt_v2/tools/active_directory/ad_config.py +238 -0
- aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
- aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
- aipt_v2/tools/active_directory/ldap_enum.py +533 -0
- aipt_v2/tools/active_directory/smb_attacks.py +505 -0
- aipt_v2/tools/agents_graph/__init__.py +19 -0
- aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
- aipt_v2/tools/api_security/__init__.py +76 -0
- aipt_v2/tools/api_security/api_discovery.py +608 -0
- aipt_v2/tools/api_security/graphql_scanner.py +622 -0
- aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
- aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
- aipt_v2/tools/browser/__init__.py +5 -0
- aipt_v2/tools/browser/browser_actions.py +238 -0
- aipt_v2/tools/browser/browser_instance.py +535 -0
- aipt_v2/tools/browser/tab_manager.py +344 -0
- aipt_v2/tools/cloud/__init__.py +70 -0
- aipt_v2/tools/cloud/cloud_config.py +273 -0
- aipt_v2/tools/cloud/cloud_scanner.py +639 -0
- aipt_v2/tools/cloud/prowler_tool.py +571 -0
- aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
- aipt_v2/tools/executor.py +307 -0
- aipt_v2/tools/parser.py +408 -0
- aipt_v2/tools/proxy/__init__.py +5 -0
- aipt_v2/tools/proxy/proxy_actions.py +103 -0
- aipt_v2/tools/proxy/proxy_manager.py +789 -0
- aipt_v2/tools/registry.py +196 -0
- aipt_v2/tools/scanners/__init__.py +343 -0
- aipt_v2/tools/scanners/acunetix_tool.py +712 -0
- aipt_v2/tools/scanners/burp_tool.py +631 -0
- aipt_v2/tools/scanners/config.py +156 -0
- aipt_v2/tools/scanners/nessus_tool.py +588 -0
- aipt_v2/tools/scanners/zap_tool.py +612 -0
- aipt_v2/tools/terminal/__init__.py +5 -0
- aipt_v2/tools/terminal/terminal_actions.py +37 -0
- aipt_v2/tools/terminal/terminal_manager.py +153 -0
- aipt_v2/tools/terminal/terminal_session.py +449 -0
- aipt_v2/tools/tool_processing.py +108 -0
- aipt_v2/utils/__init__.py +17 -0
- aipt_v2/utils/logging.py +202 -0
- aipt_v2/utils/model_manager.py +187 -0
- aipt_v2/utils/searchers/__init__.py +269 -0
- aipt_v2/verify_install.py +793 -0
- aiptx-2.0.7.dist-info/METADATA +345 -0
- aiptx-2.0.7.dist-info/RECORD +187 -0
- aiptx-2.0.7.dist-info/WHEEL +5 -0
- aiptx-2.0.7.dist-info/entry_points.txt +7 -0
- aiptx-2.0.7.dist-info/licenses/LICENSE +21 -0
- 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)
|