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
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIPT Container Manager - Manages multiple sandbox configurations
|
|
3
|
+
|
|
4
|
+
Provides pre-configured sandboxes for different use cases:
|
|
5
|
+
- Recon tools (nmap, masscan)
|
|
6
|
+
- Web tools (nuclei, httpx)
|
|
7
|
+
- Exploitation (metasploit)
|
|
8
|
+
- Post-exploitation (linpeas)
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Optional, Dict, List
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from enum import Enum
|
|
15
|
+
|
|
16
|
+
from .sandbox import DockerSandbox, SandboxConfig, SandboxResult
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SecurityImage(str, Enum):
|
|
20
|
+
"""Pre-defined security tool images"""
|
|
21
|
+
KALI = "kalilinux/kali-rolling"
|
|
22
|
+
NMAP = "instrumentisto/nmap"
|
|
23
|
+
NUCLEI = "projectdiscovery/nuclei"
|
|
24
|
+
HTTPX = "projectdiscovery/httpx"
|
|
25
|
+
SUBFINDER = "projectdiscovery/subfinder"
|
|
26
|
+
MASSCAN = "adarnimrod/masscan"
|
|
27
|
+
METASPLOIT = "metasploitframework/metasploit-framework"
|
|
28
|
+
SQLMAP = "paoloo/sqlmap"
|
|
29
|
+
NIKTO = "sullo/nikto"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class PhaseConfig:
|
|
34
|
+
"""Configuration for a pentest phase"""
|
|
35
|
+
memory_limit: str = "1g"
|
|
36
|
+
cpu_limit: float = 2.0
|
|
37
|
+
timeout: int = 600
|
|
38
|
+
network_mode: str = "bridge"
|
|
39
|
+
capabilities: List[str] = field(default_factory=list)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ContainerManager:
|
|
43
|
+
"""
|
|
44
|
+
Manages multiple sandbox configurations for different use cases.
|
|
45
|
+
|
|
46
|
+
Provides pre-configured sandboxes for:
|
|
47
|
+
- Recon tools (nmap, masscan)
|
|
48
|
+
- Web tools (nuclei, httpx)
|
|
49
|
+
- Exploitation (metasploit)
|
|
50
|
+
- Post-exploitation (linpeas)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Tool to image mapping
|
|
54
|
+
TOOL_IMAGES: Dict[str, SecurityImage] = {
|
|
55
|
+
"nmap": SecurityImage.NMAP,
|
|
56
|
+
"masscan": SecurityImage.MASSCAN,
|
|
57
|
+
"nuclei": SecurityImage.NUCLEI,
|
|
58
|
+
"httpx": SecurityImage.HTTPX,
|
|
59
|
+
"subfinder": SecurityImage.SUBFINDER,
|
|
60
|
+
"metasploit": SecurityImage.METASPLOIT,
|
|
61
|
+
"msfconsole": SecurityImage.METASPLOIT,
|
|
62
|
+
"sqlmap": SecurityImage.SQLMAP,
|
|
63
|
+
"nikto": SecurityImage.NIKTO,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Phase configurations
|
|
67
|
+
PHASE_CONFIGS: Dict[str, PhaseConfig] = {
|
|
68
|
+
"recon": PhaseConfig(
|
|
69
|
+
memory_limit="1g",
|
|
70
|
+
cpu_limit=2.0,
|
|
71
|
+
timeout=600,
|
|
72
|
+
network_mode="bridge",
|
|
73
|
+
capabilities=["NET_RAW"],
|
|
74
|
+
),
|
|
75
|
+
"enum": PhaseConfig(
|
|
76
|
+
memory_limit="2g",
|
|
77
|
+
cpu_limit=2.0,
|
|
78
|
+
timeout=900,
|
|
79
|
+
network_mode="bridge",
|
|
80
|
+
),
|
|
81
|
+
"exploit": PhaseConfig(
|
|
82
|
+
memory_limit="4g",
|
|
83
|
+
cpu_limit=4.0,
|
|
84
|
+
timeout=1800,
|
|
85
|
+
network_mode="host", # May need host network for reverse shells
|
|
86
|
+
),
|
|
87
|
+
"post": PhaseConfig(
|
|
88
|
+
memory_limit="2g",
|
|
89
|
+
cpu_limit=2.0,
|
|
90
|
+
timeout=600,
|
|
91
|
+
network_mode="none", # Isolated for safety
|
|
92
|
+
),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
def __init__(self, default_image: str = SecurityImage.KALI.value):
|
|
96
|
+
self.default_image = default_image
|
|
97
|
+
self.sandboxes: Dict[str, DockerSandbox] = {}
|
|
98
|
+
self._active_containers: List[str] = []
|
|
99
|
+
|
|
100
|
+
def get_sandbox(self, phase: str = "recon") -> DockerSandbox:
|
|
101
|
+
"""Get or create sandbox for phase"""
|
|
102
|
+
if phase not in self.sandboxes:
|
|
103
|
+
phase_config = self.PHASE_CONFIGS.get(phase, PhaseConfig())
|
|
104
|
+
|
|
105
|
+
config = SandboxConfig(
|
|
106
|
+
image=self.default_image,
|
|
107
|
+
memory_limit=phase_config.memory_limit,
|
|
108
|
+
cpu_limit=phase_config.cpu_limit,
|
|
109
|
+
timeout=phase_config.timeout,
|
|
110
|
+
network_mode=phase_config.network_mode,
|
|
111
|
+
capabilities=phase_config.capabilities,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
self.sandboxes[phase] = DockerSandbox(config)
|
|
115
|
+
|
|
116
|
+
return self.sandboxes[phase]
|
|
117
|
+
|
|
118
|
+
def get_image_for_tool(self, tool_name: str) -> str:
|
|
119
|
+
"""Get appropriate Docker image for tool"""
|
|
120
|
+
tool_lower = tool_name.lower()
|
|
121
|
+
|
|
122
|
+
# Check direct mapping
|
|
123
|
+
if tool_lower in self.TOOL_IMAGES:
|
|
124
|
+
return self.TOOL_IMAGES[tool_lower].value
|
|
125
|
+
|
|
126
|
+
# Check partial match
|
|
127
|
+
for key, image in self.TOOL_IMAGES.items():
|
|
128
|
+
if key in tool_lower:
|
|
129
|
+
return image.value
|
|
130
|
+
|
|
131
|
+
# Default to Kali for unknown tools
|
|
132
|
+
return self.default_image
|
|
133
|
+
|
|
134
|
+
def execute_tool(
|
|
135
|
+
self,
|
|
136
|
+
tool_name: str,
|
|
137
|
+
command: str,
|
|
138
|
+
phase: str = "recon",
|
|
139
|
+
**kwargs,
|
|
140
|
+
) -> SandboxResult:
|
|
141
|
+
"""
|
|
142
|
+
Execute a security tool in appropriate sandbox.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
tool_name: Name of the tool
|
|
146
|
+
command: Full command to execute
|
|
147
|
+
phase: Pentest phase (recon, enum, exploit, post)
|
|
148
|
+
**kwargs: Additional sandbox options
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
SandboxResult
|
|
152
|
+
"""
|
|
153
|
+
sandbox = self.get_sandbox(phase)
|
|
154
|
+
image = self.get_image_for_tool(tool_name)
|
|
155
|
+
return sandbox.execute(command, image=image, **kwargs)
|
|
156
|
+
|
|
157
|
+
def execute_with_callback(
|
|
158
|
+
self,
|
|
159
|
+
tool_name: str,
|
|
160
|
+
command: str,
|
|
161
|
+
callback,
|
|
162
|
+
phase: str = "recon",
|
|
163
|
+
) -> SandboxResult:
|
|
164
|
+
"""Execute tool with streaming output callback"""
|
|
165
|
+
sandbox = self.get_sandbox(phase)
|
|
166
|
+
image = self.get_image_for_tool(tool_name)
|
|
167
|
+
return sandbox.execute_streaming(command, callback, image=image)
|
|
168
|
+
|
|
169
|
+
def is_available(self) -> bool:
|
|
170
|
+
"""Check if Docker is available"""
|
|
171
|
+
sandbox = self.get_sandbox("recon")
|
|
172
|
+
return sandbox.is_available()
|
|
173
|
+
|
|
174
|
+
def pull_security_images(self, images: Optional[List[SecurityImage]] = None) -> Dict[str, bool]:
|
|
175
|
+
"""
|
|
176
|
+
Pull security tool images.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
images: List of images to pull (pulls all if None)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Dict mapping image name to success status
|
|
183
|
+
"""
|
|
184
|
+
images_to_pull = images or list(SecurityImage)
|
|
185
|
+
results = {}
|
|
186
|
+
|
|
187
|
+
sandbox = DockerSandbox()
|
|
188
|
+
|
|
189
|
+
for image in images_to_pull:
|
|
190
|
+
image_name = image.value if isinstance(image, SecurityImage) else image
|
|
191
|
+
results[image_name] = sandbox.pull_image(image_name)
|
|
192
|
+
|
|
193
|
+
return results
|
|
194
|
+
|
|
195
|
+
def list_pulled_images(self) -> List[str]:
|
|
196
|
+
"""List pulled security images"""
|
|
197
|
+
sandbox = DockerSandbox()
|
|
198
|
+
pulled = []
|
|
199
|
+
|
|
200
|
+
for image in SecurityImage:
|
|
201
|
+
if sandbox.image_exists(image.value):
|
|
202
|
+
pulled.append(image.value)
|
|
203
|
+
|
|
204
|
+
return pulled
|
|
205
|
+
|
|
206
|
+
def cleanup(self) -> None:
|
|
207
|
+
"""Cleanup all sandboxes and containers"""
|
|
208
|
+
for sandbox in self.sandboxes.values():
|
|
209
|
+
sandbox.cleanup_containers()
|
|
210
|
+
self.sandboxes.clear()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# Singleton instance
|
|
214
|
+
_container_manager: Optional[ContainerManager] = None
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def get_container_manager() -> ContainerManager:
|
|
218
|
+
"""Get singleton container manager"""
|
|
219
|
+
global _container_manager
|
|
220
|
+
if _container_manager is None:
|
|
221
|
+
_container_manager = ContainerManager()
|
|
222
|
+
return _container_manager
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIPT Docker Sandbox - Secure command execution in containers
|
|
3
|
+
|
|
4
|
+
Provides isolated execution environment for security tools:
|
|
5
|
+
- Network-isolated containers
|
|
6
|
+
- Resource limits (CPU, memory)
|
|
7
|
+
- Timeout enforcement
|
|
8
|
+
- Output capture and streaming
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import subprocess
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import time
|
|
16
|
+
import asyncio
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Optional, List, Dict, Any, Callable
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class SandboxResult:
|
|
24
|
+
"""Result from sandbox execution"""
|
|
25
|
+
output: str
|
|
26
|
+
return_code: int
|
|
27
|
+
duration: float
|
|
28
|
+
container_id: Optional[str] = None
|
|
29
|
+
error: Optional[str] = None
|
|
30
|
+
truncated: bool = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class SandboxConfig:
|
|
35
|
+
"""Docker sandbox configuration"""
|
|
36
|
+
image: str = "kalilinux/kali-rolling"
|
|
37
|
+
memory_limit: str = "512m"
|
|
38
|
+
cpu_limit: float = 1.0
|
|
39
|
+
network_mode: str = "bridge" # bridge, host, none
|
|
40
|
+
timeout: int = 300
|
|
41
|
+
working_dir: str = "/workspace"
|
|
42
|
+
environment: Dict[str, str] = field(default_factory=dict)
|
|
43
|
+
volumes: Dict[str, str] = field(default_factory=dict)
|
|
44
|
+
capabilities: List[str] = field(default_factory=list) # NET_RAW, etc.
|
|
45
|
+
privileged: bool = False
|
|
46
|
+
remove_after: bool = True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DockerSandbox:
|
|
50
|
+
"""
|
|
51
|
+
Docker-based sandbox for secure command execution.
|
|
52
|
+
|
|
53
|
+
Provides isolated execution environment with:
|
|
54
|
+
- Resource limits (memory, CPU)
|
|
55
|
+
- Network isolation options
|
|
56
|
+
- Timeout enforcement
|
|
57
|
+
- Output streaming
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
config: Optional[SandboxConfig] = None,
|
|
63
|
+
auto_pull: bool = True,
|
|
64
|
+
):
|
|
65
|
+
self.config = config or SandboxConfig()
|
|
66
|
+
self.auto_pull = auto_pull
|
|
67
|
+
self._docker_available: Optional[bool] = None
|
|
68
|
+
|
|
69
|
+
def is_available(self) -> bool:
|
|
70
|
+
"""Check if Docker is available"""
|
|
71
|
+
if self._docker_available is not None:
|
|
72
|
+
return self._docker_available
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
result = subprocess.run(
|
|
76
|
+
["docker", "info"],
|
|
77
|
+
capture_output=True,
|
|
78
|
+
timeout=10,
|
|
79
|
+
)
|
|
80
|
+
self._docker_available = result.returncode == 0
|
|
81
|
+
except (FileNotFoundError, subprocess.TimeoutExpired, PermissionError, OSError):
|
|
82
|
+
self._docker_available = False
|
|
83
|
+
|
|
84
|
+
return self._docker_available
|
|
85
|
+
|
|
86
|
+
def image_exists(self, image: str) -> bool:
|
|
87
|
+
"""Check if Docker image exists locally"""
|
|
88
|
+
try:
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
["docker", "images", "-q", image],
|
|
91
|
+
capture_output=True,
|
|
92
|
+
text=True,
|
|
93
|
+
timeout=10,
|
|
94
|
+
)
|
|
95
|
+
return bool(result.stdout.strip())
|
|
96
|
+
except Exception:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
def pull_image(self, image: Optional[str] = None) -> bool:
|
|
100
|
+
"""Pull Docker image"""
|
|
101
|
+
image = image or self.config.image
|
|
102
|
+
try:
|
|
103
|
+
result = subprocess.run(
|
|
104
|
+
["docker", "pull", image],
|
|
105
|
+
capture_output=True,
|
|
106
|
+
text=True,
|
|
107
|
+
timeout=600,
|
|
108
|
+
)
|
|
109
|
+
return result.returncode == 0
|
|
110
|
+
except Exception:
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def execute(
|
|
114
|
+
self,
|
|
115
|
+
command: str,
|
|
116
|
+
timeout: Optional[int] = None,
|
|
117
|
+
image: Optional[str] = None,
|
|
118
|
+
network: Optional[str] = None,
|
|
119
|
+
env: Optional[Dict[str, str]] = None,
|
|
120
|
+
volumes: Optional[Dict[str, str]] = None,
|
|
121
|
+
) -> SandboxResult:
|
|
122
|
+
"""
|
|
123
|
+
Execute command in Docker container.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
command: Command to execute
|
|
127
|
+
timeout: Execution timeout in seconds
|
|
128
|
+
image: Docker image (overrides config)
|
|
129
|
+
network: Network mode (overrides config)
|
|
130
|
+
env: Additional environment variables
|
|
131
|
+
volumes: Additional volume mounts
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
SandboxResult with output and status
|
|
135
|
+
"""
|
|
136
|
+
start_time = time.time()
|
|
137
|
+
|
|
138
|
+
if not self.is_available():
|
|
139
|
+
return SandboxResult(
|
|
140
|
+
output="",
|
|
141
|
+
return_code=-1,
|
|
142
|
+
duration=0,
|
|
143
|
+
error="Docker is not available",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
image = image or self.config.image
|
|
147
|
+
|
|
148
|
+
if self.auto_pull and not self.image_exists(image):
|
|
149
|
+
if not self.pull_image(image):
|
|
150
|
+
return SandboxResult(
|
|
151
|
+
output="",
|
|
152
|
+
return_code=-1,
|
|
153
|
+
duration=0,
|
|
154
|
+
error=f"Failed to pull image: {image}",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
docker_cmd = self._build_docker_command(
|
|
158
|
+
command=command,
|
|
159
|
+
image=image,
|
|
160
|
+
network=network,
|
|
161
|
+
env=env,
|
|
162
|
+
volumes=volumes,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
timeout = timeout or self.config.timeout
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
result = subprocess.run(
|
|
169
|
+
docker_cmd,
|
|
170
|
+
capture_output=True,
|
|
171
|
+
text=True,
|
|
172
|
+
timeout=timeout,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
duration = time.time() - start_time
|
|
176
|
+
output = result.stdout
|
|
177
|
+
|
|
178
|
+
if result.stderr:
|
|
179
|
+
output = f"{output}\n[STDERR]\n{result.stderr}"
|
|
180
|
+
|
|
181
|
+
truncated = False
|
|
182
|
+
if len(output) > 100000:
|
|
183
|
+
output = output[:100000] + "\n... [OUTPUT TRUNCATED]"
|
|
184
|
+
truncated = True
|
|
185
|
+
|
|
186
|
+
return SandboxResult(
|
|
187
|
+
output=output,
|
|
188
|
+
return_code=result.returncode,
|
|
189
|
+
duration=duration,
|
|
190
|
+
truncated=truncated,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
except subprocess.TimeoutExpired:
|
|
194
|
+
return SandboxResult(
|
|
195
|
+
output="",
|
|
196
|
+
return_code=-1,
|
|
197
|
+
duration=timeout,
|
|
198
|
+
error=f"Command timed out after {timeout}s",
|
|
199
|
+
)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
return SandboxResult(
|
|
202
|
+
output="",
|
|
203
|
+
return_code=-1,
|
|
204
|
+
duration=time.time() - start_time,
|
|
205
|
+
error=str(e),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
async def execute_async(
|
|
209
|
+
self,
|
|
210
|
+
command: str,
|
|
211
|
+
timeout: Optional[int] = None,
|
|
212
|
+
image: Optional[str] = None,
|
|
213
|
+
**kwargs
|
|
214
|
+
) -> SandboxResult:
|
|
215
|
+
"""Async version of execute"""
|
|
216
|
+
loop = asyncio.get_event_loop()
|
|
217
|
+
return await loop.run_in_executor(
|
|
218
|
+
None,
|
|
219
|
+
lambda: self.execute(command, timeout, image, **kwargs)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def execute_streaming(
|
|
223
|
+
self,
|
|
224
|
+
command: str,
|
|
225
|
+
callback: Callable[[str], None],
|
|
226
|
+
timeout: Optional[int] = None,
|
|
227
|
+
image: Optional[str] = None,
|
|
228
|
+
) -> SandboxResult:
|
|
229
|
+
"""
|
|
230
|
+
Execute command with streaming output.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
command: Command to execute
|
|
234
|
+
callback: Function to call with each output line
|
|
235
|
+
timeout: Execution timeout
|
|
236
|
+
image: Docker image
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
SandboxResult
|
|
240
|
+
"""
|
|
241
|
+
start_time = time.time()
|
|
242
|
+
image = image or self.config.image
|
|
243
|
+
timeout = timeout or self.config.timeout
|
|
244
|
+
|
|
245
|
+
if not self.is_available():
|
|
246
|
+
return SandboxResult(
|
|
247
|
+
output="",
|
|
248
|
+
return_code=-1,
|
|
249
|
+
duration=0,
|
|
250
|
+
error="Docker is not available",
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
docker_cmd = self._build_docker_command(command, image)
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
process = subprocess.Popen(
|
|
257
|
+
docker_cmd,
|
|
258
|
+
stdout=subprocess.PIPE,
|
|
259
|
+
stderr=subprocess.STDOUT,
|
|
260
|
+
text=True,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
output_lines = []
|
|
264
|
+
|
|
265
|
+
while True:
|
|
266
|
+
if time.time() - start_time > timeout:
|
|
267
|
+
process.kill()
|
|
268
|
+
return SandboxResult(
|
|
269
|
+
output="\n".join(output_lines),
|
|
270
|
+
return_code=-1,
|
|
271
|
+
duration=timeout,
|
|
272
|
+
error=f"Command timed out after {timeout}s",
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
line = process.stdout.readline()
|
|
276
|
+
if not line and process.poll() is not None:
|
|
277
|
+
break
|
|
278
|
+
|
|
279
|
+
if line:
|
|
280
|
+
line = line.rstrip()
|
|
281
|
+
output_lines.append(line)
|
|
282
|
+
callback(line)
|
|
283
|
+
|
|
284
|
+
return SandboxResult(
|
|
285
|
+
output="\n".join(output_lines),
|
|
286
|
+
return_code=process.returncode,
|
|
287
|
+
duration=time.time() - start_time,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
except Exception as e:
|
|
291
|
+
return SandboxResult(
|
|
292
|
+
output="",
|
|
293
|
+
return_code=-1,
|
|
294
|
+
duration=time.time() - start_time,
|
|
295
|
+
error=str(e),
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
def _build_docker_command(
|
|
299
|
+
self,
|
|
300
|
+
command: str,
|
|
301
|
+
image: str,
|
|
302
|
+
network: Optional[str] = None,
|
|
303
|
+
env: Optional[Dict[str, str]] = None,
|
|
304
|
+
volumes: Optional[Dict[str, str]] = None,
|
|
305
|
+
) -> List[str]:
|
|
306
|
+
"""Build docker run command"""
|
|
307
|
+
docker_cmd = [
|
|
308
|
+
"docker", "run",
|
|
309
|
+
"--memory", self.config.memory_limit,
|
|
310
|
+
"--cpus", str(self.config.cpu_limit),
|
|
311
|
+
"--network", network or self.config.network_mode,
|
|
312
|
+
"-w", self.config.working_dir,
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
if self.config.remove_after:
|
|
316
|
+
docker_cmd.append("--rm")
|
|
317
|
+
|
|
318
|
+
if self.config.privileged:
|
|
319
|
+
docker_cmd.append("--privileged")
|
|
320
|
+
|
|
321
|
+
for cap in self.config.capabilities:
|
|
322
|
+
docker_cmd.extend(["--cap-add", cap])
|
|
323
|
+
|
|
324
|
+
all_env = {**self.config.environment, **(env or {})}
|
|
325
|
+
for key, value in all_env.items():
|
|
326
|
+
docker_cmd.extend(["-e", f"{key}={value}"])
|
|
327
|
+
|
|
328
|
+
all_volumes = {**self.config.volumes, **(volumes or {})}
|
|
329
|
+
for host_path, container_path in all_volumes.items():
|
|
330
|
+
docker_cmd.extend(["-v", f"{host_path}:{container_path}"])
|
|
331
|
+
|
|
332
|
+
docker_cmd.extend([image, "sh", "-c", command])
|
|
333
|
+
|
|
334
|
+
return docker_cmd
|
|
335
|
+
|
|
336
|
+
def list_containers(self, all_containers: bool = False) -> List[Dict[str, str]]:
|
|
337
|
+
"""List running containers"""
|
|
338
|
+
cmd = ["docker", "ps", "--format", "{{json .}}"]
|
|
339
|
+
if all_containers:
|
|
340
|
+
cmd.append("-a")
|
|
341
|
+
|
|
342
|
+
try:
|
|
343
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
|
344
|
+
containers = []
|
|
345
|
+
for line in result.stdout.strip().split("\n"):
|
|
346
|
+
if line:
|
|
347
|
+
containers.append(json.loads(line))
|
|
348
|
+
return containers
|
|
349
|
+
except Exception:
|
|
350
|
+
return []
|
|
351
|
+
|
|
352
|
+
def stop_container(self, container_id: str, force: bool = False) -> bool:
|
|
353
|
+
"""Stop a running container"""
|
|
354
|
+
cmd = ["docker", "kill" if force else "stop", container_id]
|
|
355
|
+
try:
|
|
356
|
+
result = subprocess.run(cmd, capture_output=True, timeout=30)
|
|
357
|
+
return result.returncode == 0
|
|
358
|
+
except Exception:
|
|
359
|
+
return False
|
|
360
|
+
|
|
361
|
+
def cleanup_containers(self, image_filter: Optional[str] = None) -> int:
|
|
362
|
+
"""Remove stopped containers"""
|
|
363
|
+
cmd = ["docker", "container", "prune", "-f"]
|
|
364
|
+
if image_filter:
|
|
365
|
+
cmd.extend(["--filter", f"ancestor={image_filter}"])
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
369
|
+
return result.returncode
|
|
370
|
+
except Exception:
|
|
371
|
+
return -1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIPT Evasion Module - WAF Bypass and Request Obfuscation
|
|
3
|
+
|
|
4
|
+
Provides evasion techniques for authorized penetration testing:
|
|
5
|
+
- WAF bypass payload generation
|
|
6
|
+
- Request obfuscation and encoding
|
|
7
|
+
- User-Agent rotation
|
|
8
|
+
- TLS fingerprint randomization
|
|
9
|
+
|
|
10
|
+
WARNING: Use only for authorized security testing!
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
from aipt_v2.evasion import WAFBypass, RequestObfuscator, UARotator
|
|
14
|
+
|
|
15
|
+
bypass = WAFBypass()
|
|
16
|
+
payloads = bypass.generate_sqli_bypasses("' OR '1'='1")
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from aipt_v2.evasion.waf_bypass import (
|
|
20
|
+
WAFBypass,
|
|
21
|
+
BypassPayload,
|
|
22
|
+
generate_bypass_payloads,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from aipt_v2.evasion.request_obfuscator import (
|
|
26
|
+
RequestObfuscator,
|
|
27
|
+
ObfuscationConfig,
|
|
28
|
+
obfuscate_request,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from aipt_v2.evasion.ua_rotator import (
|
|
32
|
+
UARotator,
|
|
33
|
+
UserAgent,
|
|
34
|
+
get_random_ua,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from aipt_v2.evasion.tls_fingerprint import (
|
|
38
|
+
TLSFingerprint,
|
|
39
|
+
randomize_tls,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
# WAF Bypass
|
|
44
|
+
"WAFBypass",
|
|
45
|
+
"BypassPayload",
|
|
46
|
+
"generate_bypass_payloads",
|
|
47
|
+
# Obfuscation
|
|
48
|
+
"RequestObfuscator",
|
|
49
|
+
"ObfuscationConfig",
|
|
50
|
+
"obfuscate_request",
|
|
51
|
+
# User-Agent
|
|
52
|
+
"UARotator",
|
|
53
|
+
"UserAgent",
|
|
54
|
+
"get_random_ua",
|
|
55
|
+
# TLS
|
|
56
|
+
"TLSFingerprint",
|
|
57
|
+
"randomize_tls",
|
|
58
|
+
]
|