aiptx 2.0.2__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.

Potentially problematic release.


This version of aiptx might be problematic. Click here for more details.

Files changed (165) hide show
  1. aipt_v2/__init__.py +110 -0
  2. aipt_v2/__main__.py +24 -0
  3. aipt_v2/agents/AIPTxAgent/__init__.py +10 -0
  4. aipt_v2/agents/AIPTxAgent/aiptx_agent.py +211 -0
  5. aipt_v2/agents/__init__.py +24 -0
  6. aipt_v2/agents/base.py +520 -0
  7. aipt_v2/agents/ptt.py +406 -0
  8. aipt_v2/agents/state.py +168 -0
  9. aipt_v2/app.py +960 -0
  10. aipt_v2/browser/__init__.py +31 -0
  11. aipt_v2/browser/automation.py +458 -0
  12. aipt_v2/browser/crawler.py +453 -0
  13. aipt_v2/cli.py +321 -0
  14. aipt_v2/compliance/__init__.py +71 -0
  15. aipt_v2/compliance/compliance_report.py +449 -0
  16. aipt_v2/compliance/framework_mapper.py +424 -0
  17. aipt_v2/compliance/nist_mapping.py +345 -0
  18. aipt_v2/compliance/owasp_mapping.py +330 -0
  19. aipt_v2/compliance/pci_mapping.py +297 -0
  20. aipt_v2/config.py +288 -0
  21. aipt_v2/core/__init__.py +43 -0
  22. aipt_v2/core/agent.py +630 -0
  23. aipt_v2/core/llm.py +395 -0
  24. aipt_v2/core/memory.py +305 -0
  25. aipt_v2/core/ptt.py +329 -0
  26. aipt_v2/database/__init__.py +14 -0
  27. aipt_v2/database/models.py +232 -0
  28. aipt_v2/database/repository.py +384 -0
  29. aipt_v2/docker/__init__.py +23 -0
  30. aipt_v2/docker/builder.py +260 -0
  31. aipt_v2/docker/manager.py +222 -0
  32. aipt_v2/docker/sandbox.py +371 -0
  33. aipt_v2/evasion/__init__.py +58 -0
  34. aipt_v2/evasion/request_obfuscator.py +272 -0
  35. aipt_v2/evasion/tls_fingerprint.py +285 -0
  36. aipt_v2/evasion/ua_rotator.py +301 -0
  37. aipt_v2/evasion/waf_bypass.py +439 -0
  38. aipt_v2/execution/__init__.py +23 -0
  39. aipt_v2/execution/executor.py +302 -0
  40. aipt_v2/execution/parser.py +544 -0
  41. aipt_v2/execution/terminal.py +337 -0
  42. aipt_v2/health.py +437 -0
  43. aipt_v2/intelligence/__init__.py +85 -0
  44. aipt_v2/intelligence/auth.py +520 -0
  45. aipt_v2/intelligence/chaining.py +775 -0
  46. aipt_v2/intelligence/cve_aipt.py +334 -0
  47. aipt_v2/intelligence/cve_info.py +1111 -0
  48. aipt_v2/intelligence/rag.py +239 -0
  49. aipt_v2/intelligence/scope.py +442 -0
  50. aipt_v2/intelligence/searchers/__init__.py +5 -0
  51. aipt_v2/intelligence/searchers/exploitdb_searcher.py +523 -0
  52. aipt_v2/intelligence/searchers/github_searcher.py +467 -0
  53. aipt_v2/intelligence/searchers/google_searcher.py +281 -0
  54. aipt_v2/intelligence/tools.json +443 -0
  55. aipt_v2/intelligence/triage.py +670 -0
  56. aipt_v2/interface/__init__.py +5 -0
  57. aipt_v2/interface/cli.py +230 -0
  58. aipt_v2/interface/main.py +501 -0
  59. aipt_v2/interface/tui.py +1276 -0
  60. aipt_v2/interface/utils.py +583 -0
  61. aipt_v2/llm/__init__.py +39 -0
  62. aipt_v2/llm/config.py +26 -0
  63. aipt_v2/llm/llm.py +514 -0
  64. aipt_v2/llm/memory.py +214 -0
  65. aipt_v2/llm/request_queue.py +89 -0
  66. aipt_v2/llm/utils.py +89 -0
  67. aipt_v2/models/__init__.py +15 -0
  68. aipt_v2/models/findings.py +295 -0
  69. aipt_v2/models/phase_result.py +224 -0
  70. aipt_v2/models/scan_config.py +207 -0
  71. aipt_v2/monitoring/grafana/dashboards/aipt-dashboard.json +355 -0
  72. aipt_v2/monitoring/grafana/dashboards/default.yml +17 -0
  73. aipt_v2/monitoring/grafana/datasources/prometheus.yml +17 -0
  74. aipt_v2/monitoring/prometheus.yml +60 -0
  75. aipt_v2/orchestration/__init__.py +52 -0
  76. aipt_v2/orchestration/pipeline.py +398 -0
  77. aipt_v2/orchestration/progress.py +300 -0
  78. aipt_v2/orchestration/scheduler.py +296 -0
  79. aipt_v2/orchestrator.py +2284 -0
  80. aipt_v2/payloads/__init__.py +27 -0
  81. aipt_v2/payloads/cmdi.py +150 -0
  82. aipt_v2/payloads/sqli.py +263 -0
  83. aipt_v2/payloads/ssrf.py +204 -0
  84. aipt_v2/payloads/templates.py +222 -0
  85. aipt_v2/payloads/traversal.py +166 -0
  86. aipt_v2/payloads/xss.py +204 -0
  87. aipt_v2/prompts/__init__.py +60 -0
  88. aipt_v2/proxy/__init__.py +29 -0
  89. aipt_v2/proxy/history.py +352 -0
  90. aipt_v2/proxy/interceptor.py +452 -0
  91. aipt_v2/recon/__init__.py +44 -0
  92. aipt_v2/recon/dns.py +241 -0
  93. aipt_v2/recon/osint.py +367 -0
  94. aipt_v2/recon/subdomain.py +372 -0
  95. aipt_v2/recon/tech_detect.py +311 -0
  96. aipt_v2/reports/__init__.py +17 -0
  97. aipt_v2/reports/generator.py +313 -0
  98. aipt_v2/reports/html_report.py +378 -0
  99. aipt_v2/runtime/__init__.py +44 -0
  100. aipt_v2/runtime/base.py +30 -0
  101. aipt_v2/runtime/docker.py +401 -0
  102. aipt_v2/runtime/local.py +346 -0
  103. aipt_v2/runtime/tool_server.py +205 -0
  104. aipt_v2/scanners/__init__.py +28 -0
  105. aipt_v2/scanners/base.py +273 -0
  106. aipt_v2/scanners/nikto.py +244 -0
  107. aipt_v2/scanners/nmap.py +402 -0
  108. aipt_v2/scanners/nuclei.py +273 -0
  109. aipt_v2/scanners/web.py +454 -0
  110. aipt_v2/scripts/security_audit.py +366 -0
  111. aipt_v2/telemetry/__init__.py +7 -0
  112. aipt_v2/telemetry/tracer.py +347 -0
  113. aipt_v2/terminal/__init__.py +28 -0
  114. aipt_v2/terminal/executor.py +400 -0
  115. aipt_v2/terminal/sandbox.py +350 -0
  116. aipt_v2/tools/__init__.py +44 -0
  117. aipt_v2/tools/active_directory/__init__.py +78 -0
  118. aipt_v2/tools/active_directory/ad_config.py +238 -0
  119. aipt_v2/tools/active_directory/bloodhound_wrapper.py +447 -0
  120. aipt_v2/tools/active_directory/kerberos_attacks.py +430 -0
  121. aipt_v2/tools/active_directory/ldap_enum.py +533 -0
  122. aipt_v2/tools/active_directory/smb_attacks.py +505 -0
  123. aipt_v2/tools/agents_graph/__init__.py +19 -0
  124. aipt_v2/tools/agents_graph/agents_graph_actions.py +69 -0
  125. aipt_v2/tools/api_security/__init__.py +76 -0
  126. aipt_v2/tools/api_security/api_discovery.py +608 -0
  127. aipt_v2/tools/api_security/graphql_scanner.py +622 -0
  128. aipt_v2/tools/api_security/jwt_analyzer.py +577 -0
  129. aipt_v2/tools/api_security/openapi_fuzzer.py +761 -0
  130. aipt_v2/tools/browser/__init__.py +5 -0
  131. aipt_v2/tools/browser/browser_actions.py +238 -0
  132. aipt_v2/tools/browser/browser_instance.py +535 -0
  133. aipt_v2/tools/browser/tab_manager.py +344 -0
  134. aipt_v2/tools/cloud/__init__.py +70 -0
  135. aipt_v2/tools/cloud/cloud_config.py +273 -0
  136. aipt_v2/tools/cloud/cloud_scanner.py +639 -0
  137. aipt_v2/tools/cloud/prowler_tool.py +571 -0
  138. aipt_v2/tools/cloud/scoutsuite_tool.py +359 -0
  139. aipt_v2/tools/executor.py +307 -0
  140. aipt_v2/tools/parser.py +408 -0
  141. aipt_v2/tools/proxy/__init__.py +5 -0
  142. aipt_v2/tools/proxy/proxy_actions.py +103 -0
  143. aipt_v2/tools/proxy/proxy_manager.py +789 -0
  144. aipt_v2/tools/registry.py +196 -0
  145. aipt_v2/tools/scanners/__init__.py +343 -0
  146. aipt_v2/tools/scanners/acunetix_tool.py +712 -0
  147. aipt_v2/tools/scanners/burp_tool.py +631 -0
  148. aipt_v2/tools/scanners/config.py +156 -0
  149. aipt_v2/tools/scanners/nessus_tool.py +588 -0
  150. aipt_v2/tools/scanners/zap_tool.py +612 -0
  151. aipt_v2/tools/terminal/__init__.py +5 -0
  152. aipt_v2/tools/terminal/terminal_actions.py +37 -0
  153. aipt_v2/tools/terminal/terminal_manager.py +153 -0
  154. aipt_v2/tools/terminal/terminal_session.py +449 -0
  155. aipt_v2/tools/tool_processing.py +108 -0
  156. aipt_v2/utils/__init__.py +17 -0
  157. aipt_v2/utils/logging.py +201 -0
  158. aipt_v2/utils/model_manager.py +187 -0
  159. aipt_v2/utils/searchers/__init__.py +269 -0
  160. aiptx-2.0.2.dist-info/METADATA +324 -0
  161. aiptx-2.0.2.dist-info/RECORD +165 -0
  162. aiptx-2.0.2.dist-info/WHEEL +5 -0
  163. aiptx-2.0.2.dist-info/entry_points.txt +7 -0
  164. aiptx-2.0.2.dist-info/licenses/LICENSE +21 -0
  165. aiptx-2.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,631 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Burp Suite Scanner Tool - Plug & Play Integration for AIPT Orchestration
4
+ Provides comprehensive API integration with Burp Suite Pro REST API.
5
+
6
+ Burp Suite Pro REST API Endpoints:
7
+ PUT /configuration - Configure Burp settings
8
+ GET /issue_definitions - Get all issue definitions
9
+ POST /scan - Start a new scan
10
+ GET /scan/[task_id] - Get scan progress and issues
11
+ """
12
+
13
+ import json
14
+ import time
15
+ import logging
16
+ import requests
17
+ from typing import Optional, Dict, List, Any
18
+ from dataclasses import dataclass, field
19
+ from enum import Enum
20
+ from datetime import datetime
21
+ from pathlib import Path
22
+ import urllib3
23
+
24
+ # Disable SSL warnings for self-signed certificates
25
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class ScanStatus(Enum):
31
+ """Burp Suite scan status types."""
32
+ QUEUED = "queued"
33
+ RUNNING = "running"
34
+ PAUSED = "paused"
35
+ SUCCEEDED = "succeeded"
36
+ FAILED = "failed"
37
+ CANCELLED = "cancelled"
38
+
39
+
40
+ class IssueSeverity(Enum):
41
+ """Vulnerability severity levels in Burp."""
42
+ HIGH = "high"
43
+ MEDIUM = "medium"
44
+ LOW = "low"
45
+ INFO = "info"
46
+
47
+
48
+ class IssueConfidence(Enum):
49
+ """Issue confidence levels in Burp."""
50
+ CERTAIN = "certain"
51
+ FIRM = "firm"
52
+ TENTATIVE = "tentative"
53
+
54
+
55
+ @dataclass
56
+ class BurpConfig:
57
+ """Configuration for Burp Suite connection."""
58
+ base_url: str = "http://13.127.28.41:1337/v0.1"
59
+ api_key: str = "t7thBWbImyiP8SA9hojkiFhq9QbHqlcm"
60
+ verify_ssl: bool = False
61
+ timeout: int = 30
62
+
63
+
64
+ @dataclass
65
+ class ScanResult:
66
+ """Result of a Burp Suite scan."""
67
+ task_id: str
68
+ target_url: str
69
+ status: str
70
+ request_count: int = 0
71
+ error_count: int = 0
72
+ insertion_point_count: int = 0
73
+ issue_events: List[Dict] = field(default_factory=list)
74
+ audit_items: List[Dict] = field(default_factory=list)
75
+
76
+
77
+ @dataclass
78
+ class Issue:
79
+ """Security issue/vulnerability from Burp Suite."""
80
+ issue_type: str
81
+ name: str
82
+ severity: str
83
+ confidence: str
84
+ host: str
85
+ path: str
86
+ origin: str
87
+ description: str = ""
88
+ remediation: str = ""
89
+ serial_number: str = ""
90
+ evidence: List[Dict] = field(default_factory=list)
91
+
92
+
93
+ class BurpTool:
94
+ """
95
+ Burp Suite Scanner Tool for AIPT Orchestration.
96
+
97
+ Provides plug-and-play integration with Burp Suite Pro REST API extension.
98
+ Supports scan execution, issue retrieval, and configuration.
99
+
100
+ API Documentation: http://[server]:1337/ (HTML interface)
101
+ """
102
+
103
+ def __init__(self, config: Optional[BurpConfig] = None):
104
+ """Initialize Burp Suite tool with configuration."""
105
+ self.config = config or BurpConfig()
106
+ self.session = requests.Session()
107
+ self._setup_session()
108
+ self._connected = False
109
+ self._issue_definitions: Dict[str, Dict] = {}
110
+
111
+ def _setup_session(self):
112
+ """Setup the requests session."""
113
+ headers = {
114
+ "Content-Type": "application/json",
115
+ "Accept": "application/json"
116
+ }
117
+ # Burp REST API uses API key directly in Authorization header
118
+ if self.config.api_key:
119
+ headers["Authorization"] = self.config.api_key
120
+ self.session.headers.update(headers)
121
+ self.session.verify = self.config.verify_ssl
122
+
123
+ def _request(self, method: str, endpoint: str, data: Optional[Dict] = None,
124
+ params: Optional[Dict] = None) -> Any:
125
+ """Make an API request to Burp Suite."""
126
+ # Ensure base_url doesn't have trailing slash and endpoint doesn't have leading slash
127
+ base = self.config.base_url.rstrip('/')
128
+ ep = endpoint.lstrip('/')
129
+ url = f"{base}/{ep}"
130
+ try:
131
+ response = self.session.request(
132
+ method=method,
133
+ url=url,
134
+ json=data,
135
+ params=params,
136
+ timeout=self.config.timeout
137
+ )
138
+ response.raise_for_status()
139
+
140
+ # Handle different response types
141
+ if response.content:
142
+ content_type = response.headers.get('Content-Type', '')
143
+ if 'application/json' in content_type:
144
+ return response.json()
145
+ return response.text
146
+
147
+ # For 201/202 responses, return location header
148
+ if response.status_code in [201, 202]:
149
+ location = response.headers.get('Location', '')
150
+ return {"success": True, "location": location, "task_id": location.split('/')[-1] if location else ""}
151
+
152
+ return {"success": True}
153
+ except requests.exceptions.RequestException as e:
154
+ logger.error(f"Burp Suite API error: {e}")
155
+ raise
156
+
157
+ # ==================== Connection ====================
158
+
159
+ def connect(self) -> bool:
160
+ """Test connection to Burp Suite."""
161
+ try:
162
+ # Check if server is reachable by hitting the versioned endpoint
163
+ response = self.session.get(f"{self.config.base_url}/", timeout=self.config.timeout)
164
+
165
+ # Check for Burp version header (present on all responses)
166
+ burp_version = response.headers.get('X-Burp-Version', '')
167
+
168
+ if not burp_version:
169
+ # Try root URL for version header
170
+ root_url = self.config.base_url.replace('/v0.1', '').replace('/v1', '')
171
+ root_response = self.session.get(root_url, timeout=self.config.timeout)
172
+ burp_version = root_response.headers.get('X-Burp-Version', '')
173
+
174
+ if burp_version:
175
+ logger.info(f"Burp Suite version: {burp_version}")
176
+ self._connected = True
177
+
178
+ # Try to get issue definitions (optional - not all versions support this)
179
+ try:
180
+ result = self._request("GET", "issue_definitions")
181
+ if isinstance(result, list):
182
+ for issue_def in result:
183
+ type_index = issue_def.get("type_index", "")
184
+ if type_index:
185
+ self._issue_definitions[type_index] = issue_def
186
+ logger.info(f"Loaded {len(self._issue_definitions)} issue definitions")
187
+ except Exception:
188
+ # issue_definitions not available in this version - that's OK
189
+ logger.info("Issue definitions endpoint not available (normal for some versions)")
190
+
191
+ logger.info(f"Connected to Burp Suite API at {self.config.base_url}")
192
+ return True
193
+ else:
194
+ logger.error("No X-Burp-Version header found - server may not be Burp Suite")
195
+ return False
196
+
197
+ except requests.exceptions.ConnectionError as e:
198
+ logger.error(f"Cannot connect to Burp Suite at {self.config.base_url}: {e}")
199
+ return False
200
+ except Exception as e:
201
+ logger.error(f"Failed to connect to Burp Suite: {e}")
202
+ return False
203
+
204
+ def get_info(self) -> Dict[str, Any]:
205
+ """Get Burp Suite instance information."""
206
+ return {
207
+ "server": self.config.base_url,
208
+ "connected": self._connected,
209
+ "issue_definitions_loaded": len(self._issue_definitions),
210
+ "type": "Burp Suite Pro REST API"
211
+ }
212
+
213
+ def is_connected(self) -> bool:
214
+ """Check if connected to Burp Suite."""
215
+ return self._connected
216
+
217
+ # ==================== Configuration ====================
218
+
219
+ def configure(self, config_data: Dict[str, Any]) -> bool:
220
+ """
221
+ Configure Burp Suite settings.
222
+
223
+ Args:
224
+ config_data: Configuration dictionary (see Burp API docs)
225
+
226
+ Returns:
227
+ Success status
228
+ """
229
+ try:
230
+ self._request("PUT", "/configuration", data=config_data)
231
+ logger.info("Burp configuration updated")
232
+ return True
233
+ except Exception as e:
234
+ logger.error(f"Failed to configure Burp: {e}")
235
+ return False
236
+
237
+ def set_scope(self, urls: List[str], exclude_urls: List[str] = None) -> bool:
238
+ """
239
+ Set target scope in Burp.
240
+
241
+ Args:
242
+ urls: URLs to include in scope
243
+ exclude_urls: URLs to exclude from scope
244
+ """
245
+ config = {
246
+ "target": {
247
+ "scope": {
248
+ "include": [{"enabled": True, "prefix": url} for url in urls],
249
+ "exclude": [{"enabled": True, "prefix": url} for url in (exclude_urls or [])]
250
+ }
251
+ }
252
+ }
253
+ return self.configure(config)
254
+
255
+ # ==================== Issue Definitions ====================
256
+
257
+ def get_issue_definitions(self) -> List[Dict[str, Any]]:
258
+ """Get all Burp issue definitions."""
259
+ if not self._issue_definitions:
260
+ result = self._request("GET", "/issue_definitions")
261
+ if isinstance(result, list):
262
+ for issue_def in result:
263
+ type_index = issue_def.get("type_index", "")
264
+ if type_index:
265
+ self._issue_definitions[type_index] = issue_def
266
+ return list(self._issue_definitions.values())
267
+
268
+ def get_issue_definition(self, type_index: str) -> Optional[Dict[str, Any]]:
269
+ """Get a specific issue definition by type."""
270
+ if not self._issue_definitions:
271
+ self.get_issue_definitions()
272
+ return self._issue_definitions.get(type_index)
273
+
274
+ # ==================== Scan Management ====================
275
+
276
+ def start_scan(self, url: str, scope: List[str] = None,
277
+ configuration: Dict = None) -> str:
278
+ """
279
+ Start a new scan.
280
+
281
+ Args:
282
+ url: Target URL to scan
283
+ scope: Additional URLs for scope (optional)
284
+ configuration: Scan configuration (optional)
285
+
286
+ Returns:
287
+ Task ID for the scan
288
+ """
289
+ scan_data = {
290
+ "urls": [url] + (scope or [])
291
+ }
292
+
293
+ if configuration:
294
+ scan_data["configuration"] = configuration
295
+
296
+ result = self._request("POST", "/scan", data=scan_data)
297
+
298
+ task_id = ""
299
+ if isinstance(result, dict):
300
+ task_id = result.get("task_id", "")
301
+ if not task_id and result.get("location"):
302
+ task_id = result["location"].split("/")[-1]
303
+
304
+ logger.info(f"Started scan: {task_id} for {url}")
305
+ return task_id
306
+
307
+ def scan_url(self, url: str) -> str:
308
+ """
309
+ Convenience method to scan a URL directly.
310
+
311
+ Args:
312
+ url: URL to scan
313
+
314
+ Returns:
315
+ Task ID
316
+ """
317
+ return self.start_scan(url)
318
+
319
+ def get_scan_status(self, task_id: str, after: str = None,
320
+ issue_events: int = None) -> ScanResult:
321
+ """
322
+ Get current status of a scan.
323
+
324
+ Args:
325
+ task_id: Scan task ID
326
+ after: Return events after this marker (for incremental updates)
327
+ issue_events: Maximum number of issue events to return
328
+
329
+ Returns:
330
+ ScanResult with current status
331
+ """
332
+ params = {}
333
+ if after:
334
+ params["after"] = after
335
+ if issue_events:
336
+ params["issue_events"] = issue_events
337
+
338
+ result = self._request("GET", f"/scan/{task_id}", params=params)
339
+
340
+ if not isinstance(result, dict):
341
+ result = {}
342
+
343
+ return ScanResult(
344
+ task_id=task_id,
345
+ target_url=result.get("scan_metrics", {}).get("crawl_and_audit_urls", [""])[0] if result.get("scan_metrics") else "",
346
+ status=result.get("scan_status", "unknown"),
347
+ request_count=result.get("scan_metrics", {}).get("request_count", 0),
348
+ error_count=result.get("scan_metrics", {}).get("crawl_and_audit_error_count", 0),
349
+ insertion_point_count=result.get("scan_metrics", {}).get("insertion_point_count", 0),
350
+ issue_events=result.get("issue_events", []),
351
+ audit_items=result.get("audit_items", [])
352
+ )
353
+
354
+ def wait_for_scan(self, task_id: str, timeout: int = 3600,
355
+ poll_interval: int = 30,
356
+ callback: callable = None) -> ScanResult:
357
+ """
358
+ Wait for a scan to complete.
359
+
360
+ Args:
361
+ task_id: Task ID to wait for
362
+ timeout: Maximum time to wait in seconds
363
+ poll_interval: Time between status checks
364
+ callback: Optional callback function
365
+
366
+ Returns:
367
+ Final ScanResult
368
+ """
369
+ start_time = time.time()
370
+ terminal_statuses = ["succeeded", "failed", "cancelled"]
371
+
372
+ while time.time() - start_time < timeout:
373
+ result = self.get_scan_status(task_id)
374
+
375
+ if callback:
376
+ callback(result)
377
+
378
+ if result.status.lower() in terminal_statuses:
379
+ return result
380
+
381
+ logger.info(f"Scan {task_id}: {result.status} (requests: {result.request_count})")
382
+ time.sleep(poll_interval)
383
+
384
+ raise TimeoutError(f"Scan {task_id} did not complete within {timeout}s")
385
+
386
+ # ==================== Issue Management ====================
387
+
388
+ def get_issues(self, task_id: str) -> List[Issue]:
389
+ """
390
+ Get issues from a scan.
391
+
392
+ Args:
393
+ task_id: Scan task ID
394
+
395
+ Returns:
396
+ List of Issue objects
397
+ """
398
+ result = self.get_scan_status(task_id, issue_events=1000)
399
+ issues = []
400
+
401
+ for event in result.issue_events:
402
+ issue_data = event.get("issue", {})
403
+ type_index = issue_data.get("type_index", "")
404
+
405
+ # Get issue definition for name and description
406
+ issue_def = self.get_issue_definition(type_index) or {}
407
+
408
+ issues.append(Issue(
409
+ issue_type=type_index,
410
+ name=issue_def.get("name", issue_data.get("name", "Unknown")),
411
+ severity=issue_data.get("severity", "info"),
412
+ confidence=issue_data.get("confidence", "tentative"),
413
+ host=issue_data.get("origin", ""),
414
+ path=issue_data.get("path", ""),
415
+ origin=issue_data.get("origin", ""),
416
+ description=issue_def.get("description", ""),
417
+ remediation=issue_def.get("remediation", ""),
418
+ serial_number=str(issue_data.get("serial_number", "")),
419
+ evidence=issue_data.get("evidence", [])
420
+ ))
421
+
422
+ return issues
423
+
424
+ def get_all_issues(self, task_id: str) -> List[Dict[str, Any]]:
425
+ """Get all issues with full details for a scan."""
426
+ issues = self.get_issues(task_id)
427
+ return [self.to_finding(i) for i in issues]
428
+
429
+ # ==================== Statistics ====================
430
+
431
+ def get_scan_summary(self, task_id: str = None) -> Dict[str, Any]:
432
+ """Get scan summary."""
433
+ if not task_id:
434
+ return {
435
+ "connected": self._connected,
436
+ "issue_definitions": len(self._issue_definitions),
437
+ "message": "Provide task_id for scan-specific summary"
438
+ }
439
+
440
+ result = self.get_scan_status(task_id, issue_events=1000)
441
+
442
+ # Count issues by severity
443
+ severity_counts = {"high": 0, "medium": 0, "low": 0, "info": 0}
444
+ for event in result.issue_events:
445
+ sev = event.get("issue", {}).get("severity", "info").lower()
446
+ if sev in severity_counts:
447
+ severity_counts[sev] += 1
448
+
449
+ return {
450
+ "task_id": task_id,
451
+ "status": result.status,
452
+ "request_count": result.request_count,
453
+ "error_count": result.error_count,
454
+ "issue_count": len(result.issue_events),
455
+ "issues_by_severity": severity_counts
456
+ }
457
+
458
+ # ==================== Orchestration Helpers ====================
459
+
460
+ def to_finding(self, issue: Issue) -> Dict[str, Any]:
461
+ """Convert Burp issue to AIPT finding format."""
462
+ return {
463
+ "type": "vulnerability",
464
+ "value": issue.name,
465
+ "description": issue.description or f"{issue.name} at {issue.path}",
466
+ "severity": issue.severity,
467
+ "phase": "scanning",
468
+ "tool": "burpsuite",
469
+ "metadata": {
470
+ "issue_type": issue.issue_type,
471
+ "confidence": issue.confidence,
472
+ "host": issue.host,
473
+ "path": issue.path,
474
+ "origin": issue.origin,
475
+ "remediation": issue.remediation,
476
+ "serial_number": issue.serial_number
477
+ }
478
+ }
479
+
480
+ def export_findings(self, task_id: str, output_path: str = None) -> List[Dict[str, Any]]:
481
+ """
482
+ Export scan findings in AIPT format.
483
+
484
+ Args:
485
+ task_id: Task ID to export
486
+ output_path: Optional path to save JSON
487
+
488
+ Returns:
489
+ List of findings in AIPT format
490
+ """
491
+ issues = self.get_issues(task_id)
492
+ findings = [self.to_finding(i) for i in issues]
493
+
494
+ if output_path:
495
+ with open(output_path, 'w') as f:
496
+ json.dump(findings, f, indent=2)
497
+ logger.info(f"Exported {len(findings)} findings to {output_path}")
498
+
499
+ return findings
500
+
501
+
502
+ # ==================== Standalone Functions for Orchestration ====================
503
+
504
+ # Global instance for quick access
505
+ _burp: Optional[BurpTool] = None
506
+
507
+
508
+ def get_burp(config: Optional[BurpConfig] = None) -> BurpTool:
509
+ """Get or create Burp Suite tool instance."""
510
+ global _burp
511
+ if _burp is None or config is not None:
512
+ _burp = BurpTool(config)
513
+ _burp.connect()
514
+ return _burp
515
+
516
+
517
+ def burp_scan(url: str) -> ScanResult:
518
+ """
519
+ Quick scan function for orchestration.
520
+
521
+ Args:
522
+ url: URL to scan
523
+
524
+ Returns:
525
+ ScanResult
526
+ """
527
+ burp = get_burp()
528
+ task_id = burp.scan_url(url)
529
+ return burp.get_scan_status(task_id)
530
+
531
+
532
+ def burp_status(task_id: str) -> ScanResult:
533
+ """Get scan status."""
534
+ return get_burp().get_scan_status(task_id)
535
+
536
+
537
+ def burp_issues(task_id: str = None, severity: str = None) -> List[Dict[str, Any]]:
538
+ """Get issues as AIPT findings."""
539
+ if not task_id:
540
+ return []
541
+ burp = get_burp()
542
+ issues = burp.get_issues(task_id)
543
+ findings = [burp.to_finding(i) for i in issues]
544
+
545
+ # Filter by severity if specified
546
+ if severity:
547
+ findings = [f for f in findings if f.get("severity", "").lower() == severity.lower()]
548
+
549
+ return findings
550
+
551
+
552
+ def burp_summary(task_id: str = None) -> Dict[str, Any]:
553
+ """Get scan summary."""
554
+ return get_burp().get_scan_summary(task_id)
555
+
556
+
557
+ # ==================== CLI for Testing ====================
558
+
559
+ if __name__ == "__main__":
560
+ import argparse
561
+
562
+ parser = argparse.ArgumentParser(description="Burp Suite Scanner Tool")
563
+ parser.add_argument("command", choices=["test", "scan", "status", "issues", "summary", "definitions"])
564
+ parser.add_argument("--url", help="Target URL for scanning")
565
+ parser.add_argument("--task-id", help="Task ID for status/issues")
566
+
567
+ args = parser.parse_args()
568
+
569
+ config = BurpConfig()
570
+ burp = BurpTool(config)
571
+
572
+ if args.command == "test":
573
+ print("Testing Burp Suite connection...")
574
+ print(f"Server: {config.base_url}")
575
+ if burp.connect():
576
+ info = burp.get_info()
577
+ print(f"✓ Connected to Burp Suite Pro")
578
+ print(f"✓ Issue definitions loaded: {info.get('issue_definitions_loaded')}")
579
+ else:
580
+ print("✗ Connection failed")
581
+
582
+ elif args.command == "definitions":
583
+ print("Loading issue definitions...")
584
+ if burp.connect():
585
+ defs = burp.get_issue_definitions()
586
+ print(f"Found {len(defs)} issue definitions:")
587
+ for d in defs[:10]:
588
+ print(f" - [{d.get('type_index')}] {d.get('name')}")
589
+ if len(defs) > 10:
590
+ print(f" ... and {len(defs) - 10} more")
591
+
592
+ elif args.command == "scan":
593
+ if not args.url:
594
+ print("Error: --url required for scan")
595
+ else:
596
+ if burp.connect():
597
+ task_id = burp.scan_url(args.url)
598
+ print(f"Scan started!")
599
+ print(f"Task ID: {task_id}")
600
+ print(f"Check status: python burp_tool.py status --task-id {task_id}")
601
+
602
+ elif args.command == "status":
603
+ if not args.task_id:
604
+ print("Error: --task-id required")
605
+ else:
606
+ if burp.connect():
607
+ result = burp.get_scan_status(args.task_id)
608
+ print(f"Task ID: {result.task_id}")
609
+ print(f"Status: {result.status}")
610
+ print(f"Requests: {result.request_count}")
611
+ print(f"Errors: {result.error_count}")
612
+ print(f"Issues found: {len(result.issue_events)}")
613
+
614
+ elif args.command == "issues":
615
+ if not args.task_id:
616
+ print("Error: --task-id required")
617
+ else:
618
+ if burp.connect():
619
+ findings = burp.get_all_issues(args.task_id)
620
+ print(f"Found {len(findings)} issues:")
621
+ for f in findings[:10]:
622
+ print(f" [{f['severity'].upper()}] {f['value']}")
623
+ if len(findings) > 10:
624
+ print(f" ... and {len(findings) - 10} more")
625
+
626
+ elif args.command == "summary":
627
+ if burp.connect():
628
+ summary = burp.get_scan_summary(args.task_id)
629
+ print("Burp Suite Summary:")
630
+ for k, v in summary.items():
631
+ print(f" {k}: {v}")