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,626 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIPT Feedback Learning System
|
|
3
|
+
|
|
4
|
+
Learns from exploitation attempts to improve future scans:
|
|
5
|
+
- Records successful/failed exploitation attempts
|
|
6
|
+
- Builds knowledge of what works for specific contexts
|
|
7
|
+
- Suggests optimal payloads based on historical success
|
|
8
|
+
- Tracks WAF bypass techniques that work
|
|
9
|
+
|
|
10
|
+
This creates a feedback loop that makes AIPT smarter over time.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import sqlite3
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Optional
|
|
21
|
+
|
|
22
|
+
from aipt_v2.models.findings import VulnerabilityType
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ExploitAttempt:
|
|
29
|
+
"""Record of an exploitation attempt."""
|
|
30
|
+
vuln_type: str
|
|
31
|
+
target_url: str
|
|
32
|
+
payload: str
|
|
33
|
+
success: bool
|
|
34
|
+
tech_stack: Optional[str] = None
|
|
35
|
+
waf: Optional[str] = None
|
|
36
|
+
response_code: Optional[int] = None
|
|
37
|
+
response_time_ms: Optional[int] = None
|
|
38
|
+
error_message: Optional[str] = None
|
|
39
|
+
notes: Optional[str] = None
|
|
40
|
+
timestamp: datetime = field(default_factory=datetime.utcnow)
|
|
41
|
+
|
|
42
|
+
def to_dict(self) -> dict[str, Any]:
|
|
43
|
+
return {
|
|
44
|
+
"vuln_type": self.vuln_type,
|
|
45
|
+
"target_url": self.target_url,
|
|
46
|
+
"payload": self.payload,
|
|
47
|
+
"success": self.success,
|
|
48
|
+
"tech_stack": self.tech_stack,
|
|
49
|
+
"waf": self.waf,
|
|
50
|
+
"response_code": self.response_code,
|
|
51
|
+
"response_time_ms": self.response_time_ms,
|
|
52
|
+
"error_message": self.error_message,
|
|
53
|
+
"notes": self.notes,
|
|
54
|
+
"timestamp": self.timestamp.isoformat(),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class PayloadSuggestion:
|
|
60
|
+
"""A suggested payload based on historical success."""
|
|
61
|
+
payload: str
|
|
62
|
+
success_count: int
|
|
63
|
+
total_attempts: int
|
|
64
|
+
success_rate: float
|
|
65
|
+
avg_response_time_ms: Optional[float] = None
|
|
66
|
+
common_waf: Optional[str] = None
|
|
67
|
+
common_tech: Optional[str] = None
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def confidence(self) -> float:
|
|
71
|
+
"""Calculate confidence score."""
|
|
72
|
+
# Higher success rate and more attempts = higher confidence
|
|
73
|
+
sample_bonus = min(self.total_attempts / 10, 1.0) # Max bonus at 10 attempts
|
|
74
|
+
return self.success_rate * (0.5 + 0.5 * sample_bonus)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class TechniqueStats:
|
|
79
|
+
"""Statistics for a vulnerability type."""
|
|
80
|
+
vuln_type: str
|
|
81
|
+
total_attempts: int
|
|
82
|
+
successful_attempts: int
|
|
83
|
+
success_rate: float
|
|
84
|
+
best_payload: Optional[str] = None
|
|
85
|
+
best_payload_success_rate: Optional[float] = None
|
|
86
|
+
common_waf_bypasses: list[str] = field(default_factory=list)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ExploitationLearner:
|
|
90
|
+
"""
|
|
91
|
+
Learns from exploitation attempts to improve future scans.
|
|
92
|
+
|
|
93
|
+
Maintains a SQLite database of exploitation attempts and their outcomes,
|
|
94
|
+
allowing AIPT to learn which techniques work best in different contexts.
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
learner = ExploitationLearner()
|
|
98
|
+
|
|
99
|
+
# Record an attempt
|
|
100
|
+
learner.record_attempt(ExploitAttempt(
|
|
101
|
+
vuln_type="sql_injection",
|
|
102
|
+
target_url="https://example.com/login",
|
|
103
|
+
payload="' OR '1'='1",
|
|
104
|
+
success=True,
|
|
105
|
+
waf="cloudflare",
|
|
106
|
+
tech_stack="php/mysql"
|
|
107
|
+
))
|
|
108
|
+
|
|
109
|
+
# Get suggestions for future attempts
|
|
110
|
+
suggestions = learner.get_payload_suggestions(
|
|
111
|
+
vuln_type="sql_injection",
|
|
112
|
+
waf="cloudflare"
|
|
113
|
+
)
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(self, db_path: str = None):
|
|
117
|
+
if db_path is None:
|
|
118
|
+
# Default to ~/.aiptx/learning.db
|
|
119
|
+
aiptx_dir = Path.home() / ".aiptx"
|
|
120
|
+
aiptx_dir.mkdir(parents=True, exist_ok=True)
|
|
121
|
+
db_path = str(aiptx_dir / "learning.db")
|
|
122
|
+
|
|
123
|
+
self.db_path = db_path
|
|
124
|
+
self._init_database()
|
|
125
|
+
|
|
126
|
+
def _init_database(self):
|
|
127
|
+
"""Initialize the SQLite database schema."""
|
|
128
|
+
conn = sqlite3.connect(self.db_path)
|
|
129
|
+
cursor = conn.cursor()
|
|
130
|
+
|
|
131
|
+
# Exploitation attempts table
|
|
132
|
+
cursor.execute("""
|
|
133
|
+
CREATE TABLE IF NOT EXISTS exploit_attempts (
|
|
134
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
135
|
+
vuln_type TEXT NOT NULL,
|
|
136
|
+
target_url TEXT NOT NULL,
|
|
137
|
+
payload TEXT NOT NULL,
|
|
138
|
+
success INTEGER NOT NULL,
|
|
139
|
+
tech_stack TEXT,
|
|
140
|
+
waf TEXT,
|
|
141
|
+
response_code INTEGER,
|
|
142
|
+
response_time_ms INTEGER,
|
|
143
|
+
error_message TEXT,
|
|
144
|
+
notes TEXT,
|
|
145
|
+
timestamp TEXT NOT NULL,
|
|
146
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
147
|
+
)
|
|
148
|
+
""")
|
|
149
|
+
|
|
150
|
+
# Index for faster queries
|
|
151
|
+
cursor.execute("""
|
|
152
|
+
CREATE INDEX IF NOT EXISTS idx_vuln_type ON exploit_attempts(vuln_type)
|
|
153
|
+
""")
|
|
154
|
+
cursor.execute("""
|
|
155
|
+
CREATE INDEX IF NOT EXISTS idx_success ON exploit_attempts(success)
|
|
156
|
+
""")
|
|
157
|
+
cursor.execute("""
|
|
158
|
+
CREATE INDEX IF NOT EXISTS idx_waf ON exploit_attempts(waf)
|
|
159
|
+
""")
|
|
160
|
+
|
|
161
|
+
# WAF bypass techniques table
|
|
162
|
+
cursor.execute("""
|
|
163
|
+
CREATE TABLE IF NOT EXISTS waf_bypasses (
|
|
164
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
165
|
+
waf_name TEXT NOT NULL,
|
|
166
|
+
vuln_type TEXT NOT NULL,
|
|
167
|
+
original_payload TEXT NOT NULL,
|
|
168
|
+
bypass_payload TEXT NOT NULL,
|
|
169
|
+
success INTEGER NOT NULL,
|
|
170
|
+
notes TEXT,
|
|
171
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
172
|
+
)
|
|
173
|
+
""")
|
|
174
|
+
|
|
175
|
+
# Payload effectiveness table (aggregated stats)
|
|
176
|
+
cursor.execute("""
|
|
177
|
+
CREATE TABLE IF NOT EXISTS payload_stats (
|
|
178
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
179
|
+
vuln_type TEXT NOT NULL,
|
|
180
|
+
payload_hash TEXT NOT NULL,
|
|
181
|
+
payload TEXT NOT NULL,
|
|
182
|
+
success_count INTEGER DEFAULT 0,
|
|
183
|
+
failure_count INTEGER DEFAULT 0,
|
|
184
|
+
avg_response_time_ms REAL,
|
|
185
|
+
last_success TEXT,
|
|
186
|
+
last_failure TEXT,
|
|
187
|
+
UNIQUE(vuln_type, payload_hash)
|
|
188
|
+
)
|
|
189
|
+
""")
|
|
190
|
+
|
|
191
|
+
conn.commit()
|
|
192
|
+
conn.close()
|
|
193
|
+
|
|
194
|
+
def record_attempt(self, attempt: ExploitAttempt):
|
|
195
|
+
"""
|
|
196
|
+
Record an exploitation attempt.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
attempt: The exploitation attempt to record
|
|
200
|
+
"""
|
|
201
|
+
conn = sqlite3.connect(self.db_path)
|
|
202
|
+
cursor = conn.cursor()
|
|
203
|
+
|
|
204
|
+
# Insert attempt
|
|
205
|
+
cursor.execute("""
|
|
206
|
+
INSERT INTO exploit_attempts
|
|
207
|
+
(vuln_type, target_url, payload, success, tech_stack, waf,
|
|
208
|
+
response_code, response_time_ms, error_message, notes, timestamp)
|
|
209
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
210
|
+
""", (
|
|
211
|
+
attempt.vuln_type,
|
|
212
|
+
attempt.target_url,
|
|
213
|
+
attempt.payload,
|
|
214
|
+
1 if attempt.success else 0,
|
|
215
|
+
attempt.tech_stack,
|
|
216
|
+
attempt.waf,
|
|
217
|
+
attempt.response_code,
|
|
218
|
+
attempt.response_time_ms,
|
|
219
|
+
attempt.error_message,
|
|
220
|
+
attempt.notes,
|
|
221
|
+
attempt.timestamp.isoformat(),
|
|
222
|
+
))
|
|
223
|
+
|
|
224
|
+
# Update payload stats
|
|
225
|
+
payload_hash = self._hash_payload(attempt.payload)
|
|
226
|
+
if attempt.success:
|
|
227
|
+
cursor.execute("""
|
|
228
|
+
INSERT INTO payload_stats (vuln_type, payload_hash, payload, success_count, last_success)
|
|
229
|
+
VALUES (?, ?, ?, 1, ?)
|
|
230
|
+
ON CONFLICT(vuln_type, payload_hash) DO UPDATE SET
|
|
231
|
+
success_count = success_count + 1,
|
|
232
|
+
last_success = ?
|
|
233
|
+
""", (attempt.vuln_type, payload_hash, attempt.payload,
|
|
234
|
+
attempt.timestamp.isoformat(), attempt.timestamp.isoformat()))
|
|
235
|
+
else:
|
|
236
|
+
cursor.execute("""
|
|
237
|
+
INSERT INTO payload_stats (vuln_type, payload_hash, payload, failure_count, last_failure)
|
|
238
|
+
VALUES (?, ?, ?, 1, ?)
|
|
239
|
+
ON CONFLICT(vuln_type, payload_hash) DO UPDATE SET
|
|
240
|
+
failure_count = failure_count + 1,
|
|
241
|
+
last_failure = ?
|
|
242
|
+
""", (attempt.vuln_type, payload_hash, attempt.payload,
|
|
243
|
+
attempt.timestamp.isoformat(), attempt.timestamp.isoformat()))
|
|
244
|
+
|
|
245
|
+
conn.commit()
|
|
246
|
+
conn.close()
|
|
247
|
+
|
|
248
|
+
logger.debug(f"Recorded {'successful' if attempt.success else 'failed'} "
|
|
249
|
+
f"attempt for {attempt.vuln_type}")
|
|
250
|
+
|
|
251
|
+
def record_waf_bypass(
|
|
252
|
+
self,
|
|
253
|
+
waf_name: str,
|
|
254
|
+
vuln_type: str,
|
|
255
|
+
original_payload: str,
|
|
256
|
+
bypass_payload: str,
|
|
257
|
+
success: bool,
|
|
258
|
+
notes: str = "",
|
|
259
|
+
):
|
|
260
|
+
"""
|
|
261
|
+
Record a WAF bypass technique.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
waf_name: Name of the WAF (e.g., "cloudflare", "akamai")
|
|
265
|
+
vuln_type: Type of vulnerability being exploited
|
|
266
|
+
original_payload: The blocked payload
|
|
267
|
+
bypass_payload: The modified payload that bypassed the WAF
|
|
268
|
+
success: Whether the bypass was successful
|
|
269
|
+
notes: Additional notes
|
|
270
|
+
"""
|
|
271
|
+
conn = sqlite3.connect(self.db_path)
|
|
272
|
+
cursor = conn.cursor()
|
|
273
|
+
|
|
274
|
+
cursor.execute("""
|
|
275
|
+
INSERT INTO waf_bypasses
|
|
276
|
+
(waf_name, vuln_type, original_payload, bypass_payload, success, notes)
|
|
277
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
278
|
+
""", (waf_name, vuln_type, original_payload, bypass_payload,
|
|
279
|
+
1 if success else 0, notes))
|
|
280
|
+
|
|
281
|
+
conn.commit()
|
|
282
|
+
conn.close()
|
|
283
|
+
|
|
284
|
+
logger.info(f"Recorded WAF bypass for {waf_name}: {'success' if success else 'failure'}")
|
|
285
|
+
|
|
286
|
+
def get_payload_suggestions(
|
|
287
|
+
self,
|
|
288
|
+
vuln_type: str,
|
|
289
|
+
waf: str = None,
|
|
290
|
+
tech_stack: str = None,
|
|
291
|
+
limit: int = 10,
|
|
292
|
+
) -> list[PayloadSuggestion]:
|
|
293
|
+
"""
|
|
294
|
+
Get payload suggestions based on historical success.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
vuln_type: Type of vulnerability (e.g., "sql_injection")
|
|
298
|
+
waf: Optional WAF name to filter for
|
|
299
|
+
tech_stack: Optional tech stack to filter for
|
|
300
|
+
limit: Maximum number of suggestions
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
List of PayloadSuggestion objects ordered by success rate
|
|
304
|
+
"""
|
|
305
|
+
conn = sqlite3.connect(self.db_path)
|
|
306
|
+
cursor = conn.cursor()
|
|
307
|
+
|
|
308
|
+
# Build query based on filters
|
|
309
|
+
query = """
|
|
310
|
+
SELECT
|
|
311
|
+
payload,
|
|
312
|
+
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as success_count,
|
|
313
|
+
COUNT(*) as total_attempts,
|
|
314
|
+
AVG(CASE WHEN success = 1 THEN response_time_ms ELSE NULL END) as avg_time,
|
|
315
|
+
waf,
|
|
316
|
+
tech_stack
|
|
317
|
+
FROM exploit_attempts
|
|
318
|
+
WHERE vuln_type = ?
|
|
319
|
+
"""
|
|
320
|
+
params = [vuln_type]
|
|
321
|
+
|
|
322
|
+
if waf:
|
|
323
|
+
query += " AND (waf = ? OR waf IS NULL)"
|
|
324
|
+
params.append(waf)
|
|
325
|
+
|
|
326
|
+
if tech_stack:
|
|
327
|
+
query += " AND (tech_stack LIKE ? OR tech_stack IS NULL)"
|
|
328
|
+
params.append(f"%{tech_stack}%")
|
|
329
|
+
|
|
330
|
+
query += """
|
|
331
|
+
GROUP BY payload
|
|
332
|
+
HAVING total_attempts >= 1
|
|
333
|
+
ORDER BY (CAST(success_count AS FLOAT) / total_attempts) DESC,
|
|
334
|
+
success_count DESC
|
|
335
|
+
LIMIT ?
|
|
336
|
+
"""
|
|
337
|
+
params.append(limit)
|
|
338
|
+
|
|
339
|
+
cursor.execute(query, params)
|
|
340
|
+
rows = cursor.fetchall()
|
|
341
|
+
conn.close()
|
|
342
|
+
|
|
343
|
+
suggestions = []
|
|
344
|
+
for row in rows:
|
|
345
|
+
payload, success_count, total, avg_time, common_waf, common_tech = row
|
|
346
|
+
suggestions.append(PayloadSuggestion(
|
|
347
|
+
payload=payload,
|
|
348
|
+
success_count=success_count,
|
|
349
|
+
total_attempts=total,
|
|
350
|
+
success_rate=success_count / total if total > 0 else 0,
|
|
351
|
+
avg_response_time_ms=avg_time,
|
|
352
|
+
common_waf=common_waf,
|
|
353
|
+
common_tech=common_tech,
|
|
354
|
+
))
|
|
355
|
+
|
|
356
|
+
return suggestions
|
|
357
|
+
|
|
358
|
+
def get_waf_bypass_payloads(
|
|
359
|
+
self,
|
|
360
|
+
waf_name: str,
|
|
361
|
+
vuln_type: str = None,
|
|
362
|
+
limit: int = 10,
|
|
363
|
+
) -> list[dict[str, Any]]:
|
|
364
|
+
"""
|
|
365
|
+
Get successful WAF bypass payloads.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
waf_name: Name of the WAF
|
|
369
|
+
vuln_type: Optional vulnerability type filter
|
|
370
|
+
limit: Maximum results
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
List of bypass payload dictionaries
|
|
374
|
+
"""
|
|
375
|
+
conn = sqlite3.connect(self.db_path)
|
|
376
|
+
cursor = conn.cursor()
|
|
377
|
+
|
|
378
|
+
query = """
|
|
379
|
+
SELECT vuln_type, original_payload, bypass_payload, notes
|
|
380
|
+
FROM waf_bypasses
|
|
381
|
+
WHERE waf_name = ? AND success = 1
|
|
382
|
+
"""
|
|
383
|
+
params = [waf_name]
|
|
384
|
+
|
|
385
|
+
if vuln_type:
|
|
386
|
+
query += " AND vuln_type = ?"
|
|
387
|
+
params.append(vuln_type)
|
|
388
|
+
|
|
389
|
+
query += " ORDER BY created_at DESC LIMIT ?"
|
|
390
|
+
params.append(limit)
|
|
391
|
+
|
|
392
|
+
cursor.execute(query, params)
|
|
393
|
+
rows = cursor.fetchall()
|
|
394
|
+
conn.close()
|
|
395
|
+
|
|
396
|
+
return [
|
|
397
|
+
{
|
|
398
|
+
"vuln_type": row[0],
|
|
399
|
+
"original_payload": row[1],
|
|
400
|
+
"bypass_payload": row[2],
|
|
401
|
+
"notes": row[3],
|
|
402
|
+
}
|
|
403
|
+
for row in rows
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
def get_technique_stats(self, vuln_type: str) -> TechniqueStats:
|
|
407
|
+
"""
|
|
408
|
+
Get statistics for a vulnerability type.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
vuln_type: The vulnerability type to analyze
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
TechniqueStats with aggregated information
|
|
415
|
+
"""
|
|
416
|
+
conn = sqlite3.connect(self.db_path)
|
|
417
|
+
cursor = conn.cursor()
|
|
418
|
+
|
|
419
|
+
# Get overall stats
|
|
420
|
+
cursor.execute("""
|
|
421
|
+
SELECT
|
|
422
|
+
COUNT(*) as total,
|
|
423
|
+
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successes
|
|
424
|
+
FROM exploit_attempts
|
|
425
|
+
WHERE vuln_type = ?
|
|
426
|
+
""", (vuln_type,))
|
|
427
|
+
total, successes = cursor.fetchone()
|
|
428
|
+
total = total or 0
|
|
429
|
+
successes = successes or 0
|
|
430
|
+
|
|
431
|
+
# Get best payload
|
|
432
|
+
cursor.execute("""
|
|
433
|
+
SELECT payload,
|
|
434
|
+
CAST(SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(*) as rate
|
|
435
|
+
FROM exploit_attempts
|
|
436
|
+
WHERE vuln_type = ?
|
|
437
|
+
GROUP BY payload
|
|
438
|
+
HAVING COUNT(*) >= 3
|
|
439
|
+
ORDER BY rate DESC
|
|
440
|
+
LIMIT 1
|
|
441
|
+
""", (vuln_type,))
|
|
442
|
+
best_row = cursor.fetchone()
|
|
443
|
+
|
|
444
|
+
# Get common WAF bypasses
|
|
445
|
+
cursor.execute("""
|
|
446
|
+
SELECT DISTINCT waf
|
|
447
|
+
FROM exploit_attempts
|
|
448
|
+
WHERE vuln_type = ? AND waf IS NOT NULL AND success = 1
|
|
449
|
+
LIMIT 5
|
|
450
|
+
""", (vuln_type,))
|
|
451
|
+
waf_rows = cursor.fetchall()
|
|
452
|
+
|
|
453
|
+
conn.close()
|
|
454
|
+
|
|
455
|
+
return TechniqueStats(
|
|
456
|
+
vuln_type=vuln_type,
|
|
457
|
+
total_attempts=total,
|
|
458
|
+
successful_attempts=successes,
|
|
459
|
+
success_rate=successes / total if total > 0 else 0,
|
|
460
|
+
best_payload=best_row[0] if best_row else None,
|
|
461
|
+
best_payload_success_rate=best_row[1] if best_row else None,
|
|
462
|
+
common_waf_bypasses=[row[0] for row in waf_rows],
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def get_success_rate(
|
|
466
|
+
self,
|
|
467
|
+
vuln_type: str,
|
|
468
|
+
tech_stack: str = None,
|
|
469
|
+
waf: str = None,
|
|
470
|
+
) -> float:
|
|
471
|
+
"""
|
|
472
|
+
Get historical success rate for a vulnerability type.
|
|
473
|
+
|
|
474
|
+
Args:
|
|
475
|
+
vuln_type: Vulnerability type
|
|
476
|
+
tech_stack: Optional tech stack filter
|
|
477
|
+
waf: Optional WAF filter
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
Success rate as a float (0.0 to 1.0)
|
|
481
|
+
"""
|
|
482
|
+
conn = sqlite3.connect(self.db_path)
|
|
483
|
+
cursor = conn.cursor()
|
|
484
|
+
|
|
485
|
+
query = """
|
|
486
|
+
SELECT
|
|
487
|
+
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successes,
|
|
488
|
+
COUNT(*) as total
|
|
489
|
+
FROM exploit_attempts
|
|
490
|
+
WHERE vuln_type = ?
|
|
491
|
+
"""
|
|
492
|
+
params = [vuln_type]
|
|
493
|
+
|
|
494
|
+
if tech_stack:
|
|
495
|
+
query += " AND tech_stack LIKE ?"
|
|
496
|
+
params.append(f"%{tech_stack}%")
|
|
497
|
+
|
|
498
|
+
if waf:
|
|
499
|
+
query += " AND waf = ?"
|
|
500
|
+
params.append(waf)
|
|
501
|
+
|
|
502
|
+
cursor.execute(query, params)
|
|
503
|
+
successes, total = cursor.fetchone()
|
|
504
|
+
conn.close()
|
|
505
|
+
|
|
506
|
+
if total and total > 0:
|
|
507
|
+
return successes / total
|
|
508
|
+
return 0.0
|
|
509
|
+
|
|
510
|
+
def export_knowledge(self, output_path: str):
|
|
511
|
+
"""
|
|
512
|
+
Export learned knowledge to JSON file.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
output_path: Path to write JSON export
|
|
516
|
+
"""
|
|
517
|
+
conn = sqlite3.connect(self.db_path)
|
|
518
|
+
cursor = conn.cursor()
|
|
519
|
+
|
|
520
|
+
# Get all payload stats
|
|
521
|
+
cursor.execute("""
|
|
522
|
+
SELECT vuln_type, payload, success_count, failure_count
|
|
523
|
+
FROM payload_stats
|
|
524
|
+
ORDER BY vuln_type, (success_count * 1.0 / (success_count + failure_count + 1)) DESC
|
|
525
|
+
""")
|
|
526
|
+
payload_rows = cursor.fetchall()
|
|
527
|
+
|
|
528
|
+
# Get all WAF bypasses
|
|
529
|
+
cursor.execute("""
|
|
530
|
+
SELECT waf_name, vuln_type, original_payload, bypass_payload, success
|
|
531
|
+
FROM waf_bypasses
|
|
532
|
+
WHERE success = 1
|
|
533
|
+
""")
|
|
534
|
+
bypass_rows = cursor.fetchall()
|
|
535
|
+
|
|
536
|
+
conn.close()
|
|
537
|
+
|
|
538
|
+
export_data = {
|
|
539
|
+
"exported_at": datetime.utcnow().isoformat(),
|
|
540
|
+
"payload_knowledge": [
|
|
541
|
+
{
|
|
542
|
+
"vuln_type": row[0],
|
|
543
|
+
"payload": row[1],
|
|
544
|
+
"success_count": row[2],
|
|
545
|
+
"failure_count": row[3],
|
|
546
|
+
"success_rate": row[2] / (row[2] + row[3]) if (row[2] + row[3]) > 0 else 0,
|
|
547
|
+
}
|
|
548
|
+
for row in payload_rows
|
|
549
|
+
],
|
|
550
|
+
"waf_bypasses": [
|
|
551
|
+
{
|
|
552
|
+
"waf": row[0],
|
|
553
|
+
"vuln_type": row[1],
|
|
554
|
+
"original": row[2],
|
|
555
|
+
"bypass": row[3],
|
|
556
|
+
}
|
|
557
|
+
for row in bypass_rows
|
|
558
|
+
],
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
with open(output_path, "w") as f:
|
|
562
|
+
json.dump(export_data, f, indent=2)
|
|
563
|
+
|
|
564
|
+
logger.info(f"Exported knowledge to {output_path}")
|
|
565
|
+
|
|
566
|
+
def import_knowledge(self, input_path: str):
|
|
567
|
+
"""
|
|
568
|
+
Import knowledge from JSON file.
|
|
569
|
+
|
|
570
|
+
Args:
|
|
571
|
+
input_path: Path to JSON file to import
|
|
572
|
+
"""
|
|
573
|
+
with open(input_path, "r") as f:
|
|
574
|
+
data = json.load(f)
|
|
575
|
+
|
|
576
|
+
conn = sqlite3.connect(self.db_path)
|
|
577
|
+
cursor = conn.cursor()
|
|
578
|
+
|
|
579
|
+
# Import payload knowledge
|
|
580
|
+
for payload_data in data.get("payload_knowledge", []):
|
|
581
|
+
payload_hash = self._hash_payload(payload_data["payload"])
|
|
582
|
+
cursor.execute("""
|
|
583
|
+
INSERT OR REPLACE INTO payload_stats
|
|
584
|
+
(vuln_type, payload_hash, payload, success_count, failure_count)
|
|
585
|
+
VALUES (?, ?, ?, ?, ?)
|
|
586
|
+
""", (
|
|
587
|
+
payload_data["vuln_type"],
|
|
588
|
+
payload_hash,
|
|
589
|
+
payload_data["payload"],
|
|
590
|
+
payload_data["success_count"],
|
|
591
|
+
payload_data["failure_count"],
|
|
592
|
+
))
|
|
593
|
+
|
|
594
|
+
# Import WAF bypasses
|
|
595
|
+
for bypass in data.get("waf_bypasses", []):
|
|
596
|
+
cursor.execute("""
|
|
597
|
+
INSERT INTO waf_bypasses
|
|
598
|
+
(waf_name, vuln_type, original_payload, bypass_payload, success)
|
|
599
|
+
VALUES (?, ?, ?, ?, 1)
|
|
600
|
+
""", (
|
|
601
|
+
bypass["waf"],
|
|
602
|
+
bypass["vuln_type"],
|
|
603
|
+
bypass["original"],
|
|
604
|
+
bypass["bypass"],
|
|
605
|
+
))
|
|
606
|
+
|
|
607
|
+
conn.commit()
|
|
608
|
+
conn.close()
|
|
609
|
+
|
|
610
|
+
logger.info(f"Imported knowledge from {input_path}")
|
|
611
|
+
|
|
612
|
+
def _hash_payload(self, payload: str) -> str:
|
|
613
|
+
"""Create a hash of a payload for deduplication."""
|
|
614
|
+
import hashlib
|
|
615
|
+
return hashlib.sha256(payload.encode()).hexdigest()[:16]
|
|
616
|
+
|
|
617
|
+
def clear_all(self):
|
|
618
|
+
"""Clear all learned data (use with caution)."""
|
|
619
|
+
conn = sqlite3.connect(self.db_path)
|
|
620
|
+
cursor = conn.cursor()
|
|
621
|
+
cursor.execute("DELETE FROM exploit_attempts")
|
|
622
|
+
cursor.execute("DELETE FROM waf_bypasses")
|
|
623
|
+
cursor.execute("DELETE FROM payload_stats")
|
|
624
|
+
conn.commit()
|
|
625
|
+
conn.close()
|
|
626
|
+
logger.warning("Cleared all learning data")
|