zen-ai-pentest 2.0.0__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 (75) hide show
  1. agents/__init__.py +28 -0
  2. agents/agent_base.py +239 -0
  3. agents/agent_orchestrator.py +346 -0
  4. agents/analysis_agent.py +225 -0
  5. agents/cli.py +258 -0
  6. agents/exploit_agent.py +224 -0
  7. agents/integration.py +211 -0
  8. agents/post_scan_agent.py +937 -0
  9. agents/react_agent.py +384 -0
  10. agents/react_agent_enhanced.py +616 -0
  11. agents/react_agent_vm.py +298 -0
  12. agents/research_agent.py +176 -0
  13. api/__init__.py +11 -0
  14. api/auth.py +123 -0
  15. api/main.py +1027 -0
  16. api/schemas.py +357 -0
  17. api/websocket.py +97 -0
  18. autonomous/__init__.py +122 -0
  19. autonomous/agent.py +253 -0
  20. autonomous/agent_loop.py +1370 -0
  21. autonomous/exploit_validator.py +1537 -0
  22. autonomous/memory.py +448 -0
  23. autonomous/react.py +339 -0
  24. autonomous/tool_executor.py +488 -0
  25. backends/__init__.py +16 -0
  26. backends/chatgpt_direct.py +133 -0
  27. backends/claude_direct.py +130 -0
  28. backends/duckduckgo.py +138 -0
  29. backends/openrouter.py +120 -0
  30. benchmarks/__init__.py +149 -0
  31. benchmarks/benchmark_engine.py +904 -0
  32. benchmarks/ci_benchmark.py +785 -0
  33. benchmarks/comparison.py +729 -0
  34. benchmarks/metrics.py +553 -0
  35. benchmarks/run_benchmarks.py +809 -0
  36. ci_cd/__init__.py +2 -0
  37. core/__init__.py +17 -0
  38. core/async_pool.py +282 -0
  39. core/asyncio_fix.py +222 -0
  40. core/cache.py +472 -0
  41. core/container.py +277 -0
  42. core/database.py +114 -0
  43. core/input_validator.py +353 -0
  44. core/models.py +288 -0
  45. core/orchestrator.py +611 -0
  46. core/plugin_manager.py +571 -0
  47. core/rate_limiter.py +405 -0
  48. core/secure_config.py +328 -0
  49. core/shield_integration.py +296 -0
  50. modules/__init__.py +46 -0
  51. modules/cve_database.py +362 -0
  52. modules/exploit_assist.py +330 -0
  53. modules/nuclei_integration.py +480 -0
  54. modules/osint.py +604 -0
  55. modules/protonvpn.py +554 -0
  56. modules/recon.py +165 -0
  57. modules/sql_injection_db.py +826 -0
  58. modules/tool_orchestrator.py +498 -0
  59. modules/vuln_scanner.py +292 -0
  60. modules/wordlist_generator.py +566 -0
  61. risk_engine/__init__.py +99 -0
  62. risk_engine/business_impact.py +267 -0
  63. risk_engine/business_impact_calculator.py +563 -0
  64. risk_engine/cvss.py +156 -0
  65. risk_engine/epss.py +190 -0
  66. risk_engine/example_usage.py +294 -0
  67. risk_engine/false_positive_engine.py +1073 -0
  68. risk_engine/scorer.py +304 -0
  69. web_ui/backend/main.py +471 -0
  70. zen_ai_pentest-2.0.0.dist-info/METADATA +795 -0
  71. zen_ai_pentest-2.0.0.dist-info/RECORD +75 -0
  72. zen_ai_pentest-2.0.0.dist-info/WHEEL +5 -0
  73. zen_ai_pentest-2.0.0.dist-info/entry_points.txt +2 -0
  74. zen_ai_pentest-2.0.0.dist-info/licenses/LICENSE +21 -0
  75. zen_ai_pentest-2.0.0.dist-info/top_level.txt +10 -0
@@ -0,0 +1,1537 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Exploit Validator System for Zen AI Pentest Framework
4
+
5
+ Automatisierte Validierung und Beweisführung von Exploits in isolierten Umgebungen.
6
+
7
+ Features:
8
+ - Docker-Container-basierte Sandboxed-Ausführung
9
+ - Proof-of-Exploit Generierung (Screenshots, HTTP-Capture, PCAP)
10
+ - Evidence Collection mit Chain-of-Custody
11
+ - Unterstützung für verschiedene Exploit-Typen
12
+ - Safety Features (Read-Only, Scope-Validierung, Kill-Switch)
13
+
14
+ FOR AUTHORIZED SECURITY TESTING ONLY
15
+
16
+ Author: SHAdd0WTAka
17
+ Version: 1.0.0
18
+ """
19
+
20
+ import asyncio
21
+ import hashlib
22
+ import json
23
+ import logging
24
+ import os
25
+ import shlex
26
+ import tempfile
27
+ import time
28
+ import uuid
29
+
30
+ from dataclasses import dataclass, field, asdict
31
+ from datetime import datetime
32
+ from enum import Enum, auto
33
+ from typing import Any, Dict, List, Optional, Tuple
34
+ from urllib.parse import urlparse
35
+ import warnings
36
+
37
+ # Optional imports - handle gracefully if not available
38
+ try:
39
+ import docker
40
+ from docker.errors import DockerException, ContainerError, ImageNotFound
41
+ DOCKER_AVAILABLE = True
42
+ except ImportError:
43
+ DOCKER_AVAILABLE = False
44
+ warnings.warn("Docker SDK not available. Container isolation disabled.")
45
+
46
+ try:
47
+ import aiohttp
48
+ AIOHTTP_AVAILABLE = True
49
+ except ImportError:
50
+ AIOHTTP_AVAILABLE = False
51
+
52
+ try:
53
+ from playwright.async_api import async_playwright
54
+ PLAYWRIGHT_AVAILABLE = True
55
+ except ImportError:
56
+ PLAYWRIGHT_AVAILABLE = False
57
+ warnings.warn("Playwright not available. Screenshot capture disabled.")
58
+
59
+ # Configure logging
60
+ logger = logging.getLogger("ZenAI.ExploitValidator")
61
+
62
+
63
+ class ExploitType(Enum):
64
+ """Enumeration of supported exploit types."""
65
+ WEB_SQLI = "web_sqli"
66
+ WEB_XSS = "web_xss"
67
+ WEB_LFI = "web_lfi"
68
+ WEB_RFI = "web_rfi"
69
+ WEB_RCE = "web_rce"
70
+ WEB_CMD_INJECTION = "web_cmd_injection"
71
+ WEB_CSRF = "web_csrf"
72
+ WEB_SSRF = "web_ssrf"
73
+ WEB_XXE = "web_xxe"
74
+ WEB_PATH_TRAVERSAL = "web_path_traversal"
75
+ SERVICE = "service"
76
+ PRIVESC = "privilege_escalation"
77
+ POST_EXPLOITATION = "post_exploitation"
78
+ LOCAL = "local"
79
+
80
+
81
+ class ExploitStatus(Enum):
82
+ """Status of exploit execution."""
83
+ PENDING = auto()
84
+ RUNNING = auto()
85
+ SUCCESS = auto()
86
+ FAILED = auto()
87
+ TIMEOUT = auto()
88
+ BLOCKED = auto()
89
+ ERROR = auto()
90
+
91
+
92
+ class SafetyLevel(Enum):
93
+ """Safety levels for exploit execution."""
94
+ READ_ONLY = 1 # Passive validation only, no modifications
95
+ VALIDATE_ONLY = 2 # Validate exploit without full execution
96
+ CONTROLLED = 3 # Controlled execution with limits
97
+ FULL = 4 # Full exploitation (requires explicit approval)
98
+
99
+
100
+ @dataclass
101
+ class ScopeConfig:
102
+ """Configuration for scope validation."""
103
+ allowed_hosts: List[str] = field(default_factory=list)
104
+ allowed_ports: List[int] = field(default_factory=lambda: [80, 443, 8080])
105
+ blocked_hosts: List[str] = field(default_factory=lambda: [
106
+ "localhost", "127.0.0.1", "::1", "0.0.0.0",
107
+ "169.254.169.254" # AWS metadata
108
+ ])
109
+ blocked_ports: List[int] = field(default_factory=lambda: [
110
+ 22, 23, 25, 53, 110, 143, 587, 993, 995 # Email/DNS services
111
+ ])
112
+ require_https: bool = False
113
+ max_redirects: int = 5
114
+ allowed_schemes: List[str] = field(default_factory=lambda: ["http", "https"])
115
+
116
+ def validate_target(self, target: str) -> Tuple[bool, Optional[str]]:
117
+ """
118
+ Validate if target is within scope.
119
+
120
+ Args:
121
+ target: Target URL or host
122
+
123
+ Returns:
124
+ Tuple of (is_valid, error_message)
125
+ """
126
+ try:
127
+ # Parse URL if it's a full URL
128
+ if "//" in target:
129
+ parsed = urlparse(target)
130
+ host = parsed.hostname
131
+ port = parsed.port
132
+ scheme = parsed.scheme
133
+
134
+ if not host:
135
+ return False, "Could not parse host from target"
136
+
137
+ # Check scheme
138
+ if scheme not in self.allowed_schemes:
139
+ return False, f"Scheme '{scheme}' not allowed"
140
+ else:
141
+ host = target.split(":")[0]
142
+ port = int(target.split(":")[1]) if ":" in target else None
143
+
144
+ # Check blocked hosts
145
+ if host in self.blocked_hosts:
146
+ return False, f"Host '{host}' is in blocklist"
147
+
148
+ # Check IP ranges
149
+ try:
150
+ import ipaddress
151
+ ip = ipaddress.ip_address(host)
152
+ # Block private IPs unless explicitly allowed
153
+ if ip.is_private and host not in self.allowed_hosts:
154
+ return False, f"Private IP '{host}' not in allowed list"
155
+ if ip.is_loopback:
156
+ return False, f"Loopback address '{host}' not allowed"
157
+ if ip.is_multicast:
158
+ return False, f"Multicast address '{host}' not allowed"
159
+ except ValueError:
160
+ # Not an IP, continue with hostname check
161
+ pass
162
+
163
+ # Check blocked ports
164
+ if port and port in self.blocked_ports:
165
+ return False, f"Port {port} is blocked"
166
+
167
+ # Check allowed hosts (if specified)
168
+ if self.allowed_hosts and host not in self.allowed_hosts:
169
+ # Allow wildcards
170
+ allowed = any(
171
+ host.endswith(allowed.replace("*.", ".")) or host == allowed
172
+ for allowed in self.allowed_hosts
173
+ )
174
+ if not allowed:
175
+ return False, f"Host '{host}' not in allowed scope"
176
+
177
+ return True, None
178
+
179
+ except Exception as e:
180
+ return False, f"Validation error: {str(e)}"
181
+
182
+
183
+ @dataclass
184
+ class Evidence:
185
+ """Collection of evidence from exploit execution."""
186
+ screenshots: List[str] = field(default_factory=list)
187
+ http_responses: List[Dict[str, Any]] = field(default_factory=list)
188
+ pcap_file: Optional[str] = None
189
+ shell_session: Optional[str] = None
190
+ video_recording: Optional[str] = None
191
+ logs: List[str] = field(default_factory=list)
192
+ files: Dict[str, str] = field(default_factory=dict)
193
+ metadata: Dict[str, Any] = field(default_factory=dict)
194
+ timestamps: Dict[str, datetime] = field(default_factory=dict)
195
+ hashes: Dict[str, str] = field(default_factory=dict)
196
+
197
+ def to_dict(self) -> Dict[str, Any]:
198
+ """Convert to dictionary with serializable values."""
199
+ result = asdict(self)
200
+ # Convert timestamps to ISO format
201
+ result['timestamps'] = {
202
+ k: v.isoformat() if isinstance(v, datetime) else v
203
+ for k, v in self.timestamps.items()
204
+ }
205
+ return result
206
+
207
+ def compute_hashes(self) -> None:
208
+ """Compute SHA256 hashes for all evidence files."""
209
+ for attr in ['screenshots', 'pcap_file', 'video_recording']:
210
+ value = getattr(self, attr)
211
+ if value:
212
+ if isinstance(value, list):
213
+ for f in value:
214
+ self._hash_file(f)
215
+ else:
216
+ self._hash_file(value)
217
+
218
+ def _hash_file(self, filepath: str) -> None:
219
+ """Compute hash for a single file."""
220
+ try:
221
+ if os.path.exists(filepath):
222
+ sha256 = hashlib.sha256()
223
+ with open(filepath, 'rb') as f:
224
+ for chunk in iter(lambda: f.read(8192), b''):
225
+ sha256.update(chunk)
226
+ self.hashes[filepath] = sha256.hexdigest()
227
+ except Exception as e:
228
+ logger.warning(f"Failed to hash {filepath}: {e}")
229
+
230
+
231
+ @dataclass
232
+ class ExploitResult:
233
+ """Result of exploit validation."""
234
+ success: bool
235
+ exploit_type: ExploitType
236
+ target: str
237
+ timestamp: datetime
238
+ evidence: Evidence
239
+ output: str
240
+ status: ExploitStatus = ExploitStatus.PENDING
241
+ error: Optional[str] = None
242
+ remediation: Optional[str] = None
243
+ cvss_score: Optional[float] = None
244
+ severity: Optional[str] = None
245
+ execution_time: float = 0.0
246
+ validator_id: str = field(default_factory=lambda: str(uuid.uuid4()))
247
+ chain_of_custody: List[Dict[str, Any]] = field(default_factory=list)
248
+
249
+ def to_dict(self) -> Dict[str, Any]:
250
+ """Convert to dictionary."""
251
+ return {
252
+ 'success': self.success,
253
+ 'exploit_type': self.exploit_type.value,
254
+ 'target': self.target,
255
+ 'timestamp': self.timestamp.isoformat(),
256
+ 'evidence': self.evidence.to_dict(),
257
+ 'output': self.output,
258
+ 'status': self.status.name,
259
+ 'error': self.error,
260
+ 'remediation': self.remediation,
261
+ 'cvss_score': self.cvss_score,
262
+ 'severity': self.severity,
263
+ 'execution_time': self.execution_time,
264
+ 'validator_id': self.validator_id,
265
+ 'chain_of_custody': self.chain_of_custody
266
+ }
267
+
268
+ def to_json(self) -> str:
269
+ """Convert to JSON string."""
270
+ return json.dumps(self.to_dict(), indent=2, default=str)
271
+
272
+
273
+ @dataclass
274
+ class SandboxConfig:
275
+ """Configuration for sandboxed execution."""
276
+ use_docker: bool = True
277
+ use_gvisor: bool = False # Experimental gVisor support
278
+ network_isolated: bool = True
279
+ cpu_limit: float = 1.0 # CPU cores
280
+ memory_limit: str = "512m"
281
+ timeout: int = 60
282
+ read_only_root: bool = True
283
+ tmpfs_size: str = "100m"
284
+ cap_drop: List[str] = field(default_factory=lambda: [
285
+ "ALL"
286
+ ])
287
+ cap_add: List[str] = field(default_factory=lambda: [
288
+ "NET_BIND_SERVICE"
289
+ ])
290
+ dns_servers: List[str] = field(default_factory=lambda: [
291
+ "8.8.8.8", "1.1.1.1"
292
+ ])
293
+ image: str = "zenai/exploit-sandbox:latest"
294
+
295
+
296
+ class ExploitValidator:
297
+ """
298
+ Main class for validating exploits in sandboxed environments.
299
+
300
+ This validator provides comprehensive exploit testing capabilities
301
+ with strong isolation, evidence collection, and safety controls.
302
+
303
+ Usage:
304
+ validator = ExploitValidator(
305
+ safety_level=SafetyLevel.CONTROLLED,
306
+ scope_config=ScopeConfig(allowed_hosts=["example.com"])
307
+ )
308
+
309
+ result = await validator.validate(
310
+ exploit_code="...",
311
+ target="https://example.com/vuln",
312
+ exploit_type=ExploitType.WEB_SQLI
313
+ )
314
+ """
315
+
316
+ def __init__(
317
+ self,
318
+ safety_level: SafetyLevel = SafetyLevel.CONTROLLED,
319
+ scope_config: Optional[ScopeConfig] = None,
320
+ sandbox_config: Optional[SandboxConfig] = None,
321
+ output_dir: Optional[str] = None,
322
+ enable_playwright: bool = True
323
+ ):
324
+ """
325
+ Initialize the ExploitValidator.
326
+
327
+ Args:
328
+ safety_level: Maximum allowed safety level
329
+ scope_config: Scope validation configuration
330
+ sandbox_config: Sandbox execution configuration
331
+ output_dir: Directory for evidence storage
332
+ enable_playwright: Enable Playwright for screenshot capture
333
+ """
334
+ self.safety_level = safety_level
335
+ self.scope_config = scope_config or ScopeConfig()
336
+ self.sandbox_config = sandbox_config or SandboxConfig()
337
+ self.output_dir = output_dir or tempfile.gettempdir()
338
+ self.enable_playwright = enable_playwright and PLAYWRIGHT_AVAILABLE
339
+
340
+ # Initialize Docker client if available
341
+ self.docker_client = None
342
+ if DOCKER_AVAILABLE and self.sandbox_config.use_docker:
343
+ try:
344
+ self.docker_client = docker.from_env()
345
+ logger.info("Docker client initialized")
346
+ except DockerException as e:
347
+ logger.warning(f"Docker not available: {e}")
348
+
349
+ # Rate limiting
350
+ self._rate_limiter = asyncio.Semaphore(5) # Max 5 concurrent exploits
351
+ self._last_execution: Dict[str, float] = {}
352
+ self._min_interval = 1.0 # Minimum seconds between executions to same target
353
+
354
+ # Kill switch
355
+ self._killed = False
356
+
357
+ # Evidence storage
358
+ self._evidence_counter = 0
359
+
360
+ logger.info(f"ExploitValidator initialized (safety={safety_level.name})")
361
+
362
+ async def validate(
363
+ self,
364
+ exploit_code: str,
365
+ target: str,
366
+ exploit_type: ExploitType,
367
+ parameters: Optional[Dict[str, Any]] = None,
368
+ timeout: Optional[int] = None
369
+ ) -> ExploitResult:
370
+ """
371
+ Validate an exploit against a target.
372
+
373
+ Args:
374
+ exploit_code: The exploit code/payload to execute
375
+ target: Target URL, host, or service
376
+ exploit_type: Type of exploit being tested
377
+ parameters: Additional exploit parameters
378
+ timeout: Execution timeout override
379
+
380
+ Returns:
381
+ ExploitResult with execution details and evidence
382
+ """
383
+ start_time = time.time()
384
+ timestamp = datetime.utcnow()
385
+ validator_id = str(uuid.uuid4())
386
+
387
+ # Initialize chain of custody
388
+ chain_of_custody = [
389
+ {
390
+ 'action': 'validation_started',
391
+ 'timestamp': timestamp.isoformat(),
392
+ 'validator_id': validator_id,
393
+ 'hash': hashlib.sha256(exploit_code.encode()).hexdigest()[:16]
394
+ }
395
+ ]
396
+
397
+ # Check kill switch
398
+ if self._killed:
399
+ return ExploitResult(
400
+ success=False,
401
+ exploit_type=exploit_type,
402
+ target=target,
403
+ timestamp=timestamp,
404
+ evidence=Evidence(),
405
+ output="",
406
+ status=ExploitStatus.BLOCKED,
407
+ error="Kill switch activated",
408
+ chain_of_custody=chain_of_custody
409
+ )
410
+
411
+ # Validate scope
412
+ is_valid, error_msg = self.scope_config.validate_target(target)
413
+ if not is_valid:
414
+ return ExploitResult(
415
+ success=False,
416
+ exploit_type=exploit_type,
417
+ target=target,
418
+ timestamp=timestamp,
419
+ evidence=Evidence(),
420
+ output="",
421
+ status=ExploitStatus.BLOCKED,
422
+ error=f"Scope validation failed: {error_msg}",
423
+ chain_of_custody=chain_of_custody
424
+ )
425
+
426
+ chain_of_custody.append({
427
+ 'action': 'scope_validated',
428
+ 'timestamp': datetime.utcnow().isoformat()
429
+ })
430
+
431
+ # Rate limiting check
432
+ await self._check_rate_limit(target)
433
+
434
+ # Check safety level compatibility
435
+ if not self._is_safety_compatible(exploit_type):
436
+ return ExploitResult(
437
+ success=False,
438
+ exploit_type=exploit_type,
439
+ target=target,
440
+ timestamp=timestamp,
441
+ evidence=Evidence(),
442
+ output="",
443
+ status=ExploitStatus.BLOCKED,
444
+ error=f"Exploit type {exploit_type.value} exceeds safety level {self.safety_level.name}",
445
+ chain_of_custody=chain_of_custody
446
+ )
447
+
448
+ # Execute with semaphore for rate limiting
449
+ async with self._rate_limiter:
450
+ try:
451
+ if self.sandbox_config.use_docker and self.docker_client:
452
+ result = await self._execute_docker_sandboxed(
453
+ exploit_code, target, exploit_type,
454
+ parameters or {}, timeout or self.sandbox_config.timeout
455
+ )
456
+ else:
457
+ result = await self._execute_local_sandboxed(
458
+ exploit_code, target, exploit_type,
459
+ parameters or {}, timeout or self.sandbox_config.timeout
460
+ )
461
+
462
+ result.chain_of_custody = chain_of_custody + result.chain_of_custody
463
+ result.execution_time = time.time() - start_time
464
+ return result
465
+
466
+ except asyncio.TimeoutError:
467
+ execution_time = time.time() - start_time
468
+ return ExploitResult(
469
+ success=False,
470
+ exploit_type=exploit_type,
471
+ target=target,
472
+ timestamp=timestamp,
473
+ evidence=Evidence(),
474
+ output="",
475
+ status=ExploitStatus.TIMEOUT,
476
+ error=f"Execution timeout after {timeout or self.sandbox_config.timeout}s",
477
+ execution_time=execution_time,
478
+ validator_id=validator_id,
479
+ chain_of_custody=chain_of_custody
480
+ )
481
+ except Exception as e:
482
+ execution_time = time.time() - start_time
483
+ logger.exception("Exploit validation failed")
484
+ return ExploitResult(
485
+ success=False,
486
+ exploit_type=exploit_type,
487
+ target=target,
488
+ timestamp=timestamp,
489
+ evidence=Evidence(),
490
+ output="",
491
+ status=ExploitStatus.ERROR,
492
+ error=f"Execution error: {str(e)}",
493
+ execution_time=execution_time,
494
+ validator_id=validator_id,
495
+ chain_of_custody=chain_of_custody
496
+ )
497
+
498
+ async def execute_sandboxed(
499
+ self,
500
+ command: str,
501
+ timeout: int = 60,
502
+ network_access: bool = False
503
+ ) -> Dict[str, Any]:
504
+ """
505
+ Execute a command in a sandboxed environment.
506
+
507
+ Args:
508
+ command: Command to execute
509
+ timeout: Execution timeout
510
+ network_access: Whether to allow network access
511
+
512
+ Returns:
513
+ Dictionary with stdout, stderr, return_code, and execution details
514
+ """
515
+ if self.sandbox_config.use_docker and self.docker_client:
516
+ return await self._execute_docker_command(command, timeout, network_access)
517
+ else:
518
+ return await self._execute_local_command(command, timeout)
519
+
520
+ async def capture_evidence(
521
+ self,
522
+ target: str,
523
+ exploit_type: ExploitType,
524
+ capture_screenshot: bool = True,
525
+ capture_http: bool = True,
526
+ capture_pcap: bool = False
527
+ ) -> Evidence:
528
+ """
529
+ Capture evidence from target interaction.
530
+
531
+ Args:
532
+ target: Target URL
533
+ exploit_type: Type of exploit
534
+ capture_screenshot: Capture browser screenshot
535
+ capture_http: Capture HTTP responses
536
+ capture_pcap: Capture network traffic (requires permissions)
537
+
538
+ Returns:
539
+ Evidence object with collected artifacts
540
+ """
541
+ evidence = Evidence()
542
+ evidence.timestamps['started'] = datetime.utcnow()
543
+
544
+ # Create evidence directory
545
+ evidence_dir = os.path.join(
546
+ self.output_dir,
547
+ f"evidence_{int(time.time())}_{self._evidence_counter}"
548
+ )
549
+ self._evidence_counter += 1
550
+ os.makedirs(evidence_dir, exist_ok=True)
551
+
552
+ try:
553
+ # Capture HTTP responses
554
+ if capture_http and AIOHTTP_AVAILABLE:
555
+ http_evidence = await self._capture_http_evidence(target, evidence_dir)
556
+ evidence.http_responses = http_evidence
557
+
558
+ # Capture screenshot for web exploits
559
+ if capture_screenshot and self.enable_playwright and self._is_web_exploit(exploit_type):
560
+ screenshot_path = await self._capture_screenshot(target, evidence_dir)
561
+ if screenshot_path:
562
+ evidence.screenshots.append(screenshot_path)
563
+
564
+ # Capture PCAP (if enabled and running as root)
565
+ if capture_pcap:
566
+ pcap_path = await self._capture_pcap(target, evidence_dir)
567
+ if pcap_path:
568
+ evidence.pcap_file = pcap_path
569
+
570
+ # Collect metadata
571
+ evidence.metadata = {
572
+ 'target': target,
573
+ 'exploit_type': exploit_type.value,
574
+ 'evidence_dir': evidence_dir,
575
+ 'user_agent': 'ZenAI-ExploitValidator/1.0',
576
+ 'source_ip': await self._get_source_ip()
577
+ }
578
+
579
+ evidence.timestamps['completed'] = datetime.utcnow()
580
+ evidence.compute_hashes()
581
+
582
+ except Exception as e:
583
+ logger.error(f"Evidence capture failed: {e}")
584
+ evidence.metadata['error'] = str(e)
585
+
586
+ return evidence
587
+
588
+ def generate_remediation(self, vulnerability: Dict[str, Any]) -> str:
589
+ """
590
+ Generate remediation advice for a vulnerability.
591
+
592
+ Args:
593
+ vulnerability: Vulnerability details dictionary
594
+
595
+ Returns:
596
+ Remediation advice as markdown text
597
+ """
598
+ vuln_type = vulnerability.get('type', 'unknown')
599
+ severity = vulnerability.get('severity', 'medium')
600
+
601
+ remediation_templates = {
602
+ ExploitType.WEB_SQLI.value: """
603
+ ## SQL Injection Remediation
604
+
605
+ ### Immediate Actions
606
+ 1. **Use Parameterized Queries**: Replace all dynamic SQL with prepared statements
607
+ 2. **Input Validation**: Validate and sanitize all user inputs
608
+ 3. **Least Privilege**: Ensure database user has minimal permissions
609
+
610
+ ### Code Example (Python/Flask)
611
+ ```python
612
+ # VULNERABLE
613
+ cursor.execute(f"SELECT * FROM users WHERE id = '{user_id}'")
614
+
615
+ # SECURE
616
+ cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
617
+ ```
618
+
619
+ ### Long-term Recommendations
620
+ - Implement Web Application Firewall (WAF)
621
+ - Enable SQL query logging and monitoring
622
+ - Regular security code reviews
623
+ - Use ORM frameworks that prevent SQL injection
624
+ """,
625
+ ExploitType.WEB_XSS.value: """
626
+ ## Cross-Site Scripting (XSS) Remediation
627
+
628
+ ### Immediate Actions
629
+ 1. **Output Encoding**: Encode all output based on context (HTML, JS, URL, CSS)
630
+ 2. **Content Security Policy**: Implement strict CSP headers
631
+ 3. **Input Validation**: Validate input against expected patterns
632
+
633
+ ### Code Example
634
+ ```python
635
+ # VULNERABLE
636
+ <div>{{ user_input }}</div>
637
+
638
+ # SECURE (with Jinja2 autoescape)
639
+ <div>{{ user_input | e }}</div>
640
+ ```
641
+
642
+ ### Headers to Implement
643
+ ```
644
+ Content-Security-Policy: default-src 'self'
645
+ X-XSS-Protection: 1; mode=block
646
+ X-Content-Type-Options: nosniff
647
+ ```
648
+ """,
649
+ ExploitType.WEB_RCE.value: """
650
+ ## Remote Code Execution Remediation
651
+
652
+ ### Immediate Actions
653
+ 1. **Disable Dangerous Functions**: Disable eval(), exec(), system() in PHP/Python
654
+ 2. **Input Sanitization**: Never pass user input to system commands
655
+ 3. **Sandboxing**: Run application in restricted environment
656
+
657
+ ### Code Example
658
+ ```python
659
+ # VULNERABLE
660
+ os.system(f"ping {user_input}")
661
+
662
+ # SECURE
663
+ allowed_hosts = ['8.8.8.8', '1.1.1.1']
664
+ if user_input in allowed_hosts:
665
+ subprocess.run(['ping', '-c', '4', user_input], check=True)
666
+ ```
667
+
668
+ ### Critical Recommendations
669
+ - Remove all command execution functionality if not essential
670
+ - Use allowlists for allowed commands/arguments
671
+ - Implement strong network segmentation
672
+ """,
673
+ ExploitType.WEB_LFI.value: """
674
+ ## Local File Inclusion Remediation
675
+
676
+ ### Immediate Actions
677
+ 1. **Path Validation**: Validate and sanitize file paths
678
+ 2. **Allowlist**: Use allowlist of allowed files
679
+ 3. **Disable Remote Includes**: Set allow_url_include=Off in PHP
680
+
681
+ ### Code Example
682
+ ```php
683
+ // VULNERABLE
684
+ include($_GET['page']);
685
+
686
+ // SECURE
687
+ $allowed = ['home', 'about', 'contact'];
688
+ $page = $_GET['page'];
689
+ if (in_array($page, $allowed)) {
690
+ include("pages/" . $page . ".php");
691
+ }
692
+ ```
693
+ """,
694
+ 'default': f"""
695
+ ## Vulnerability Remediation
696
+
697
+ **Severity**: {severity}
698
+ **Type**: {vuln_type}
699
+
700
+ ### General Recommendations
701
+ 1. **Update Software**: Apply latest security patches
702
+ 2. **Input Validation**: Validate all user inputs
703
+ 3. **Principle of Least Privilege**: Minimize permissions
704
+ 4. **Security Headers**: Implement security headers
705
+ 5. **Monitoring**: Enable comprehensive logging
706
+
707
+ ### Verification
708
+ After applying fixes:
709
+ 1. Re-run the vulnerability scan
710
+ 2. Test functionality to ensure no breakage
711
+ 3. Monitor for any suspicious activity
712
+ """
713
+ }
714
+
715
+ return remediation_templates.get(vuln_type, remediation_templates['default'])
716
+
717
+ async def safe_execute(self, exploit: Dict[str, Any]) -> bool:
718
+ """
719
+ Safely execute an exploit with comprehensive checks.
720
+
721
+ Args:
722
+ exploit: Exploit dictionary with code, target, type
723
+
724
+ Returns:
725
+ True if exploit execution was successful
726
+ """
727
+ try:
728
+ # Pre-execution checks
729
+ if not self._validate_exploit_structure(exploit):
730
+ logger.error("Invalid exploit structure")
731
+ return False
732
+
733
+ # Execute validation
734
+ result = await self.validate(
735
+ exploit_code=exploit['code'],
736
+ target=exploit['target'],
737
+ exploit_type=ExploitType(exploit.get('type', 'web_rce')),
738
+ parameters=exploit.get('parameters', {})
739
+ )
740
+
741
+ return result.success
742
+
743
+ except Exception as e:
744
+ logger.error(f"Safe execution failed: {e}")
745
+ return False
746
+
747
+ def kill_switch(self) -> None:
748
+ """Activate kill switch to stop all executions."""
749
+ logger.warning("Kill switch activated!")
750
+ self._killed = True
751
+
752
+ def reset_kill_switch(self) -> None:
753
+ """Reset kill switch."""
754
+ logger.info("Kill switch reset")
755
+ self._killed = False
756
+
757
+ # Private helper methods
758
+
759
+ def _is_safety_compatible(self, exploit_type: ExploitType) -> bool:
760
+ """Check if exploit type is compatible with current safety level."""
761
+ safety_mapping = {
762
+ SafetyLevel.READ_ONLY: [],
763
+ SafetyLevel.VALIDATE_ONLY: [
764
+ ExploitType.WEB_XSS, ExploitType.WEB_SQLI,
765
+ ExploitType.WEB_LFI, ExploitType.WEB_CSRF
766
+ ],
767
+ SafetyLevel.CONTROLLED: [
768
+ ExploitType.WEB_XSS, ExploitType.WEB_SQLI, ExploitType.WEB_LFI,
769
+ ExploitType.WEB_RFI, ExploitType.WEB_RCE, ExploitType.WEB_CMD_INJECTION,
770
+ ExploitType.WEB_SSRF, ExploitType.WEB_XXE, ExploitType.WEB_PATH_TRAVERSAL,
771
+ ExploitType.SERVICE
772
+ ],
773
+ SafetyLevel.FULL: list(ExploitType)
774
+ }
775
+
776
+ allowed = safety_mapping.get(self.safety_level, [])
777
+ return exploit_type in allowed or self.safety_level == SafetyLevel.FULL
778
+
779
+ def _is_web_exploit(self, exploit_type: ExploitType) -> bool:
780
+ """Check if exploit type is web-based."""
781
+ return exploit_type.value.startswith('web_')
782
+
783
+ async def _check_rate_limit(self, target: str) -> None:
784
+ """Check and enforce rate limiting."""
785
+ now = time.time()
786
+ host = urlparse(target).hostname or target
787
+
788
+ if host in self._last_execution:
789
+ elapsed = now - self._last_execution[host]
790
+ if elapsed < self._min_interval:
791
+ wait_time = self._min_interval - elapsed
792
+ logger.debug(f"Rate limiting: waiting {wait_time:.2f}s for {host}")
793
+ await asyncio.sleep(wait_time)
794
+
795
+ self._last_execution[host] = now
796
+
797
+ def _validate_exploit_structure(self, exploit: Dict[str, Any]) -> bool:
798
+ """Validate exploit dictionary structure."""
799
+ required_fields = ['code', 'target', 'type']
800
+ return all(field in exploit for field in required_fields)
801
+
802
+ async def _execute_docker_sandboxed(
803
+ self,
804
+ exploit_code: str,
805
+ target: str,
806
+ exploit_type: ExploitType,
807
+ parameters: Dict[str, Any],
808
+ timeout: int
809
+ ) -> ExploitResult:
810
+ """Execute exploit in Docker sandbox."""
811
+ timestamp = datetime.utcnow()
812
+ chain_of_custody = []
813
+
814
+ # Prepare exploit script
815
+ script_content = self._generate_exploit_script(
816
+ exploit_code, target, exploit_type, parameters
817
+ )
818
+
819
+ # Create temporary directory for volumes
820
+ with tempfile.TemporaryDirectory() as tmpdir:
821
+ script_path = os.path.join(tmpdir, 'exploit.py')
822
+ with open(script_path, 'w') as f:
823
+ f.write(script_content)
824
+
825
+ # Output directory for results
826
+ output_dir = os.path.join(tmpdir, 'output')
827
+ os.makedirs(output_dir, exist_ok=True)
828
+
829
+ try:
830
+ # Build container configuration
831
+ container_config = {
832
+ 'image': self.sandbox_config.image,
833
+ 'command': ['python3', '/exploit/exploit.py'],
834
+ 'volumes': {
835
+ tmpdir: {'bind': '/exploit', 'mode': 'ro'},
836
+ output_dir: {'bind': '/output', 'mode': 'rw'}
837
+ },
838
+ 'network_disabled': self.sandbox_config.network_isolated,
839
+ 'mem_limit': self.sandbox_config.memory_limit,
840
+ 'cpu_quota': int(self.sandbox_config.cpu_limit * 100000),
841
+ 'read_only': self.sandbox_config.read_only_root,
842
+ 'cap_drop': self.sandbox_config.cap_drop,
843
+ 'cap_add': self.sandbox_config.cap_add,
844
+ 'dns': self.sandbox_config.dns_servers,
845
+ 'detach': True,
846
+ 'auto_remove': True
847
+ }
848
+
849
+ # Run container
850
+ chain_of_custody.append({
851
+ 'action': 'container_created',
852
+ 'timestamp': datetime.utcnow().isoformat(),
853
+ 'image': self.sandbox_config.image
854
+ })
855
+
856
+ container = self.docker_client.containers.run(**container_config)
857
+
858
+ # Wait for completion with timeout
859
+ try:
860
+ result = container.wait(timeout=timeout)
861
+ logs = container.logs().decode('utf-8', errors='ignore')
862
+
863
+ # Read output files
864
+ output_data = {}
865
+ for filename in os.listdir(output_dir):
866
+ filepath = os.path.join(output_dir, filename)
867
+ try:
868
+ with open(filepath, 'r') as f:
869
+ output_data[filename] = f.read()
870
+ except Exception:
871
+ output_data[filename] = '[binary]'
872
+
873
+ # Parse results
874
+ success = result.get('StatusCode', 1) == 0
875
+
876
+ # Capture evidence
877
+ evidence = await self.capture_evidence(
878
+ target, exploit_type,
879
+ capture_screenshot=self._is_web_exploit(exploit_type)
880
+ )
881
+
882
+ chain_of_custody.append({
883
+ 'action': 'execution_completed',
884
+ 'timestamp': datetime.utcnow().isoformat(),
885
+ 'exit_code': result.get('StatusCode', -1)
886
+ })
887
+
888
+ return ExploitResult(
889
+ success=success,
890
+ exploit_type=exploit_type,
891
+ target=target,
892
+ timestamp=timestamp,
893
+ evidence=evidence,
894
+ output=logs + "\n" + json.dumps(output_data, indent=2),
895
+ status=ExploitStatus.SUCCESS if success else ExploitStatus.FAILED,
896
+ chain_of_custody=chain_of_custody
897
+ )
898
+
899
+ except Exception:
900
+ container.kill()
901
+ raise
902
+
903
+ except ContainerError as e:
904
+ return ExploitResult(
905
+ success=False,
906
+ exploit_type=exploit_type,
907
+ target=target,
908
+ timestamp=timestamp,
909
+ evidence=Evidence(),
910
+ output=str(e),
911
+ status=ExploitStatus.ERROR,
912
+ error=f"Container error: {str(e)}",
913
+ chain_of_custody=chain_of_custody
914
+ )
915
+ except ImageNotFound:
916
+ return ExploitResult(
917
+ success=False,
918
+ exploit_type=exploit_type,
919
+ target=target,
920
+ timestamp=timestamp,
921
+ evidence=Evidence(),
922
+ output="",
923
+ status=ExploitStatus.ERROR,
924
+ error=f"Docker image '{self.sandbox_config.image}' not found",
925
+ chain_of_custody=chain_of_custody
926
+ )
927
+
928
+ async def _execute_local_sandboxed(
929
+ self,
930
+ exploit_code: str,
931
+ target: str,
932
+ exploit_type: ExploitType,
933
+ parameters: Dict[str, Any],
934
+ timeout: int
935
+ ) -> ExploitResult:
936
+ """Execute exploit locally with restrictions."""
937
+ timestamp = datetime.utcnow()
938
+ chain_of_custody = []
939
+
940
+ # Generate and execute exploit script
941
+ script_content = self._generate_exploit_script(
942
+ exploit_code, target, exploit_type, parameters
943
+ )
944
+
945
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
946
+ f.write(script_content)
947
+ script_path = f.name
948
+
949
+ try:
950
+ chain_of_custody.append({
951
+ 'action': 'local_execution_started',
952
+ 'timestamp': datetime.utcnow().isoformat()
953
+ })
954
+
955
+ # Execute with timeout
956
+ process = await asyncio.create_subprocess_exec(
957
+ 'python3', script_path,
958
+ stdout=asyncio.subprocess.PIPE,
959
+ stderr=asyncio.subprocess.PIPE
960
+ )
961
+
962
+ try:
963
+ stdout, stderr = await asyncio.wait_for(
964
+ process.communicate(), timeout=timeout
965
+ )
966
+
967
+ output = stdout.decode('utf-8', errors='ignore')
968
+ error = stderr.decode('utf-8', errors='ignore')
969
+
970
+ success = process.returncode == 0 and not error
971
+
972
+ # Capture evidence
973
+ evidence = await self.capture_evidence(
974
+ target, exploit_type,
975
+ capture_screenshot=self._is_web_exploit(exploit_type)
976
+ )
977
+
978
+ chain_of_custody.append({
979
+ 'action': 'execution_completed',
980
+ 'timestamp': datetime.utcnow().isoformat(),
981
+ 'exit_code': process.returncode
982
+ })
983
+
984
+ return ExploitResult(
985
+ success=success,
986
+ exploit_type=exploit_type,
987
+ target=target,
988
+ timestamp=timestamp,
989
+ evidence=evidence,
990
+ output=output,
991
+ status=ExploitStatus.SUCCESS if success else ExploitStatus.FAILED,
992
+ error=error if error else None,
993
+ chain_of_custody=chain_of_custody
994
+ )
995
+
996
+ except asyncio.TimeoutError:
997
+ process.kill()
998
+ raise
999
+
1000
+ finally:
1001
+ os.unlink(script_path)
1002
+
1003
+ async def _execute_docker_command(
1004
+ self,
1005
+ command: str,
1006
+ timeout: int,
1007
+ network_access: bool
1008
+ ) -> Dict[str, Any]:
1009
+ """Execute a command in Docker container."""
1010
+ try:
1011
+ container = self.docker_client.containers.run(
1012
+ image=self.sandbox_config.image,
1013
+ command=['sh', '-c', command],
1014
+ network_disabled=not network_access,
1015
+ mem_limit=self.sandbox_config.memory_limit,
1016
+ detach=True,
1017
+ auto_remove=True
1018
+ )
1019
+
1020
+ result = container.wait(timeout=timeout)
1021
+ logs = container.logs().decode('utf-8', errors='ignore')
1022
+
1023
+ return {
1024
+ 'stdout': logs,
1025
+ 'stderr': '',
1026
+ 'return_code': result.get('StatusCode', -1),
1027
+ 'success': result.get('StatusCode', 1) == 0
1028
+ }
1029
+
1030
+ except Exception as e:
1031
+ return {
1032
+ 'stdout': '',
1033
+ 'stderr': str(e),
1034
+ 'return_code': -1,
1035
+ 'success': False
1036
+ }
1037
+
1038
+ async def _execute_local_command(
1039
+ self,
1040
+ command: str,
1041
+ timeout: int
1042
+ ) -> Dict[str, Any]:
1043
+ """Execute command locally."""
1044
+ try:
1045
+ process = await asyncio.create_subprocess_shell(
1046
+ command,
1047
+ stdout=asyncio.subprocess.PIPE,
1048
+ stderr=asyncio.subprocess.PIPE
1049
+ )
1050
+
1051
+ stdout, stderr = await asyncio.wait_for(
1052
+ process.communicate(), timeout=timeout
1053
+ )
1054
+
1055
+ return {
1056
+ 'stdout': stdout.decode('utf-8', errors='ignore'),
1057
+ 'stderr': stderr.decode('utf-8', errors='ignore'),
1058
+ 'return_code': process.returncode,
1059
+ 'success': process.returncode == 0
1060
+ }
1061
+
1062
+ except asyncio.TimeoutError:
1063
+ process.kill()
1064
+ return {
1065
+ 'stdout': '',
1066
+ 'stderr': 'Timeout',
1067
+ 'return_code': -1,
1068
+ 'success': False
1069
+ }
1070
+
1071
+ async def _capture_http_evidence(
1072
+ self,
1073
+ target: str,
1074
+ evidence_dir: str
1075
+ ) -> List[Dict[str, Any]]:
1076
+ """Capture HTTP response evidence."""
1077
+ responses = []
1078
+
1079
+ if not AIOHTTP_AVAILABLE:
1080
+ return responses
1081
+
1082
+ try:
1083
+ # Ensure URL has scheme
1084
+ if not target.startswith(('http://', 'https://')):
1085
+ target = f"http://{target}"
1086
+
1087
+ timeout = aiohttp.ClientTimeout(total=30)
1088
+ async with aiohttp.ClientSession(timeout=timeout) as session:
1089
+ async with session.get(target, ssl=False) as response:
1090
+ body_text = await response.text()
1091
+ response_data = {
1092
+ 'url': str(response.url),
1093
+ 'status': response.status,
1094
+ 'headers': dict(response.headers),
1095
+ 'timestamp': datetime.utcnow().isoformat(),
1096
+ 'body': body_text[:10000] # Limit body size
1097
+ }
1098
+ responses.append(response_data)
1099
+
1100
+ # Save to file
1101
+ http_file = os.path.join(evidence_dir, 'http_response.json')
1102
+ with open(http_file, 'w') as f:
1103
+ json.dump(response_data, f, indent=2, default=str)
1104
+
1105
+ except Exception as e:
1106
+ logger.warning(f"HTTP capture failed: {e}")
1107
+
1108
+ return responses
1109
+
1110
+ async def _capture_screenshot(
1111
+ self,
1112
+ target: str,
1113
+ evidence_dir: str
1114
+ ) -> Optional[str]:
1115
+ """Capture browser screenshot using Playwright."""
1116
+ if not PLAYWRIGHT_AVAILABLE or not self.enable_playwright:
1117
+ return None
1118
+
1119
+ screenshot_path = None
1120
+
1121
+ try:
1122
+ # Ensure URL has scheme
1123
+ if not target.startswith(('http://', 'https://')):
1124
+ target = f"http://{target}"
1125
+
1126
+ async with async_playwright() as p:
1127
+ browser = await p.chromium.launch(headless=True)
1128
+ context = await browser.new_context(
1129
+ viewport={'width': 1920, 'height': 1080},
1130
+ user_agent='ZenAI-ExploitValidator/1.0'
1131
+ )
1132
+
1133
+ page = await context.new_page()
1134
+
1135
+ try:
1136
+ await page.goto(target, wait_until='networkidle', timeout=30000)
1137
+
1138
+ # Capture screenshot
1139
+ screenshot_path = os.path.join(evidence_dir, 'screenshot.png')
1140
+ await page.screenshot(path=screenshot_path, full_page=True)
1141
+
1142
+ # Also capture page content
1143
+ content = await page.content()
1144
+ html_path = os.path.join(evidence_dir, 'page.html')
1145
+ with open(html_path, 'w', encoding='utf-8') as f:
1146
+ f.write(content)
1147
+
1148
+ except Exception as e:
1149
+ logger.warning(f"Page navigation failed: {e}")
1150
+
1151
+ await browser.close()
1152
+
1153
+ except Exception as e:
1154
+ logger.warning(f"Screenshot capture failed: {e}")
1155
+
1156
+ return screenshot_path
1157
+
1158
+ async def _capture_pcap(
1159
+ self,
1160
+ target: str,
1161
+ evidence_dir: str
1162
+ ) -> Optional[str]:
1163
+ """Capture network traffic using tcpdump."""
1164
+ # PCAP capture requires root and is complex in async context
1165
+ # This is a placeholder implementation
1166
+ logger.debug("PCAP capture not implemented - requires elevated privileges")
1167
+ return None
1168
+
1169
+ async def _get_source_ip(self) -> str:
1170
+ """Get the source IP address."""
1171
+ try:
1172
+ # Connect to a public DNS server to determine outbound IP
1173
+ reader, writer = await asyncio.wait_for(
1174
+ asyncio.open_connection('8.8.8.8', 53),
1175
+ timeout=5
1176
+ )
1177
+ sock = writer.get_extra_info('socket')
1178
+ ip = sock.getsockname()[0]
1179
+ writer.close()
1180
+ await writer.wait_closed()
1181
+ return ip
1182
+ except Exception:
1183
+ return 'unknown'
1184
+
1185
+ def _generate_exploit_script(
1186
+ self,
1187
+ exploit_code: str,
1188
+ target: str,
1189
+ exploit_type: ExploitType,
1190
+ parameters: Dict[str, Any]
1191
+ ) -> str:
1192
+ """Generate a safe exploit execution script."""
1193
+
1194
+ # Sanitize inputs
1195
+ safe_target = shlex.quote(target)
1196
+
1197
+ script = f'''#!/usr/bin/env python3
1198
+ """
1199
+ Auto-generated exploit validation script
1200
+ Generated: {datetime.utcnow().isoformat()}
1201
+ Exploit Type: {exploit_type.value}
1202
+ Target: {target}
1203
+ """
1204
+
1205
+ import json
1206
+ import sys
1207
+ import os
1208
+
1209
+ def main():
1210
+ target = {safe_target}
1211
+ parameters = {json.dumps(parameters)}
1212
+
1213
+ # Output directory
1214
+ output_dir = "/output" if os.path.exists("/output") else "."
1215
+
1216
+ result = {{
1217
+ "success": False,
1218
+ "target": target,
1219
+ "output": "",
1220
+ "error": None
1221
+ }}
1222
+
1223
+ try:
1224
+ # User exploit code
1225
+ {self._indent_code(exploit_code, 8)}
1226
+
1227
+ result["success"] = True
1228
+ result["output"] = "Exploit executed successfully"
1229
+
1230
+ except Exception as e:
1231
+ result["error"] = str(e)
1232
+ result["output"] = f"Exploit failed: {{e}}"
1233
+
1234
+ # Write results
1235
+ with open(os.path.join(output_dir, "result.json"), "w") as f:
1236
+ json.dump(result, f, indent=2)
1237
+
1238
+ print(json.dumps(result))
1239
+ return 0 if result["success"] else 1
1240
+
1241
+ if __name__ == "__main__":
1242
+ sys.exit(main())
1243
+ '''
1244
+ return script
1245
+
1246
+ def _indent_code(self, code: str, indent: int) -> str:
1247
+ """Indent code block for script generation."""
1248
+ lines = code.split('\n')
1249
+ spaces = ' ' * indent
1250
+ return '\n'.join(spaces + line for line in lines)
1251
+
1252
+
1253
+ class ExploitValidatorPool:
1254
+ """
1255
+ Pool of ExploitValidators for concurrent execution.
1256
+
1257
+ Manages multiple validators with load balancing and
1258
+ resource management.
1259
+ """
1260
+
1261
+ def __init__(
1262
+ self,
1263
+ pool_size: int = 3,
1264
+ safety_level: SafetyLevel = SafetyLevel.CONTROLLED,
1265
+ scope_config: Optional[ScopeConfig] = None
1266
+ ):
1267
+ """
1268
+ Initialize validator pool.
1269
+
1270
+ Args:
1271
+ pool_size: Number of validators in pool
1272
+ safety_level: Safety level for all validators
1273
+ scope_config: Scope configuration
1274
+ """
1275
+ self.pool_size = pool_size
1276
+ self.safety_level = safety_level
1277
+ self.scope_config = scope_config or ScopeConfig()
1278
+
1279
+ self._validators: List[ExploitValidator] = []
1280
+ self._queue: asyncio.Queue = asyncio.Queue()
1281
+ self._semaphore = asyncio.Semaphore(pool_size)
1282
+
1283
+ # Statistics
1284
+ self._stats = {
1285
+ 'total_executed': 0,
1286
+ 'successful': 0,
1287
+ 'failed': 0,
1288
+ 'blocked': 0
1289
+ }
1290
+
1291
+ async def initialize(self) -> None:
1292
+ """Initialize all validators in the pool."""
1293
+ for i in range(self.pool_size):
1294
+ validator = ExploitValidator(
1295
+ safety_level=self.safety_level,
1296
+ scope_config=self.scope_config
1297
+ )
1298
+ self._validators.append(validator)
1299
+ logger.info(f"Validator pool initialized with {self.pool_size} validators")
1300
+
1301
+ async def submit(
1302
+ self,
1303
+ exploit_code: str,
1304
+ target: str,
1305
+ exploit_type: ExploitType,
1306
+ parameters: Optional[Dict[str, Any]] = None
1307
+ ) -> ExploitResult:
1308
+ """
1309
+ Submit an exploit for validation.
1310
+
1311
+ Args:
1312
+ exploit_code: Exploit code to execute
1313
+ target: Target for exploitation
1314
+ exploit_type: Type of exploit
1315
+ parameters: Additional parameters
1316
+
1317
+ Returns:
1318
+ ExploitResult from validation
1319
+ """
1320
+ async with self._semaphore:
1321
+ # Round-robin selection
1322
+ validator = self._validators[
1323
+ self._stats['total_executed'] % len(self._validators)
1324
+ ]
1325
+
1326
+ self._stats['total_executed'] += 1
1327
+
1328
+ result = await validator.validate(
1329
+ exploit_code=exploit_code,
1330
+ target=target,
1331
+ exploit_type=exploit_type,
1332
+ parameters=parameters
1333
+ )
1334
+
1335
+ # Update statistics
1336
+ if result.success:
1337
+ self._stats['successful'] += 1
1338
+ elif result.status == ExploitStatus.BLOCKED:
1339
+ self._stats['blocked'] += 1
1340
+ else:
1341
+ self._stats['failed'] += 1
1342
+
1343
+ return result
1344
+
1345
+ async def submit_batch(
1346
+ self,
1347
+ exploits: List[Dict[str, Any]]
1348
+ ) -> List[ExploitResult]:
1349
+ """
1350
+ Submit multiple exploits for validation.
1351
+
1352
+ Args:
1353
+ exploits: List of exploit dictionaries
1354
+
1355
+ Returns:
1356
+ List of ExploitResults
1357
+ """
1358
+ tasks = []
1359
+ for exploit in exploits:
1360
+ task = self.submit(
1361
+ exploit_code=exploit['code'],
1362
+ target=exploit['target'],
1363
+ exploit_type=ExploitType(exploit.get('type', 'web_rce')),
1364
+ parameters=exploit.get('parameters', {})
1365
+ )
1366
+ tasks.append(task)
1367
+
1368
+ return await asyncio.gather(*tasks, return_exceptions=True)
1369
+
1370
+ def get_stats(self) -> Dict[str, int]:
1371
+ """Get pool statistics."""
1372
+ return self._stats.copy()
1373
+
1374
+ def kill_all(self) -> None:
1375
+ """Activate kill switch on all validators."""
1376
+ for validator in self._validators:
1377
+ validator.kill_switch()
1378
+
1379
+
1380
+ # Convenience functions for common use cases
1381
+
1382
+ async def validate_sql_injection(
1383
+ target: str,
1384
+ parameter: str,
1385
+ payload: str,
1386
+ method: str = "GET",
1387
+ **kwargs
1388
+ ) -> ExploitResult:
1389
+ """
1390
+ Validate SQL injection vulnerability.
1391
+
1392
+ Args:
1393
+ target: Target URL
1394
+ parameter: Vulnerable parameter
1395
+ payload: SQL injection payload
1396
+ method: HTTP method
1397
+ **kwargs: Additional options for ExploitValidator
1398
+
1399
+ Returns:
1400
+ ExploitResult
1401
+ """
1402
+ exploit_code = f'''
1403
+ import requests
1404
+
1405
+ url = "{target}"
1406
+ params = {{"{parameter}": "{payload}"}}
1407
+ response = requests.{method.lower()}(url, params=params, timeout=30)
1408
+
1409
+ # Check for SQL error indicators
1410
+ sql_errors = [
1411
+ "sql syntax", "mysql_fetch", "pg_query", "ora-",
1412
+ "sqlserver", "jdbc", "odbc", "syntax error"
1413
+ ]
1414
+
1415
+ found_error = any(err in response.text.lower() for err in sql_errors)
1416
+ print(f"Response status: {{response.status_code}}")
1417
+ print(f"SQL error detected: {{found_error}}")
1418
+ print(f"Response length: {{len(response.text)}}")
1419
+ '''
1420
+
1421
+ validator = ExploitValidator(**kwargs)
1422
+ return await validator.validate(
1423
+ exploit_code=exploit_code,
1424
+ target=target,
1425
+ exploit_type=ExploitType.WEB_SQLI
1426
+ )
1427
+
1428
+
1429
+ async def validate_xss(
1430
+ target: str,
1431
+ parameter: str,
1432
+ payload: str = "<script>alert(1)</script>",
1433
+ **kwargs
1434
+ ) -> ExploitResult:
1435
+ """
1436
+ Validate XSS vulnerability.
1437
+
1438
+ Args:
1439
+ target: Target URL
1440
+ parameter: Vulnerable parameter
1441
+ payload: XSS payload
1442
+ **kwargs: Additional options for ExploitValidator
1443
+
1444
+ Returns:
1445
+ ExploitResult
1446
+ """
1447
+ exploit_code = f'''
1448
+ import requests
1449
+
1450
+ url = "{target}"
1451
+ payload = "{payload}"
1452
+ response = requests.get(url, params={{"{parameter}": payload}}, timeout=30)
1453
+
1454
+ # Check if payload is reflected
1455
+ is_reflected = payload in response.text
1456
+ print(f"Payload reflected: {{is_reflected}}")
1457
+ print(f"Response status: {{response.status_code}}")
1458
+
1459
+ if is_reflected:
1460
+ print("XSS vulnerability confirmed - payload reflected")
1461
+ else:
1462
+ print("Payload not reflected in response")
1463
+ '''
1464
+
1465
+ validator = ExploitValidator(**kwargs)
1466
+ return await validator.validate(
1467
+ exploit_code=exploit_code,
1468
+ target=target,
1469
+ exploit_type=ExploitType.WEB_XSS
1470
+ )
1471
+
1472
+
1473
+ async def validate_command_injection(
1474
+ target: str,
1475
+ parameter: str,
1476
+ command: str = "echo ZENAI_TEST",
1477
+ **kwargs
1478
+ ) -> ExploitResult:
1479
+ """
1480
+ Validate command injection vulnerability.
1481
+
1482
+ Args:
1483
+ target: Target URL
1484
+ parameter: Vulnerable parameter
1485
+ command: Command to inject
1486
+ **kwargs: Additional options for ExploitValidator
1487
+
1488
+ Returns:
1489
+ ExploitResult
1490
+ """
1491
+ exploit_code = f'''
1492
+ import requests
1493
+ import time
1494
+
1495
+ url = "{target}"
1496
+
1497
+ # Test command injection with timing
1498
+ payload = "; {command}; #"
1499
+ start = time.time()
1500
+ response = requests.get(url, params={{"{parameter}": payload}}, timeout=60)
1501
+ elapsed = time.time() - start
1502
+
1503
+ print(f"Response time: {{elapsed:.2f}}s")
1504
+ print(f"Response status: {{response.status_code}}")
1505
+
1506
+ # Check for command output
1507
+ if "ZENAI_TEST" in response.text:
1508
+ print("Command injection confirmed - output reflected")
1509
+ elif elapsed > 4:
1510
+ print("Possible blind command injection - timing detected")
1511
+ else:
1512
+ print("Command injection not confirmed")
1513
+ '''
1514
+
1515
+ validator = ExploitValidator(**kwargs)
1516
+ return await validator.validate(
1517
+ exploit_code=exploit_code,
1518
+ target=target,
1519
+ exploit_type=ExploitType.WEB_CMD_INJECTION
1520
+ )
1521
+
1522
+
1523
+ # Export public API
1524
+ __all__ = [
1525
+ 'ExploitValidator',
1526
+ 'ExploitValidatorPool',
1527
+ 'ExploitResult',
1528
+ 'ExploitType',
1529
+ 'ExploitStatus',
1530
+ 'SafetyLevel',
1531
+ 'Evidence',
1532
+ 'ScopeConfig',
1533
+ 'SandboxConfig',
1534
+ 'validate_sql_injection',
1535
+ 'validate_xss',
1536
+ 'validate_command_injection',
1537
+ ]