Coverage for src/alprina_cli/tools/security/exploit.py: 21%
117 statements
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-14 11:27 +0100
« prev ^ index » next coverage.py v7.11.3, created at 2025-11-14 11:27 +0100
1"""
2Exploit Testing Tool
4Context Engineering:
5- Safe exploitation testing for educational/authorized use
6- Returns structured exploit results
7- Built-in safety checks and consent verification
8- Educational mode by default
10Educational exploitation testing - authorized use only.
11"""
13from typing import Dict, Any, List, Literal
14from pydantic import BaseModel, Field
15from loguru import logger
16from pathlib import Path
17import re
19from alprina_cli.tools.base import AlprinaToolBase, ToolOk, ToolError
22class ExploitParams(BaseModel):
23 """
24 Parameters for exploit testing.
26 Context: Focused schema for exploitation testing.
27 """
28 target: str = Field(
29 description="Target to test (file, directory, or URL)"
30 )
31 exploit_type: Literal["safe", "poc", "educational"] = Field(
32 default="safe",
33 description="Exploit mode: safe (non-destructive), poc (proof-of-concept), educational (learning)"
34 )
35 vulnerability: str = Field(
36 default="",
37 description="Specific vulnerability to test (e.g., 'sql_injection', 'xss', 'path_traversal')"
38 )
39 max_attempts: int = Field(
40 default=5,
41 description="Maximum exploit attempts"
42 )
45class ExploitTool(AlprinaToolBase[ExploitParams]):
46 """
47 Exploit testing tool for authorized security testing.
49 Context Engineering Benefits:
50 - Safe mode by default (non-destructive)
51 - Educational focus
52 - Structured exploit results
53 - Built-in safety checks
55 IMPORTANT: This tool is for:
56 - Educational purposes
57 - Authorized penetration testing
58 - CTF competitions
59 - Security research with proper authorization
61 Exploit Types:
62 - safe: Non-destructive testing only
63 - poc: Proof-of-concept demonstrations
64 - educational: Learning and training
66 Supported Vulnerabilities:
67 - sql_injection: SQL injection testing
68 - xss: Cross-site scripting testing
69 - path_traversal: Path traversal testing
70 - command_injection: Command injection testing
72 Usage:
73 ```python
74 tool = ExploitTool()
75 result = await tool.execute(ExploitParams(
76 target="./test_app",
77 exploit_type="educational",
78 vulnerability="sql_injection"
79 ))
80 ```
81 """
83 name: str = "Exploit"
84 description: str = """Exploit testing for authorized security testing.
86AUTHORIZED USE ONLY - For education, pentesting, CTF, research.
88Capabilities:
89- SQL injection testing
90- XSS testing
91- Path traversal testing
92- Command injection testing
94Returns: Structured exploit results with safety information"""
95 params: type[ExploitParams] = ExploitParams
97 async def execute(self, params: ExploitParams) -> ToolOk | ToolError:
98 """
99 Execute exploit testing.
101 Context: Returns structured, educational results.
102 """
103 logger.info(f"Exploit: {params.target} (type={params.exploit_type}, vuln={params.vulnerability})")
105 try:
106 # Safety check: Ensure safe mode
107 if params.exploit_type not in ["safe", "poc", "educational"]:
108 return ToolError(
109 message="Only safe, poc, and educational modes are supported",
110 brief="Invalid exploit mode"
111 )
113 # Determine target type
114 target_path = Path(params.target).expanduser()
115 is_local = target_path.exists()
117 if is_local:
118 results = await self._exploit_local(params, target_path)
119 else:
120 results = await self._exploit_remote(params)
122 # Limit attempts
123 if len(results) > params.max_attempts:
124 results = results[:params.max_attempts]
125 truncated = True
126 else:
127 truncated = False
129 # Calculate success rate
130 successful = sum(1 for r in results if r.get("successful", False))
131 success_rate = (successful / len(results) * 100) if results else 0
133 return ToolOk(
134 content={
135 "target": params.target,
136 "exploit_type": params.exploit_type,
137 "vulnerability": params.vulnerability or "general",
138 "results": results,
139 "summary": {
140 "total_attempts": len(results),
141 "successful": successful,
142 "success_rate": success_rate,
143 "truncated": truncated,
144 "target_type": "local" if is_local else "remote"
145 },
146 "safety_notice": "This tool is for authorized testing only. Always obtain proper authorization."
147 }
148 )
150 except Exception as e:
151 logger.error(f"Exploit testing failed: {e}")
152 return ToolError(
153 message=f"Exploit testing failed: {str(e)}",
154 brief="Exploit failed"
155 )
157 async def _exploit_local(
158 self,
159 params: ExploitParams,
160 target_path: Path
161 ) -> List[Dict[str, Any]]:
162 """
163 Test exploits on local target.
165 Context: Safe, educational exploitation testing.
166 """
167 results = []
169 if target_path.is_file():
170 results.extend(self._test_file_exploits(target_path, params))
171 else:
172 # Test directory
173 files = list(target_path.rglob("*"))
174 for file_path in files:
175 if file_path.is_file():
176 results.extend(self._test_file_exploits(file_path, params))
178 # Limit attempts
179 if len(results) >= params.max_attempts:
180 break
182 return results
184 def _test_file_exploits(
185 self,
186 file_path: Path,
187 params: ExploitParams
188 ) -> List[Dict[str, Any]]:
189 """Test exploits on individual file"""
190 results = []
192 try:
193 # Skip binary files
194 if self._is_binary(file_path):
195 return results
197 content = file_path.read_text(errors="ignore")
198 lines = content.splitlines()
200 # Test specific vulnerability or all
201 if not params.vulnerability or params.vulnerability == "sql_injection":
202 results.extend(self._test_sql_injection(file_path, content, lines))
204 if not params.vulnerability or params.vulnerability == "xss":
205 results.extend(self._test_xss(file_path, content, lines))
207 if not params.vulnerability or params.vulnerability == "path_traversal":
208 results.extend(self._test_path_traversal(file_path, content, lines))
210 if not params.vulnerability or params.vulnerability == "command_injection":
211 results.extend(self._test_command_injection(file_path, content, lines))
213 except Exception as e:
214 logger.warning(f"Could not test {file_path}: {e}")
216 return results
218 def _test_sql_injection(
219 self,
220 file_path: Path,
221 content: str,
222 lines: List[str]
223 ) -> List[Dict[str, Any]]:
224 """Test SQL injection vulnerabilities (educational)"""
225 results = []
227 # Look for vulnerable SQL patterns
228 vulnerable_patterns = [
229 (r"execute\([^)]*\+[^)]*\)", "String concatenation in SQL"),
230 (r'SELECT.*"\s*\+\s*', "SQL query with concatenation"),
231 (r"\.format\(.*SELECT", "format() with SQL query"),
232 ]
234 for pattern, description in vulnerable_patterns:
235 matches = re.finditer(pattern, content, re.IGNORECASE)
236 for match in matches:
237 line_num = content[:match.start()].count('\n') + 1
239 # Educational exploit payloads
240 test_payloads = [
241 "' OR '1'='1",
242 "1' UNION SELECT NULL--",
243 "' OR 1=1--"
244 ]
246 results.append({
247 "vulnerability": "sql_injection",
248 "file": str(file_path),
249 "line_number": line_num,
250 "description": description,
251 "matched_code": lines[line_num - 1].strip()[:80],
252 "successful": False, # Safe mode - don't actually exploit
253 "payloads_tested": test_payloads,
254 "educational_note": "Vulnerable pattern detected. In real testing, try payloads to confirm.",
255 "severity": "HIGH"
256 })
258 return results
260 def _test_xss(
261 self,
262 file_path: Path,
263 content: str,
264 lines: List[str]
265 ) -> List[Dict[str, Any]]:
266 """Test XSS vulnerabilities (educational)"""
267 results = []
269 # Look for unescaped user input
270 xss_patterns = [
271 (r"\.innerHTML\s*=", "Direct innerHTML assignment"),
272 (r"document\.write\(", "document.write usage"),
273 (r"\.html\([^)]*\+", "jQuery html() with concatenation"),
274 ]
276 for pattern, description in xss_patterns:
277 matches = re.finditer(pattern, content, re.IGNORECASE)
278 for match in matches:
279 line_num = content[:match.start()].count('\n') + 1
281 test_payloads = [
282 "<script>alert('XSS')</script>",
283 "<img src=x onerror=alert('XSS')>",
284 "<svg onload=alert('XSS')>"
285 ]
287 results.append({
288 "vulnerability": "xss",
289 "file": str(file_path),
290 "line_number": line_num,
291 "description": description,
292 "matched_code": lines[line_num - 1].strip()[:80],
293 "successful": False,
294 "payloads_tested": test_payloads,
295 "educational_note": "Potential XSS vector. Test with payloads in controlled environment.",
296 "severity": "MEDIUM"
297 })
299 return results
301 def _test_path_traversal(
302 self,
303 file_path: Path,
304 content: str,
305 lines: List[str]
306 ) -> List[Dict[str, Any]]:
307 """Test path traversal vulnerabilities (educational)"""
308 results = []
310 # Look for file operations with user input
311 traversal_patterns = [
312 (r"open\([^)]*\+[^)]*\)", "File open with concatenation"),
313 (r"Path\([^)]*\+[^)]*\)", "Path construction with concatenation"),
314 (r"readFile\([^)]*\+", "readFile with concatenation"),
315 (r"=\s*[^+]*\+\s*user[_a-zA-Z]*.*\n.*open\(", "File path with user input"),
316 ]
318 for pattern, description in traversal_patterns:
319 matches = re.finditer(pattern, content, re.IGNORECASE)
320 for match in matches:
321 line_num = content[:match.start()].count('\n') + 1
323 test_payloads = [
324 "../../../etc/passwd",
325 "..\\..\\..\\windows\\system32\\config\\sam",
326 "....//....//....//etc/passwd"
327 ]
329 results.append({
330 "vulnerability": "path_traversal",
331 "file": str(file_path),
332 "line_number": line_num,
333 "description": description,
334 "matched_code": lines[line_num - 1].strip()[:80],
335 "successful": False,
336 "payloads_tested": test_payloads,
337 "educational_note": "Potential path traversal. Validate and sanitize file paths.",
338 "severity": "HIGH"
339 })
341 return results
343 def _test_command_injection(
344 self,
345 file_path: Path,
346 content: str,
347 lines: List[str]
348 ) -> List[Dict[str, Any]]:
349 """Test command injection vulnerabilities (educational)"""
350 results = []
352 # Look for dangerous functions with user input
353 cmd_patterns = [
354 (r"os\.system\([^)]*\+[^)]*\)", "os.system with concatenation"),
355 (r"subprocess\.call\([^)]*\+[^)]*\)", "subprocess with concatenation"),
356 (r"eval\(", "eval() usage"),
357 (r"exec\(", "exec() usage"),
358 ]
360 for pattern, description in cmd_patterns:
361 matches = re.finditer(pattern, content, re.IGNORECASE)
362 for match in matches:
363 line_num = content[:match.start()].count('\n') + 1
365 test_payloads = [
366 "; ls -la",
367 "| whoami",
368 "&& cat /etc/passwd"
369 ]
371 results.append({
372 "vulnerability": "command_injection",
373 "file": str(file_path),
374 "line_number": line_num,
375 "description": description,
376 "matched_code": lines[line_num - 1].strip()[:80],
377 "successful": False,
378 "payloads_tested": test_payloads,
379 "educational_note": "Command injection risk. Never execute user input directly.",
380 "severity": "CRITICAL"
381 })
383 return results
385 async def _exploit_remote(self, params: ExploitParams) -> List[Dict[str, Any]]:
386 """
387 Test exploits on remote target.
389 Context: Educational remote testing.
390 """
391 results = []
393 # Educational notice for remote testing
394 results.append({
395 "vulnerability": "remote_testing",
396 "description": "Remote exploit testing",
397 "successful": False,
398 "educational_note": (
399 "Remote exploitation requires proper authorization. "
400 "This tool provides educational information only. "
401 "For real testing, use tools like Burp Suite, OWASP ZAP, or Metasploit."
402 ),
403 "severity": "INFO"
404 })
406 # Basic checks
407 if params.target.startswith("http://"):
408 results.append({
409 "vulnerability": "insecure_protocol",
410 "description": "Target uses HTTP (insecure)",
411 "successful": True, # This is a confirmed finding
412 "recommendation": "Use HTTPS instead of HTTP",
413 "severity": "MEDIUM"
414 })
416 return results
418 def _is_binary(self, file_path: Path) -> bool:
419 """Check if file is binary"""
420 try:
421 with open(file_path, 'rb') as f:
422 chunk = f.read(8192)
423 return b'\x00' in chunk
424 except Exception:
425 return False