Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
═══════════════════════════════════════════════════════════════════════════════
|
| 3 |
-
|
| 4 |
─────────────────────────────────────────────────────────────────────────
|
| 5 |
-
|
| 6 |
-
|
| 7 |
═══════════════════════════════════════════════════════════════════════════════
|
| 8 |
"""
|
| 9 |
|
|
@@ -28,6 +32,10 @@ import plotly.graph_objects as go
|
|
| 28 |
import plotly.express as px
|
| 29 |
from io import BytesIO
|
| 30 |
import base64
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
# ════════════════════════════════════════════════════════════════════════════
|
| 33 |
# SECTION 1: CONFIGURATION & CONSTANTS
|
|
@@ -81,41 +89,131 @@ STRIDE_THREATS = {
|
|
| 81 |
}
|
| 82 |
}
|
| 83 |
|
| 84 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
TECH_FINGERPRINTS = {
|
| 86 |
"Web Servers": {
|
| 87 |
"Apache": [r"Server: Apache", r"X-Powered-By: Apache"],
|
| 88 |
"Nginx": [r"Server: nginx", r"X-Nginx"],
|
| 89 |
"IIS": [r"Server: Microsoft-IIS"],
|
| 90 |
-
"Cloudflare": [r"CF-RAY", r"Cloudflare"]
|
|
|
|
|
|
|
| 91 |
},
|
| 92 |
"CMS": {
|
| 93 |
"WordPress": [r"/wp-admin", r"wp-content", r"wp_.*"],
|
| 94 |
-
"Drupal": [r"/sites/default", r"drupal
|
| 95 |
-
"Joomla": [r"/administrator", r"com_content"]
|
|
|
|
|
|
|
| 96 |
},
|
| 97 |
"Frameworks": {
|
| 98 |
"Django": [r"CSRF", r"django_session"],
|
| 99 |
"Flask": [r"werkzeug", r"Flask"],
|
| 100 |
"Laravel": [r"XSRF-TOKEN", r"laravel_session"],
|
| 101 |
-
"Spring": [r"JSESSIONID", r"spring"]
|
|
|
|
|
|
|
| 102 |
},
|
| 103 |
"JavaScript": {
|
| 104 |
-
"React": [r"__REACT", r"react
|
| 105 |
-
"Vue": [r"__VUE", r"vue
|
| 106 |
-
"Angular": [r"ng-app", r"angular
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
|
| 110 |
-
#
|
| 111 |
-
|
| 112 |
-
"
|
| 113 |
-
"
|
| 114 |
-
"
|
| 115 |
-
"
|
| 116 |
-
"
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
# ════════════════════════════════════════════════════════════════════════════
|
| 120 |
# SECTION 2: DATA MODELS
|
| 121 |
# ════════════════════════════════════════════════════════════════════════════
|
|
@@ -123,9 +221,9 @@ VULNERABILITY_DATABASE = {
|
|
| 123 |
@dataclass
|
| 124 |
class IntelligenceIndicator:
|
| 125 |
"""IOC - Indicator of Compromise"""
|
| 126 |
-
type: str
|
| 127 |
value: str
|
| 128 |
-
confidence: float
|
| 129 |
source: str
|
| 130 |
timestamp: str
|
| 131 |
metadata: Optional[Dict] = None
|
|
@@ -139,6 +237,8 @@ class ThreatVector:
|
|
| 139 |
techniques: List[str]
|
| 140 |
description: str
|
| 141 |
cvss_score: Optional[float] = None
|
|
|
|
|
|
|
| 142 |
|
| 143 |
@dataclass
|
| 144 |
class AttackPath:
|
|
@@ -147,7 +247,31 @@ class AttackPath:
|
|
| 147 |
intermediate_steps: List[str]
|
| 148 |
objective: str
|
| 149 |
risk_level: str
|
| 150 |
-
complexity: float
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
|
| 152 |
# ════════════════════════════════════════════════════════════════════════════
|
| 153 |
# SECTION 3: STEALTH & OPSEC ENGINE
|
|
@@ -174,12 +298,16 @@ class StealthConfig:
|
|
| 174 |
}
|
| 175 |
|
| 176 |
self.user_agents = [
|
| 177 |
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
| 178 |
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
| 179 |
-
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
|
| 180 |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
| 181 |
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15"
|
|
|
|
| 182 |
]
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
def get_delay(self) -> float:
|
| 185 |
"""Random delay to avoid pattern detection"""
|
|
@@ -188,16 +316,29 @@ class StealthConfig:
|
|
| 188 |
|
| 189 |
def get_headers(self) -> Dict[str, str]:
|
| 190 |
"""Anti-fingerprinting headers"""
|
| 191 |
-
|
| 192 |
"User-Agent": random.choice(self.user_agents),
|
| 193 |
-
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
| 194 |
"Accept-Encoding": random.choice(["gzip, deflate", "gzip, deflate, br"]),
|
| 195 |
-
"Accept-Language": random.choice(["en-US,en;q=0.9", "en-US,en;q=0.9,pt;q=0.8"]),
|
| 196 |
"Cache-Control": "no-cache",
|
| 197 |
"DNT": "1",
|
| 198 |
"Connection": "keep-alive",
|
| 199 |
-
"Upgrade-Insecure-Requests": "1"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
|
| 202 |
# ════════════════════════════════════════════════════════════════════════════
|
| 203 |
# SECTION 4: PASSIVE OSINT ENGINE
|
|
@@ -212,7 +353,7 @@ class PassiveOSINTEngine:
|
|
| 212 |
self.logger = self._setup_logging()
|
| 213 |
|
| 214 |
def _setup_logging(self):
|
| 215 |
-
logging.basicConfig(level=logging.INFO)
|
| 216 |
return logging.getLogger("PassiveOSINT")
|
| 217 |
|
| 218 |
async def gather_dns_intel(self, domain: str) -> Dict:
|
|
@@ -221,7 +362,10 @@ class PassiveOSINTEngine:
|
|
| 221 |
"subdomains": [],
|
| 222 |
"mx_records": [],
|
| 223 |
"ns_records": [],
|
| 224 |
-
"txt_records": []
|
|
|
|
|
|
|
|
|
|
| 225 |
}
|
| 226 |
|
| 227 |
try:
|
|
@@ -230,7 +374,9 @@ class PassiveOSINTEngine:
|
|
| 230 |
# Try common subdomains
|
| 231 |
common_subs = [
|
| 232 |
"www", "mail", "ftp", "admin", "api", "dev", "staging",
|
| 233 |
-
"cdn", "test", "blog", "shop", "support", "docs", "app"
|
|
|
|
|
|
|
| 234 |
]
|
| 235 |
|
| 236 |
for sub in common_subs:
|
|
@@ -240,7 +386,20 @@ class PassiveOSINTEngine:
|
|
| 240 |
for rdata in result:
|
| 241 |
intel["subdomains"].append({
|
| 242 |
"subdomain": full_domain,
|
| 243 |
-
"ip": str(rdata)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
})
|
| 245 |
except:
|
| 246 |
pass
|
|
@@ -248,7 +407,14 @@ class PassiveOSINTEngine:
|
|
| 248 |
# MX records
|
| 249 |
try:
|
| 250 |
mx = dns.resolver.resolve(domain, 'MX')
|
| 251 |
-
intel["mx_records"] = [str(r) for r in mx]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
except:
|
| 253 |
pass
|
| 254 |
|
|
@@ -266,15 +432,17 @@ class PassiveOSINTEngine:
|
|
| 266 |
|
| 267 |
async def gather_ssl_cert_intel(self, domain: str) -> Dict:
|
| 268 |
"""SSL certificate analysis for subdomains"""
|
| 269 |
-
import ssl
|
| 270 |
-
import socket
|
| 271 |
-
|
| 272 |
cert_intel = {
|
| 273 |
"subject": None,
|
| 274 |
"issuer": None,
|
| 275 |
"valid_from": None,
|
| 276 |
"valid_to": None,
|
| 277 |
-
"subjectAltNames": []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
}
|
| 279 |
|
| 280 |
try:
|
|
@@ -282,11 +450,23 @@ class PassiveOSINTEngine:
|
|
| 282 |
with socket.create_connection((domain, 443), timeout=5) as sock:
|
| 283 |
with context.wrap_socket(sock, server_hostname=domain) as ssock:
|
| 284 |
cert = ssock.getpeercert()
|
|
|
|
|
|
|
| 285 |
|
| 286 |
cert_intel["subject"] = dict(x[0] for x in cert['subject'])
|
| 287 |
cert_intel["issuer"] = dict(x[0] for x in cert['issuer'])
|
| 288 |
cert_intel["valid_from"] = cert['notBefore']
|
| 289 |
cert_intel["valid_to"] = cert['notAfter']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
|
| 291 |
# Extract SANs
|
| 292 |
for alt_name in cert.get('subjectAltName', []):
|
|
@@ -297,15 +477,38 @@ class PassiveOSINTEngine:
|
|
| 297 |
|
| 298 |
return cert_intel
|
| 299 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
async def github_reconnaissance(self, org_name: str) -> Dict:
|
| 301 |
"""Search GitHub for organization info"""
|
| 302 |
github_intel = {
|
| 303 |
"repositories": [],
|
| 304 |
"leaked_patterns": [],
|
| 305 |
-
"technology_hints": []
|
|
|
|
|
|
|
| 306 |
}
|
| 307 |
|
| 308 |
try:
|
|
|
|
| 309 |
endpoint = f"https://api.github.com/users/{org_name}/repos"
|
| 310 |
headers = self.config.get_headers()
|
| 311 |
|
|
@@ -313,403 +516,50 @@ class PassiveOSINTEngine:
|
|
| 313 |
async with session.get(endpoint, headers=headers, timeout=10) as resp:
|
| 314 |
if resp.status == 200:
|
| 315 |
repos = await resp.json()
|
| 316 |
-
for repo in repos[:
|
| 317 |
github_intel["repositories"].append({
|
| 318 |
"name": repo.get("name"),
|
| 319 |
"url": repo.get("html_url"),
|
| 320 |
"description": repo.get("description"),
|
| 321 |
-
"language": repo.get("language")
|
|
|
|
|
|
|
|
|
|
| 322 |
})
|
| 323 |
|
| 324 |
if repo.get("language"):
|
| 325 |
github_intel["technology_hints"].append(repo.get("language"))
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
try:
|
| 336 |
-
# HIBP-like check (public API)
|
| 337 |
-
endpoint = f"https://haveibeenpwned.com/api/v3/breachedaccount/{domain}"
|
| 338 |
-
headers = {"User-Agent": "RedTeamFramework/2.0"}
|
| 339 |
-
|
| 340 |
-
resp = requests.get(endpoint, headers=headers, timeout=5)
|
| 341 |
-
if resp.status_code == 200:
|
| 342 |
-
breaches = resp.json()
|
| 343 |
-
except:
|
| 344 |
-
pass
|
| 345 |
-
|
| 346 |
-
return breaches
|
| 347 |
-
|
| 348 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 349 |
-
# SECTION 5: ACTIVE RECONNAISSANCE ENGINE
|
| 350 |
-
# ════════════════════════════��═══════════════════════════════════════════════
|
| 351 |
-
|
| 352 |
-
class ActiveReconEngine:
|
| 353 |
-
"""Active scanning with OPSEC measures"""
|
| 354 |
-
|
| 355 |
-
def __init__(self, config: StealthConfig):
|
| 356 |
-
self.config = config
|
| 357 |
-
self.findings = []
|
| 358 |
-
self.logger = logging.getLogger("ActiveRecon")
|
| 359 |
-
|
| 360 |
-
async def fingerprint_technologies(self, url: str) -> List[str]:
|
| 361 |
-
"""Identify technologies from headers, HTML, JS"""
|
| 362 |
-
technologies = []
|
| 363 |
-
|
| 364 |
-
try:
|
| 365 |
-
headers = self.config.get_headers()
|
| 366 |
-
resp = requests.get(f"https://{url}", headers=headers, timeout=10, verify=False)
|
| 367 |
-
|
| 368 |
-
# Server header analysis
|
| 369 |
-
if "Server" in resp.headers:
|
| 370 |
-
server = resp.headers["Server"]
|
| 371 |
-
if "Apache" in server:
|
| 372 |
-
technologies.append("Apache")
|
| 373 |
-
if "nginx" in server:
|
| 374 |
-
technologies.append("Nginx")
|
| 375 |
-
if "IIS" in server:
|
| 376 |
-
technologies.append("IIS")
|
| 377 |
-
|
| 378 |
-
# X-Powered-By
|
| 379 |
-
if "X-Powered-By" in resp.headers:
|
| 380 |
-
technologies.append(resp.headers["X-Powered-By"])
|
| 381 |
-
|
| 382 |
-
content = resp.text
|
| 383 |
-
|
| 384 |
-
# CMS/Framework detection
|
| 385 |
-
patterns = {
|
| 386 |
-
"WordPress": r"wp-content|wp-includes|/wp-admin",
|
| 387 |
-
"Drupal": r"sites/default/files|drupal\.css",
|
| 388 |
-
"Joomla": r"Joomla|com_content",
|
| 389 |
-
"Django": r"Django|csrf",
|
| 390 |
-
"Flask": r"Flask|werkzeug",
|
| 391 |
-
"React": r"__REACT_DEVTOOLS__|react\.js",
|
| 392 |
-
"Vue": r"__VUE__|vue\.js",
|
| 393 |
-
"Angular": r"ng-app|angular\.js"
|
| 394 |
-
}
|
| 395 |
-
|
| 396 |
-
for tech, pattern in patterns.items():
|
| 397 |
-
if re.search(pattern, content, re.IGNORECASE):
|
| 398 |
-
technologies.append(tech)
|
| 399 |
-
|
| 400 |
-
except Exception as e:
|
| 401 |
-
self.logger.error(f"Fingerprinting failed: {e}")
|
| 402 |
-
|
| 403 |
-
return list(set(technologies))
|
| 404 |
-
|
| 405 |
-
async def discover_endpoints(self, url: str, wordlist: List[str]) -> List[Dict]:
|
| 406 |
-
"""Endpoint discovery with smart filtering"""
|
| 407 |
-
discovered = []
|
| 408 |
-
|
| 409 |
-
for path in wordlist[:50]: # Limit wordlist
|
| 410 |
-
try:
|
| 411 |
-
full_url = f"https://{url.rstrip('/')}/{path.lstrip('/')}"
|
| 412 |
-
headers = self.config.get_headers()
|
| 413 |
-
|
| 414 |
-
await asyncio.sleep(self.config.get_delay())
|
| 415 |
-
|
| 416 |
-
resp = requests.get(full_url, headers=headers, timeout=5, verify=False, allow_redirects=False)
|
| 417 |
-
|
| 418 |
-
if resp.status_code in [200, 301, 302, 401, 403]:
|
| 419 |
-
discovered.append({
|
| 420 |
-
"path": path,
|
| 421 |
-
"status": resp.status_code,
|
| 422 |
-
"size": len(resp.text)
|
| 423 |
-
})
|
| 424 |
-
except:
|
| 425 |
-
pass
|
| 426 |
-
|
| 427 |
-
return discovered
|
| 428 |
-
|
| 429 |
-
async def analyze_forms(self, url: str) -> List[Dict]:
|
| 430 |
-
"""Form detection and analysis"""
|
| 431 |
-
forms = []
|
| 432 |
-
|
| 433 |
-
try:
|
| 434 |
-
headers = self.config.get_headers()
|
| 435 |
-
resp = requests.get(f"https://{url}", headers=headers, timeout=10, verify=False)
|
| 436 |
-
soup = BeautifulSoup(resp.text, 'html.parser')
|
| 437 |
-
|
| 438 |
-
for form in soup.find_all('form'):
|
| 439 |
-
form_data = {
|
| 440 |
-
"action": form.get('action', ''),
|
| 441 |
-
"method": form.get('method', 'GET').upper(),
|
| 442 |
-
"fields": []
|
| 443 |
-
}
|
| 444 |
-
|
| 445 |
-
for field in form.find_all(['input', 'textarea', 'select']):
|
| 446 |
-
form_data["fields"].append({
|
| 447 |
-
"name": field.get('name', ''),
|
| 448 |
-
"type": field.get('type', 'text')
|
| 449 |
-
})
|
| 450 |
-
|
| 451 |
-
forms.append(form_data)
|
| 452 |
-
|
| 453 |
-
except Exception as e:
|
| 454 |
-
self.logger.error(f"Form analysis failed: {e}")
|
| 455 |
-
|
| 456 |
-
return forms
|
| 457 |
-
|
| 458 |
-
async def extract_javascript_endpoints(self, url: str) -> List[str]:
|
| 459 |
-
"""Extract API endpoints from JavaScript"""
|
| 460 |
-
endpoints = []
|
| 461 |
-
|
| 462 |
-
try:
|
| 463 |
-
headers = self.config.get_headers()
|
| 464 |
-
resp = requests.get(f"https://{url}", headers=headers, timeout=10, verify=False)
|
| 465 |
-
|
| 466 |
-
# Find all script tags
|
| 467 |
-
soup = BeautifulSoup(resp.text, 'html.parser')
|
| 468 |
-
|
| 469 |
-
for script in soup.find_all('script'):
|
| 470 |
-
if script.string:
|
| 471 |
-
# Find API-like patterns
|
| 472 |
-
api_pattern = r'["\']/(api|v[0-9]|rest)/[^"\'\s]+["\']'
|
| 473 |
-
matches = re.findall(api_pattern, script.string)
|
| 474 |
-
endpoints.extend(matches)
|
| 475 |
-
|
| 476 |
-
content = resp.text
|
| 477 |
-
api_urls = re.findall(r'(https?://[^\s"\']+/api/[^\s"\']+)', content)
|
| 478 |
-
endpoints.extend(api_urls)
|
| 479 |
-
|
| 480 |
-
except Exception as e:
|
| 481 |
-
self.logger.error(f"JS extraction failed: {e}")
|
| 482 |
-
|
| 483 |
-
return list(set(endpoints))
|
| 484 |
-
|
| 485 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 486 |
-
# SECTION 6: THREAT MODELING ENGINE (STRIDE + MITRE ATT&CK)
|
| 487 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 488 |
-
|
| 489 |
-
class ThreatModelingEngine:
|
| 490 |
-
"""Advanced threat modeling"""
|
| 491 |
-
|
| 492 |
-
def __init__(self):
|
| 493 |
-
self.threats: List[Dict] = []
|
| 494 |
-
self.attack_paths: List[AttackPath] = []
|
| 495 |
-
|
| 496 |
-
def analyze_web_app(self, recon_data: Dict) -> List[ThreatVector]:
|
| 497 |
-
"""Map reconnaissance to threats"""
|
| 498 |
-
threat_vectors = []
|
| 499 |
-
|
| 500 |
-
# Forms = injection vectors
|
| 501 |
-
for form in recon_data.get("forms", []):
|
| 502 |
-
threat_vectors.append(ThreatVector(
|
| 503 |
-
category="web_form",
|
| 504 |
-
location=form.get("action", ""),
|
| 505 |
-
risk_score=7.5,
|
| 506 |
-
techniques=["T1565.001", "T1598.003"],
|
| 507 |
-
description=f"Form {form.get('action')}: SQL Injection, XSS potential",
|
| 508 |
-
cvss_score=7.5
|
| 509 |
-
))
|
| 510 |
-
|
| 511 |
-
# JavaScript = gadget chains
|
| 512 |
-
for js_file in recon_data.get("js_files", []):
|
| 513 |
-
threat_vectors.append(ThreatVector(
|
| 514 |
-
category="js_gadget",
|
| 515 |
-
location=js_file,
|
| 516 |
-
risk_score=5.0,
|
| 517 |
-
techniques=["T1195.001"],
|
| 518 |
-
description=f"JavaScript gadget chain: {js_file}",
|
| 519 |
-
cvss_score=5.0
|
| 520 |
-
))
|
| 521 |
-
|
| 522 |
-
# API endpoints = information disclosure
|
| 523 |
-
for endpoint in recon_data.get("endpoints", []):
|
| 524 |
-
threat_vectors.append(ThreatVector(
|
| 525 |
-
category="api_endpoint",
|
| 526 |
-
location=endpoint,
|
| 527 |
-
risk_score=6.5,
|
| 528 |
-
techniques=["T1526"],
|
| 529 |
-
description=f"API endpoint: {endpoint}",
|
| 530 |
-
cvss_score=6.5
|
| 531 |
-
))
|
| 532 |
-
|
| 533 |
-
return threat_vectors
|
| 534 |
-
|
| 535 |
-
def build_attack_paths(self, threat_vectors: List[ThreatVector], technologies: List[str]) -> List[AttackPath]:
|
| 536 |
-
"""Generate attack chains"""
|
| 537 |
-
paths = []
|
| 538 |
-
|
| 539 |
-
# Generic attack path
|
| 540 |
-
paths.append(AttackPath(
|
| 541 |
-
entry_point="Public web form or API endpoint",
|
| 542 |
-
intermediate_steps=[
|
| 543 |
-
"Reconnaissance (technology fingerprinting)",
|
| 544 |
-
"Vulnerability identification (SQLi, XSS, CSRF)",
|
| 545 |
-
"Exploitation",
|
| 546 |
-
"Data exfiltration or lateral movement"
|
| 547 |
-
],
|
| 548 |
-
objective="Unauthorized access / Data breach",
|
| 549 |
-
risk_level="CRITICAL",
|
| 550 |
-
complexity=0.6
|
| 551 |
-
))
|
| 552 |
-
|
| 553 |
-
# WordPress-specific
|
| 554 |
-
if "WordPress" in technologies:
|
| 555 |
-
paths.append(AttackPath(
|
| 556 |
-
entry_point="WordPress admin panel",
|
| 557 |
-
intermediate_steps=[
|
| 558 |
-
"Plugin enumeration",
|
| 559 |
-
"Known CVE exploitation",
|
| 560 |
-
"Plugin upload for RCE",
|
| 561 |
-
"Server compromise"
|
| 562 |
-
],
|
| 563 |
-
objective="Remote Code Execution",
|
| 564 |
-
risk_level="CRITICAL",
|
| 565 |
-
complexity=0.4
|
| 566 |
-
))
|
| 567 |
-
|
| 568 |
-
return paths
|
| 569 |
-
|
| 570 |
-
def generate_stride_report(self, recon_data: Dict) -> Dict:
|
| 571 |
-
"""Generate STRIDE threat model"""
|
| 572 |
-
stride_report = {}
|
| 573 |
-
|
| 574 |
-
for threat_category, threat_info in STRIDE_THREATS.items():
|
| 575 |
-
stride_report[threat_category] = {
|
| 576 |
-
"description": threat_info["description"],
|
| 577 |
-
"potential_impacts": [],
|
| 578 |
-
"mitigations": threat_info["mitigations"]
|
| 579 |
-
}
|
| 580 |
-
|
| 581 |
-
# Match with found vulnerabilities
|
| 582 |
-
if "forms" in recon_data and len(recon_data["forms"]) > 0:
|
| 583 |
-
if threat_category == "Tampering":
|
| 584 |
-
stride_report[threat_category]["potential_impacts"].append(
|
| 585 |
-
"SQL Injection in form fields"
|
| 586 |
-
)
|
| 587 |
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
@staticmethod
|
| 604 |
-
def create_enhanced_attack_graph(threat_vectors: List[ThreatVector],
|
| 605 |
-
attack_paths: List[AttackPath]) -> Dict:
|
| 606 |
-
"""Build graph with threat vectors and attack paths"""
|
| 607 |
-
|
| 608 |
-
nodes = ["Attacker", "Internet", "Target Domain"]
|
| 609 |
-
edges = [("Attacker", "Internet"), ("Internet", "Target Domain")]
|
| 610 |
-
node_info = {
|
| 611 |
-
"Attacker": {"type": "attacker", "risk": 10},
|
| 612 |
-
"Internet": {"type": "network", "risk": 5},
|
| 613 |
-
"Target Domain": {"type": "asset", "risk": 7}
|
| 614 |
-
}
|
| 615 |
-
|
| 616 |
-
# Add threat vectors as nodes
|
| 617 |
-
for i, vector in enumerate(threat_vectors[:10]):
|
| 618 |
-
node_name = f"{vector.category.replace('_', ' ')}_{i}"
|
| 619 |
-
nodes.append(node_name)
|
| 620 |
-
edges.append(("Target Domain", node_name))
|
| 621 |
-
node_info[node_name] = {
|
| 622 |
-
"type": "vulnerability",
|
| 623 |
-
"risk": vector.risk_score,
|
| 624 |
-
"cvss": vector.cvss_score
|
| 625 |
-
}
|
| 626 |
-
|
| 627 |
-
return {
|
| 628 |
-
"nodes": nodes,
|
| 629 |
-
"edges": edges,
|
| 630 |
-
"node_info": node_info,
|
| 631 |
-
"threat_vectors": [asdict(v) for v in threat_vectors],
|
| 632 |
-
"attack_paths": [asdict(ap) for ap in attack_paths]
|
| 633 |
-
}
|
| 634 |
-
|
| 635 |
-
@staticmethod
|
| 636 |
-
def visualize_attack_graph_plotly(graph_data: Dict) -> go.Figure:
|
| 637 |
-
"""Create interactive Plotly visualization"""
|
| 638 |
-
|
| 639 |
-
G = nx.DiGraph()
|
| 640 |
-
G.add_edges_from(graph_data["edges"])
|
| 641 |
-
pos = nx.spring_layout(G, k=2, iterations=50, seed=42)
|
| 642 |
-
|
| 643 |
-
# Edge traces
|
| 644 |
-
edge_x, edge_y = [], []
|
| 645 |
-
for edge in G.edges():
|
| 646 |
-
x0, y0 = pos[edge[0]]
|
| 647 |
-
x1, y1 = pos[edge[1]]
|
| 648 |
-
edge_x.extend([x0, x1, None])
|
| 649 |
-
edge_y.extend([y0, y1, None])
|
| 650 |
-
|
| 651 |
-
edge_trace = go.Scatter(
|
| 652 |
-
x=edge_x, y=edge_y,
|
| 653 |
-
line=dict(width=2, color='#888'),
|
| 654 |
-
hoverinfo='none',
|
| 655 |
-
mode='lines',
|
| 656 |
-
name='Relationships'
|
| 657 |
-
)
|
| 658 |
-
|
| 659 |
-
# Node traces with risk coloring
|
| 660 |
-
node_x, node_y, node_text, node_color, node_size = [], [], [], [], []
|
| 661 |
-
|
| 662 |
-
for node in G.nodes():
|
| 663 |
-
x, y = pos[node]
|
| 664 |
-
node_x.append(x)
|
| 665 |
-
node_y.append(y)
|
| 666 |
-
node_text.append(node)
|
| 667 |
-
|
| 668 |
-
node_info = graph_data["node_info"].get(node, {})
|
| 669 |
-
risk = node_info.get("risk", 5)
|
| 670 |
-
|
| 671 |
-
# Color by risk
|
| 672 |
-
if risk >= 8:
|
| 673 |
-
node_color.append('#ff0000') # Red - Critical
|
| 674 |
-
elif risk >= 6:
|
| 675 |
-
node_color.append('#ff7700') # Orange - High
|
| 676 |
-
elif risk >= 4:
|
| 677 |
-
node_color.append('#ffff00') # Yellow - Medium
|
| 678 |
-
else:
|
| 679 |
-
node_color.append('#00ff00') # Green - Low
|
| 680 |
-
|
| 681 |
-
node_size.append(30 + (risk * 2))
|
| 682 |
-
|
| 683 |
-
node_trace = go.Scatter(
|
| 684 |
-
x=node_x, y=node_y,
|
| 685 |
-
mode='markers+text',
|
| 686 |
-
hoverinfo='text',
|
| 687 |
-
text=node_text,
|
| 688 |
-
textposition="top center",
|
| 689 |
-
marker=dict(
|
| 690 |
-
size=node_size,
|
| 691 |
-
color=node_color,
|
| 692 |
-
line_width=2,
|
| 693 |
-
line=dict(color='#222')
|
| 694 |
-
),
|
| 695 |
-
name='Assets/Threats'
|
| 696 |
-
)
|
| 697 |
-
|
| 698 |
-
fig = go.Figure(data=[edge_trace, node_trace])
|
| 699 |
-
fig.update_layout(
|
| 700 |
-
title='🎯 Advanced Attack Surface Graph',
|
| 701 |
-
titlefont=dict(size=20, color='#ff0000'),
|
| 702 |
-
showlegend=True,
|
| 703 |
-
hovermode='closest',
|
| 704 |
-
margin=dict(b=20, l=5, r=5, t=40),
|
| 705 |
-
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
|
| 706 |
-
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
|
| 707 |
-
plot_bgcolor='#1a1a1a',
|
| 708 |
-
paper_bgcolor='#1a1a1a',
|
| 709 |
-
font=dict(color='#ffffff')
|
| 710 |
-
)
|
| 711 |
-
|
| 712 |
-
return fig
|
| 713 |
|
| 714 |
# ════════════════════════════════════════════════════════════════════════════
|
| 715 |
# SECTION 8: COMPREHENSIVE REPORTING ENGINE
|
|
@@ -720,42 +570,82 @@ class ReportingEngine:
|
|
| 720 |
|
| 721 |
@staticmethod
|
| 722 |
def generate_assessment_report(target: str, recon_data: Dict, threat_vectors: List[ThreatVector],
|
| 723 |
-
attack_paths: List[AttackPath], stride_report: Dict
|
|
|
|
| 724 |
"""Generate comprehensive assessment report"""
|
| 725 |
|
|
|
|
|
|
|
| 726 |
report = f"""
|
| 727 |
╔════════════════════════════════════════════════════════════════════════╗
|
| 728 |
║ PROFESSIONAL SECURITY ASSESSMENT REPORT ║
|
| 729 |
║ [CONFIDENTIAL] ║
|
|
|
|
| 730 |
╚════════════════════════════════════════════════════════════════════════╝
|
| 731 |
|
| 732 |
EXECUTIVE SUMMARY
|
| 733 |
─────────────────────────────────────────────────────────────────────────
|
| 734 |
Target: {target}
|
| 735 |
Assessment Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 736 |
-
Assessed By: Red Team Framework
|
| 737 |
Classification: CONFIDENTIAL
|
|
|
|
| 738 |
|
| 739 |
RISK OVERVIEW
|
| 740 |
─────────────────────────────────────────────────────────────────────────
|
| 741 |
-
Critical Findings: {len([t for t in
|
| 742 |
-
High Findings: {len([t for t in
|
| 743 |
-
Medium Findings: {len([t for t in
|
| 744 |
-
Low Findings: {len([t for t in
|
| 745 |
|
| 746 |
-
Overall Risk Level: {"🔴 CRITICAL" if len([t for t in
|
| 747 |
|
| 748 |
ATTACK SURFACE
|
| 749 |
─────────────────────────────────────────────────────────────────────────
|
| 750 |
-
Technologies Identified: {len(recon_data.get('technologies', []))}
|
| 751 |
API Endpoints: {len(recon_data.get('endpoints', []))}
|
| 752 |
Forms Discovered: {len(recon_data.get('forms', []))}
|
| 753 |
Subdomains Found: {len(recon_data.get('subdomains', []))}
|
| 754 |
-
|
|
|
|
| 755 |
|
| 756 |
TECHNOLOGIES DETECTED
|
| 757 |
─────────────────────────────────────────────────────────────────────────
|
| 758 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 759 |
|
| 760 |
THREAT VECTORS
|
| 761 |
─────────────────────────────────────────────────────────────────────────
|
|
@@ -767,8 +657,10 @@ THREAT VECTORS
|
|
| 767 |
Location: {vector.location}
|
| 768 |
Risk Score: {vector.risk_score}/10
|
| 769 |
CVSS Score: {vector.cvss_score if vector.cvss_score else 'N/A'}
|
|
|
|
| 770 |
MITRE ATT&CK: {', '.join(vector.techniques)}
|
| 771 |
Description: {vector.description}
|
|
|
|
| 772 |
"""
|
| 773 |
|
| 774 |
report += f"""
|
|
@@ -780,9 +672,18 @@ STRIDE THREAT MODEL
|
|
| 780 |
for threat_type, threat_data in stride_report.items():
|
| 781 |
report += f"""
|
| 782 |
{threat_type}:
|
|
|
|
| 783 |
Description: {threat_data['description']}
|
| 784 |
-
|
| 785 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
|
| 787 |
report += f"""
|
| 788 |
|
|
@@ -796,46 +697,191 @@ Attack Path {i}: {path.objective}
|
|
| 796 |
Entry Point: {path.entry_point}
|
| 797 |
Complexity: {path.complexity}/1.0
|
| 798 |
Risk Level: {path.risk_level}
|
|
|
|
| 799 |
Steps:
|
| 800 |
"""
|
| 801 |
for step in path.intermediate_steps:
|
| 802 |
-
report += f" → {step}
|
| 803 |
|
| 804 |
report += """
|
| 805 |
|
| 806 |
RECOMMENDATIONS
|
| 807 |
─────────────────────────────────────────────────────────────────────────
|
| 808 |
-
1. IMMEDIATE (Critical):
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
|
|
|
| 813 |
|
| 814 |
-
2. SHORT-TERM (High):
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
|
|
|
| 819 |
|
| 820 |
-
3.
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 825 |
|
| 826 |
METHODOLOGY
|
| 827 |
─────────────────────────────────────────────────────────────────────────
|
| 828 |
-
1. Passive OSINT:
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 832 |
|
| 833 |
═══════════════════════════════════════════════════════════════════════════
|
| 834 |
Report Generated: {datetime.now().isoformat()}
|
| 835 |
Classification: CONFIDENTIAL - DO NOT DISTRIBUTE
|
|
|
|
| 836 |
═══════════════════��═══════════════════════════════════════════════════════
|
| 837 |
"""
|
| 838 |
return report
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
|
| 840 |
# ════════════════════════════════════════════════════════════════════════════
|
| 841 |
# SECTION 9: MAIN ORCHESTRATOR
|
|
@@ -859,10 +905,12 @@ class RedTeamReconFramework:
|
|
| 859 |
"target": target_url,
|
| 860 |
"timestamp": datetime.now().isoformat(),
|
| 861 |
"subdomains": [],
|
| 862 |
-
"technologies":
|
| 863 |
"endpoints": [],
|
| 864 |
"forms": [],
|
| 865 |
"js_files": [],
|
|
|
|
|
|
|
| 866 |
"threat_vectors": [],
|
| 867 |
"attack_paths": [],
|
| 868 |
"stride_analysis": {},
|
|
@@ -872,6 +920,7 @@ class RedTeamReconFramework:
|
|
| 872 |
|
| 873 |
try:
|
| 874 |
# PHASE 1: Passive OSINT
|
|
|
|
| 875 |
passive_data = await self.passive_engine.gather_dns_intel(target_url)
|
| 876 |
results["subdomains"] = passive_data.get("subdomains", [])
|
| 877 |
|
|
@@ -882,18 +931,27 @@ class RedTeamReconFramework:
|
|
| 882 |
for san in ssl_data["subjectAltNames"]
|
| 883 |
])
|
| 884 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 885 |
github_data = await self.passive_engine.github_reconnaissance(target_url.replace(".com", ""))
|
| 886 |
results["github_intel"] = github_data
|
| 887 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 888 |
# PHASE 2: Active Reconnaissance
|
|
|
|
| 889 |
technologies = await self.active_engine.fingerprint_technologies(target_url)
|
| 890 |
results["technologies"] = technologies
|
| 891 |
|
| 892 |
-
endpoints = await self.active_engine.discover_endpoints(target_url,
|
| 893 |
-
|
| 894 |
-
"api/users", "api/admin", "api/auth", "api/data"
|
| 895 |
-
])
|
| 896 |
-
results["endpoints"] = [e["path"] for e in endpoints]
|
| 897 |
|
| 898 |
forms = await self.active_engine.analyze_forms(target_url)
|
| 899 |
results["forms"] = forms
|
|
@@ -901,7 +959,16 @@ class RedTeamReconFramework:
|
|
| 901 |
js_endpoints = await self.active_engine.extract_javascript_endpoints(target_url)
|
| 902 |
results["js_files"] = js_endpoints
|
| 903 |
|
| 904 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 905 |
threat_vectors = self.threat_model.analyze_web_app(results)
|
| 906 |
results["threat_vectors"] = [asdict(tv) for tv in threat_vectors]
|
| 907 |
|
|
@@ -911,19 +978,27 @@ class RedTeamReconFramework:
|
|
| 911 |
stride_analysis = self.threat_model.generate_stride_report(results)
|
| 912 |
results["stride_analysis"] = stride_analysis
|
| 913 |
|
| 914 |
-
# PHASE
|
| 915 |
-
|
|
|
|
|
|
|
|
|
|
| 916 |
results["graph_data"] = graph_data
|
| 917 |
|
| 918 |
-
# PHASE
|
|
|
|
| 919 |
report = self.reporting.generate_assessment_report(
|
| 920 |
-
target_url, results, threat_vectors, attack_paths, stride_analysis
|
| 921 |
)
|
| 922 |
results["report"] = report
|
| 923 |
|
|
|
|
|
|
|
| 924 |
except Exception as e:
|
| 925 |
results["error"] = str(e)
|
| 926 |
logging.error(f"Assessment failed: {e}")
|
|
|
|
|
|
|
| 927 |
|
| 928 |
return results
|
| 929 |
|
|
@@ -938,6 +1013,12 @@ def run_assessment(target_url: str, threat_level: str, progress=gr.Progress(trac
|
|
| 938 |
"""Gradio wrapper function"""
|
| 939 |
|
| 940 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
progress(0.1, desc="🔍 Validating target...")
|
| 942 |
|
| 943 |
# Update threat level
|
|
@@ -967,115 +1048,21 @@ def run_assessment(target_url: str, threat_level: str, progress=gr.Progress(trac
|
|
| 967 |
else:
|
| 968 |
fig = go.Figure()
|
| 969 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 970 |
# Summary
|
| 971 |
summary = f"""
|
| 972 |
## 🔴 ASSESSMENT COMPLETE
|
| 973 |
|
| 974 |
**Target:** {target_url}
|
| 975 |
-
**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
|
|
| 976 |
|
| 977 |
### Quick Stats
|
| 978 |
- 🌐 Subdomains: {len(results.get('subdomains', []))}
|
| 979 |
-
- 🔧 Technologies: {len(results.get('technologies', []))}
|
| 980 |
-
- 📍 Endpoints:
|
| 981 |
-
- 📝 Forms: {len(results.get('forms', []))}
|
| 982 |
-
- ⚠️ Threat Vectors: {len(results.get('threat_vectors', []))}
|
| 983 |
-
- 🎯 Attack Paths: {len(results.get('attack_paths', []))}
|
| 984 |
-
|
| 985 |
-
### Risk Assessment
|
| 986 |
-
- **Critical:** {len([t for t in results.get('threat_vectors', []) if t.get('cvss_score', 0) >= 9.0])}
|
| 987 |
-
- **High:** {len([t for t in results.get('threat_vectors', []) if 7.0 <= t.get('cvss_score', 0) < 9.0])}
|
| 988 |
-
- **Medium:** {len([t for t in results.get('threat_vectors', []) if 4.0 <= t.get('cvss_score', 0) < 7.0])}
|
| 989 |
-
|
| 990 |
-
### Technologies Detected
|
| 991 |
-
{', '.join(results.get('technologies', ['None']))}
|
| 992 |
-
"""
|
| 993 |
-
|
| 994 |
-
return (
|
| 995 |
-
summary,
|
| 996 |
-
json.dumps(results, indent=2, default=str),
|
| 997 |
-
fig,
|
| 998 |
-
results.get("report", "No report generated")
|
| 999 |
-
)
|
| 1000 |
-
|
| 1001 |
-
except Exception as e:
|
| 1002 |
-
error_msg = f"Error: {str(e)}"
|
| 1003 |
-
return error_msg, "{}", go.Figure(), error_msg
|
| 1004 |
-
|
| 1005 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 1006 |
-
# GRADIO UI DEFINITION
|
| 1007 |
-
# ══════════════��═════════════════════════════════════════════════════════════
|
| 1008 |
-
|
| 1009 |
-
with gr.Blocks(theme=gr.themes.Soft(primary_hue="red"), title="Red Team Recon Framework") as demo:
|
| 1010 |
-
gr.Markdown("""
|
| 1011 |
-
# 🛡️ RED TEAM ADVANCED WEB RECONNAISSANCE FRAMEWORK v2.0
|
| 1012 |
-
### Professional Security Assessment Tool
|
| 1013 |
-
|
| 1014 |
-
**Features:**
|
| 1015 |
-
- 🕵️ Passive OSINT (DNS, SSL, GitHub, Breach databases)
|
| 1016 |
-
- 📡 Active Reconnaissance (Fingerprinting, endpoint discovery)
|
| 1017 |
-
- 🎯 Threat Modeling (STRIDE + MITRE ATT&CK)
|
| 1018 |
-
- 📊 Advanced Attack Surface Visualization
|
| 1019 |
-
- 📝 Professional Reporting (CVSS, ATT&CK TID)
|
| 1020 |
-
|
| 1021 |
-
⚠️ **DISCLAIMER:** Authorized testing only. Unauthorized access is illegal.
|
| 1022 |
-
""")
|
| 1023 |
-
|
| 1024 |
-
with gr.Row():
|
| 1025 |
-
with gr.Column(scale=1):
|
| 1026 |
-
target_input = gr.Textbox(
|
| 1027 |
-
label="Target Domain",
|
| 1028 |
-
placeholder="example.com",
|
| 1029 |
-
info="Enter target domain (without https://)"
|
| 1030 |
-
)
|
| 1031 |
-
|
| 1032 |
-
threat_level = gr.Radio(
|
| 1033 |
-
choices=["Low (Stealthy)", "Medium (Balanced)", "High (Aggressive)"],
|
| 1034 |
-
value="Medium (Balanced)",
|
| 1035 |
-
label="Threat Level / Scan Intensity"
|
| 1036 |
-
)
|
| 1037 |
-
|
| 1038 |
-
scan_button = gr.Button("🚀 START ASSESSMENT", variant="primary", size="lg")
|
| 1039 |
-
|
| 1040 |
-
with gr.Column(scale=1):
|
| 1041 |
-
gr.Markdown("""
|
| 1042 |
-
### How It Works
|
| 1043 |
-
|
| 1044 |
-
1. **Passive OSINT**: DNS records, SSL certs, public data
|
| 1045 |
-
2. **Active Recon**: Technology fingerprinting
|
| 1046 |
-
3. **Threat Modeling**: STRIDE + MITRE ATT&CK
|
| 1047 |
-
4. **Risk Analysis**: CVSS scoring
|
| 1048 |
-
5. **Reporting**: Executive + technical reports
|
| 1049 |
-
""")
|
| 1050 |
-
|
| 1051 |
-
with gr.Tabs():
|
| 1052 |
-
with gr.Tab("📊 Summary"):
|
| 1053 |
-
summary_output = gr.Markdown(label="Assessment Summary")
|
| 1054 |
-
|
| 1055 |
-
with gr.Tab("📈 Attack Graph"):
|
| 1056 |
-
graph_output = gr.Plot(label="Attack Surface Visualization")
|
| 1057 |
-
|
| 1058 |
-
with gr.Tab("🔍 Raw Data"):
|
| 1059 |
-
json_output = gr.Code(language="json", label="Detailed Findings (JSON)")
|
| 1060 |
-
|
| 1061 |
-
with gr.Tab("📋 Full Report"):
|
| 1062 |
-
report_output = gr.Textbox(
|
| 1063 |
-
label="Security Assessment Report",
|
| 1064 |
-
lines=30,
|
| 1065 |
-
max_lines=100,
|
| 1066 |
-
interactive=False
|
| 1067 |
-
)
|
| 1068 |
-
|
| 1069 |
-
# Button click handler
|
| 1070 |
-
scan_button.click(
|
| 1071 |
-
fn=run_assessment,
|
| 1072 |
-
inputs=[target_input, threat_level],
|
| 1073 |
-
outputs=[summary_output, json_output, graph_output, report_output]
|
| 1074 |
-
)
|
| 1075 |
-
|
| 1076 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 1077 |
-
# LAUNCH
|
| 1078 |
-
# ════════════════════════════════════════════════════════════════════════════
|
| 1079 |
-
|
| 1080 |
-
if __name__ == "__main__":
|
| 1081 |
-
demo.launch(share=True, server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 1 |
+
|
| 2 |
+
# BÖLÜM 1: KODUN 1-7. BÖLÜMLERİ
|
| 3 |
+
# Bu dosyayı app_part1.py olarak kaydedin
|
| 4 |
+
|
| 5 |
+
part1_code = '''"""
|
| 6 |
═══════════════════════════════════════════════════════════════════════════════
|
| 7 |
+
PRIVATE RED TEAM WEB RECONNAISSANCE FRAMEWORK v3.0 - PART 1
|
| 8 |
─────────────────────────────────────────────────────────────────────────
|
| 9 |
+
Bölümler: 1-7 (Configuration, Data Models, Stealth, OSINT, Active Recon,
|
| 10 |
+
Threat Modeling, Attack Graph)
|
| 11 |
═══════════════════════════════════════════════════════════════════════════════
|
| 12 |
"""
|
| 13 |
|
|
|
|
| 32 |
import plotly.express as px
|
| 33 |
from io import BytesIO
|
| 34 |
import base64
|
| 35 |
+
import ssl
|
| 36 |
+
import socket
|
| 37 |
+
import subprocess
|
| 38 |
+
from urllib.parse import urljoin, urlparse
|
| 39 |
|
| 40 |
# ════════════════════════════════════════════════════════════════════════════
|
| 41 |
# SECTION 1: CONFIGURATION & CONSTANTS
|
|
|
|
| 89 |
}
|
| 90 |
}
|
| 91 |
|
| 92 |
+
# Extended MITRE ATT&CK Matrix
|
| 93 |
+
MITRE_TECHNIQUES = {
|
| 94 |
+
"Reconnaissance": {
|
| 95 |
+
"T1592": "Gather Victim Host Information",
|
| 96 |
+
"T1593": "Search Open Websites/Domains",
|
| 97 |
+
"T1594": "Search Victim-Owned Websites",
|
| 98 |
+
"T1595": "Active Scanning",
|
| 99 |
+
"T1596": "Search Open Technical Databases",
|
| 100 |
+
"T1597": "Search Closed Sources",
|
| 101 |
+
"T1598": "Phishing for Information"
|
| 102 |
+
},
|
| 103 |
+
"Initial Access": {
|
| 104 |
+
"T1190": "Exploit Public-Facing Application",
|
| 105 |
+
"T1199": "Trusted Relationship",
|
| 106 |
+
"T1566": "Phishing"
|
| 107 |
+
},
|
| 108 |
+
"Execution": {
|
| 109 |
+
"T1059": "Command and Scripting Interpreter",
|
| 110 |
+
"T1203": "Exploitation for Client Execution"
|
| 111 |
+
},
|
| 112 |
+
"Persistence": {
|
| 113 |
+
"T1078": "Valid Accounts",
|
| 114 |
+
"T1547": "Boot or Logon Autostart Execution"
|
| 115 |
+
},
|
| 116 |
+
"Privilege Escalation": {
|
| 117 |
+
"T1134": "Access Token Manipulation",
|
| 118 |
+
"T1548": "Abuse Elevation Control Mechanism"
|
| 119 |
+
},
|
| 120 |
+
"Defense Evasion": {
|
| 121 |
+
"T1562": "Impair Defenses",
|
| 122 |
+
"T1036": "Masquerading"
|
| 123 |
+
},
|
| 124 |
+
"Credential Access": {
|
| 125 |
+
"T1110": "Brute Force",
|
| 126 |
+
"T1187": "Forced Authentication"
|
| 127 |
+
},
|
| 128 |
+
"Discovery": {
|
| 129 |
+
"T1526": "Enumerate External Remote Systems",
|
| 130 |
+
"T1087": "Account Discovery"
|
| 131 |
+
},
|
| 132 |
+
"Lateral Movement": {
|
| 133 |
+
"T1021": "Remote Services",
|
| 134 |
+
"T1570": "Lateral Tool Transfer"
|
| 135 |
+
},
|
| 136 |
+
"Collection": {
|
| 137 |
+
"T1113": "Screen Capture",
|
| 138 |
+
"T1115": "Clipboard Data"
|
| 139 |
+
},
|
| 140 |
+
"Command and Control": {
|
| 141 |
+
"T1071": "Application Layer Protocol",
|
| 142 |
+
"T1572": "Protocol Tunneling"
|
| 143 |
+
},
|
| 144 |
+
"Exfiltration": {
|
| 145 |
+
"T1041": "Exfiltration Over C2 Channel",
|
| 146 |
+
"T1048": "Exfiltration Over Alternative Protocol"
|
| 147 |
+
},
|
| 148 |
+
"Impact": {
|
| 149 |
+
"T1531": "Account Access Removal",
|
| 150 |
+
"T1561": "Disk Wipe"
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
# Technology fingerprints - Extended
|
| 155 |
TECH_FINGERPRINTS = {
|
| 156 |
"Web Servers": {
|
| 157 |
"Apache": [r"Server: Apache", r"X-Powered-By: Apache"],
|
| 158 |
"Nginx": [r"Server: nginx", r"X-Nginx"],
|
| 159 |
"IIS": [r"Server: Microsoft-IIS"],
|
| 160 |
+
"Cloudflare": [r"CF-RAY", r"Cloudflare"],
|
| 161 |
+
"AWS": [r"X-Amz", r"AmazonS3"],
|
| 162 |
+
"Azure": [r"Azure", r"Microsoft-IIS"]
|
| 163 |
},
|
| 164 |
"CMS": {
|
| 165 |
"WordPress": [r"/wp-admin", r"wp-content", r"wp_.*"],
|
| 166 |
+
"Drupal": [r"/sites/default", r"drupal\\.css"],
|
| 167 |
+
"Joomla": [r"/administrator", r"com_content"],
|
| 168 |
+
"Magento": [r"/skin/frontend", r"Mage.Cookies"],
|
| 169 |
+
"Shopify": [r"cdn.shopify.com", r"Shopify.theme"]
|
| 170 |
},
|
| 171 |
"Frameworks": {
|
| 172 |
"Django": [r"CSRF", r"django_session"],
|
| 173 |
"Flask": [r"werkzeug", r"Flask"],
|
| 174 |
"Laravel": [r"XSRF-TOKEN", r"laravel_session"],
|
| 175 |
+
"Spring": [r"JSESSIONID", r"spring"],
|
| 176 |
+
"Ruby on Rails": [r"_rails", r"authenticity_token"],
|
| 177 |
+
"ASP.NET": [r"ASP.NET_SessionId", r"__VIEWSTATE"]
|
| 178 |
},
|
| 179 |
"JavaScript": {
|
| 180 |
+
"React": [r"__REACT", r"react\\.js"],
|
| 181 |
+
"Vue": [r"__VUE", r"vue\\.js"],
|
| 182 |
+
"Angular": [r"ng-app", r"angular\\.js"],
|
| 183 |
+
"jQuery": [r"jquery", r"jQuery"],
|
| 184 |
+
"Bootstrap": [r"bootstrap", r"data-toggle"]
|
| 185 |
+
},
|
| 186 |
+
"Databases": {
|
| 187 |
+
"MySQL": [r"MySQL", r"sqlstate"],
|
| 188 |
+
"PostgreSQL": [r"PostgreSQL", r"pg_query"],
|
| 189 |
+
"MongoDB": [r"MongoDB", r"mongod"],
|
| 190 |
+
"Redis": [r"Redis", r"redis-cli"]
|
| 191 |
}
|
| 192 |
}
|
| 193 |
|
| 194 |
+
# Security Headers to check
|
| 195 |
+
SECURITY_HEADERS = {
|
| 196 |
+
"Strict-Transport-Security": "HSTS",
|
| 197 |
+
"Content-Security-Policy": "CSP",
|
| 198 |
+
"X-Frame-Options": "Clickjacking Protection",
|
| 199 |
+
"X-Content-Type-Options": "MIME Sniffing Protection",
|
| 200 |
+
"X-XSS-Protection": "XSS Filter",
|
| 201 |
+
"Referrer-Policy": "Referrer Control",
|
| 202 |
+
"Permissions-Policy": "Feature Policy"
|
| 203 |
}
|
| 204 |
|
| 205 |
+
# Common endpoints for discovery
|
| 206 |
+
COMMON_ENDPOINTS = [
|
| 207 |
+
"", "admin", "api", "login", "test", "debug", "config",
|
| 208 |
+
"api/users", "api/admin", "api/auth", "api/data", "api/v1",
|
| 209 |
+
"wp-admin", "wp-login", "administrator", "phpmyadmin",
|
| 210 |
+
"robots.txt", "sitemap.xml", ".env", ".git", ".htaccess",
|
| 211 |
+
"backup", "db", "database", "dump", "sql", "old",
|
| 212 |
+
"dev", "staging", "beta", "uat", "demo",
|
| 213 |
+
"swagger", "api-docs", "graphql", "graphiql",
|
| 214 |
+
"actuator", "health", "metrics", "prometheus"
|
| 215 |
+
]
|
| 216 |
+
|
| 217 |
# ════════════════════════════════════════════════════════════════════════════
|
| 218 |
# SECTION 2: DATA MODELS
|
| 219 |
# ════════════════════════════════════════════════════════════════════════════
|
|
|
|
| 221 |
@dataclass
|
| 222 |
class IntelligenceIndicator:
|
| 223 |
"""IOC - Indicator of Compromise"""
|
| 224 |
+
type: str
|
| 225 |
value: str
|
| 226 |
+
confidence: float
|
| 227 |
source: str
|
| 228 |
timestamp: str
|
| 229 |
metadata: Optional[Dict] = None
|
|
|
|
| 237 |
techniques: List[str]
|
| 238 |
description: str
|
| 239 |
cvss_score: Optional[float] = None
|
| 240 |
+
cwe_id: Optional[str] = None
|
| 241 |
+
evidence: Optional[str] = None
|
| 242 |
|
| 243 |
@dataclass
|
| 244 |
class AttackPath:
|
|
|
|
| 247 |
intermediate_steps: List[str]
|
| 248 |
objective: str
|
| 249 |
risk_level: str
|
| 250 |
+
complexity: float
|
| 251 |
+
mitre_techniques: List[str] = None
|
| 252 |
+
|
| 253 |
+
def __post_init__(self):
|
| 254 |
+
if self.mitre_techniques is None:
|
| 255 |
+
self.mitre_techniques = []
|
| 256 |
+
|
| 257 |
+
@dataclass
|
| 258 |
+
class Vulnerability:
|
| 259 |
+
"""Vulnerability finding"""
|
| 260 |
+
name: str
|
| 261 |
+
description: str
|
| 262 |
+
severity: str
|
| 263 |
+
cvss_score: float
|
| 264 |
+
cvss_vector: str
|
| 265 |
+
location: str
|
| 266 |
+
evidence: str
|
| 267 |
+
remediation: str
|
| 268 |
+
cwe_id: Optional[str] = None
|
| 269 |
+
owasp_category: Optional[str] = None
|
| 270 |
+
mitre_techniques: List[str] = None
|
| 271 |
+
|
| 272 |
+
def __post_init__(self):
|
| 273 |
+
if self.mitre_techniques is None:
|
| 274 |
+
self.mitre_techniques = []
|
| 275 |
|
| 276 |
# ════════════════════════════════════════════════════════════════════════════
|
| 277 |
# SECTION 3: STEALTH & OPSEC ENGINE
|
|
|
|
| 298 |
}
|
| 299 |
|
| 300 |
self.user_agents = [
|
| 301 |
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
| 302 |
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
| 303 |
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
| 304 |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
| 305 |
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
|
| 306 |
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/120.0.0.0"
|
| 307 |
]
|
| 308 |
+
|
| 309 |
+
self.proxies = []
|
| 310 |
+
self.current_proxy = 0
|
| 311 |
|
| 312 |
def get_delay(self) -> float:
|
| 313 |
"""Random delay to avoid pattern detection"""
|
|
|
|
| 316 |
|
| 317 |
def get_headers(self) -> Dict[str, str]:
|
| 318 |
"""Anti-fingerprinting headers"""
|
| 319 |
+
headers = {
|
| 320 |
"User-Agent": random.choice(self.user_agents),
|
| 321 |
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
| 322 |
"Accept-Encoding": random.choice(["gzip, deflate", "gzip, deflate, br"]),
|
| 323 |
+
"Accept-Language": random.choice(["en-US,en;q=0.9", "en-US,en;q=0.9,pt;q=0.8", "en-GB,en;q=0.9"]),
|
| 324 |
"Cache-Control": "no-cache",
|
| 325 |
"DNT": "1",
|
| 326 |
"Connection": "keep-alive",
|
| 327 |
+
"Upgrade-Insecure-Requests": "1",
|
| 328 |
+
"Sec-Fetch-Dest": "document",
|
| 329 |
+
"Sec-Fetch-Mode": "navigate",
|
| 330 |
+
"Sec-Fetch-Site": "none",
|
| 331 |
+
"Sec-Fetch-User": "?1"
|
| 332 |
}
|
| 333 |
+
return headers
|
| 334 |
+
|
| 335 |
+
def get_proxy(self) -> Optional[Dict]:
|
| 336 |
+
"""Rotate proxies if available"""
|
| 337 |
+
if not self.proxies:
|
| 338 |
+
return None
|
| 339 |
+
proxy = self.proxies[self.current_proxy % len(self.proxies)]
|
| 340 |
+
self.current_proxy += 1
|
| 341 |
+
return proxy
|
| 342 |
|
| 343 |
# ════════════════════════════════════════════════════════════════════════════
|
| 344 |
# SECTION 4: PASSIVE OSINT ENGINE
|
|
|
|
| 353 |
self.logger = self._setup_logging()
|
| 354 |
|
| 355 |
def _setup_logging(self):
|
| 356 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
| 357 |
return logging.getLogger("PassiveOSINT")
|
| 358 |
|
| 359 |
async def gather_dns_intel(self, domain: str) -> Dict:
|
|
|
|
| 362 |
"subdomains": [],
|
| 363 |
"mx_records": [],
|
| 364 |
"ns_records": [],
|
| 365 |
+
"txt_records": [],
|
| 366 |
+
"a_records": [],
|
| 367 |
+
"aaaa_records": [],
|
| 368 |
+
"cname_records": []
|
| 369 |
}
|
| 370 |
|
| 371 |
try:
|
|
|
|
| 374 |
# Try common subdomains
|
| 375 |
common_subs = [
|
| 376 |
"www", "mail", "ftp", "admin", "api", "dev", "staging",
|
| 377 |
+
"cdn", "test", "blog", "shop", "support", "docs", "app",
|
| 378 |
+
"portal", "secure", "vpn", "remote", "webmail", "mx",
|
| 379 |
+
"ns1", "ns2", "dns", "autodiscover", "autoconfig"
|
| 380 |
]
|
| 381 |
|
| 382 |
for sub in common_subs:
|
|
|
|
| 386 |
for rdata in result:
|
| 387 |
intel["subdomains"].append({
|
| 388 |
"subdomain": full_domain,
|
| 389 |
+
"ip": str(rdata),
|
| 390 |
+
"type": "A"
|
| 391 |
+
})
|
| 392 |
+
except:
|
| 393 |
+
pass
|
| 394 |
+
|
| 395 |
+
# Try AAAA records
|
| 396 |
+
try:
|
| 397 |
+
full_domain = f"{sub}.{domain}"
|
| 398 |
+
result = dns.resolver.resolve(full_domain, 'AAAA')
|
| 399 |
+
for rdata in result:
|
| 400 |
+
intel["aaaa_records"].append({
|
| 401 |
+
"subdomain": full_domain,
|
| 402 |
+
"ipv6": str(rdata)
|
| 403 |
})
|
| 404 |
except:
|
| 405 |
pass
|
|
|
|
| 407 |
# MX records
|
| 408 |
try:
|
| 409 |
mx = dns.resolver.resolve(domain, 'MX')
|
| 410 |
+
intel["mx_records"] = [{"preference": r.preference, "exchange": str(r.exchange)} for r in mx]
|
| 411 |
+
except:
|
| 412 |
+
pass
|
| 413 |
+
|
| 414 |
+
# NS records
|
| 415 |
+
try:
|
| 416 |
+
ns = dns.resolver.resolve(domain, 'NS')
|
| 417 |
+
intel["ns_records"] = [str(r) for r in ns]
|
| 418 |
except:
|
| 419 |
pass
|
| 420 |
|
|
|
|
| 432 |
|
| 433 |
async def gather_ssl_cert_intel(self, domain: str) -> Dict:
|
| 434 |
"""SSL certificate analysis for subdomains"""
|
|
|
|
|
|
|
|
|
|
| 435 |
cert_intel = {
|
| 436 |
"subject": None,
|
| 437 |
"issuer": None,
|
| 438 |
"valid_from": None,
|
| 439 |
"valid_to": None,
|
| 440 |
+
"subjectAltNames": [],
|
| 441 |
+
"serial_number": None,
|
| 442 |
+
"signature_algorithm": None,
|
| 443 |
+
"version": None,
|
| 444 |
+
"expired": False,
|
| 445 |
+
"valid": False
|
| 446 |
}
|
| 447 |
|
| 448 |
try:
|
|
|
|
| 450 |
with socket.create_connection((domain, 443), timeout=5) as sock:
|
| 451 |
with context.wrap_socket(sock, server_hostname=domain) as ssock:
|
| 452 |
cert = ssock.getpeercert()
|
| 453 |
+
cipher = ssock.cipher()
|
| 454 |
+
version = ssock.version()
|
| 455 |
|
| 456 |
cert_intel["subject"] = dict(x[0] for x in cert['subject'])
|
| 457 |
cert_intel["issuer"] = dict(x[0] for x in cert['issuer'])
|
| 458 |
cert_intel["valid_from"] = cert['notBefore']
|
| 459 |
cert_intel["valid_to"] = cert['notAfter']
|
| 460 |
+
cert_intel["serial_number"] = cert.get('serialNumber')
|
| 461 |
+
cert_intel["signature_algorithm"] = cert.get('signatureAlgorithm')
|
| 462 |
+
cert_intel["version"] = version
|
| 463 |
+
cert_intel["cipher"] = cipher
|
| 464 |
+
|
| 465 |
+
# Check expiration
|
| 466 |
+
from datetime import datetime
|
| 467 |
+
expiry = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
|
| 468 |
+
cert_intel["expired"] = expiry < datetime.now()
|
| 469 |
+
cert_intel["valid"] = True
|
| 470 |
|
| 471 |
# Extract SANs
|
| 472 |
for alt_name in cert.get('subjectAltName', []):
|
|
|
|
| 477 |
|
| 478 |
return cert_intel
|
| 479 |
|
| 480 |
+
async def crt_sh_lookup(self, domain: str) -> List[str]:
|
| 481 |
+
"""Query Certificate Transparency logs via crt.sh"""
|
| 482 |
+
subdomains = set()
|
| 483 |
+
try:
|
| 484 |
+
url = f"https://crt.sh/?q=%.{domain}&output=json"
|
| 485 |
+
headers = self.config.get_headers()
|
| 486 |
+
|
| 487 |
+
async with aiohttp.ClientSession() as session:
|
| 488 |
+
async with session.get(url, headers=headers, timeout=10) as resp:
|
| 489 |
+
if resp.status == 200:
|
| 490 |
+
data = await resp.json()
|
| 491 |
+
for entry in data:
|
| 492 |
+
name = entry.get('name_value', '')
|
| 493 |
+
if name and '*' not in name:
|
| 494 |
+
subdomains.add(name)
|
| 495 |
+
except Exception as e:
|
| 496 |
+
self.logger.error(f"crt.sh lookup failed: {e}")
|
| 497 |
+
|
| 498 |
+
return list(subdomains)
|
| 499 |
+
|
| 500 |
async def github_reconnaissance(self, org_name: str) -> Dict:
|
| 501 |
"""Search GitHub for organization info"""
|
| 502 |
github_intel = {
|
| 503 |
"repositories": [],
|
| 504 |
"leaked_patterns": [],
|
| 505 |
+
"technology_hints": [],
|
| 506 |
+
"members": [],
|
| 507 |
+
"gists": []
|
| 508 |
}
|
| 509 |
|
| 510 |
try:
|
| 511 |
+
# Search repos
|
| 512 |
endpoint = f"https://api.github.com/users/{org_name}/repos"
|
| 513 |
headers = self.config.get_headers()
|
| 514 |
|
|
|
|
| 516 |
async with session.get(endpoint, headers=headers, timeout=10) as resp:
|
| 517 |
if resp.status == 200:
|
| 518 |
repos = await resp.json()
|
| 519 |
+
for repo in repos[:20]: # Limit to 20
|
| 520 |
github_intel["repositories"].append({
|
| 521 |
"name": repo.get("name"),
|
| 522 |
"url": repo.get("html_url"),
|
| 523 |
"description": repo.get("description"),
|
| 524 |
+
"language": repo.get("language"),
|
| 525 |
+
"stars": repo.get("stargazers_count"),
|
| 526 |
+
"forks": repo.get("forks_count"),
|
| 527 |
+
"updated": repo.get("updated_at")
|
| 528 |
})
|
| 529 |
|
| 530 |
if repo.get("language"):
|
| 531 |
github_intel["technology_hints"].append(repo.get("language"))
|
| 532 |
+
|
| 533 |
+
# Check for common leaked patterns in repo names/descriptions
|
| 534 |
+
desc = (repo.get("description") or "").lower()
|
| 535 |
+
if any(x in desc for x in ['password', 'secret', 'key', 'token', 'credential']):
|
| 536 |
+
github_intel["leaked_patterns"].append({
|
| 537 |
+
"repo": repo.get("name"),
|
| 538 |
+
"pattern": "Potential secret in description"
|
| 539 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 540 |
|
| 541 |
+
# Search for gists
|
| 542 |
+
gist_endpoint = f"https://api.github.com/users/{org_name}/gists"
|
| 543 |
+
async with aiohttp.ClientSession() as session:
|
| 544 |
+
async with session.get(gist_endpoint, headers=headers, timeout=10) as resp:
|
| 545 |
+
if resp.status == 200:
|
| 546 |
+
gists = await resp.json()
|
| 547 |
+
for gist in gists[:10]:
|
| 548 |
+
github_intel["gists"].append({
|
| 549 |
+
"id": gist.get("id"),
|
| 550 |
+
# BÖLÜM 2: KODUN 8-10. BÖLÜMLERİ
|
| 551 |
+
# Bu dosyayı app_part2.py olarak kaydedin
|
| 552 |
|
| 553 |
+
part2_code = '''"""
|
| 554 |
+
═══════════════════════════════════════════════════════════════════════════════
|
| 555 |
+
PRIVATE RED TEAM WEB RECONNAISSANCE FRAMEWORK v3.0 - PART 2
|
| 556 |
+
─────────────────────────────────────────────────────────────────────────
|
| 557 |
+
Bölümler: 8-10 (Reporting Engine, Main Orchestrator, Gradio Interface)
|
| 558 |
+
═══════════════════════════════════════════════════════════════════════════════
|
| 559 |
+
"""
|
| 560 |
|
| 561 |
+
# Part 1'deki importları ve sınıfları tekrar etmek için:
|
| 562 |
+
# Bu dosyayı çalıştırmadan önce Part 1'i import edin veya birleştirin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
|
| 564 |
# ════════════════════════════════════════════════════════════════════════════
|
| 565 |
# SECTION 8: COMPREHENSIVE REPORTING ENGINE
|
|
|
|
| 570 |
|
| 571 |
@staticmethod
|
| 572 |
def generate_assessment_report(target: str, recon_data: Dict, threat_vectors: List[ThreatVector],
|
| 573 |
+
attack_paths: List[AttackPath], stride_report: Dict,
|
| 574 |
+
vulnerabilities: List[Vulnerability] = None) -> str:
|
| 575 |
"""Generate comprehensive assessment report"""
|
| 576 |
|
| 577 |
+
vulns = vulnerabilities or []
|
| 578 |
+
|
| 579 |
report = f"""
|
| 580 |
╔════════════════════════════════════════════════════════════════════════╗
|
| 581 |
║ PROFESSIONAL SECURITY ASSESSMENT REPORT ║
|
| 582 |
║ [CONFIDENTIAL] ║
|
| 583 |
+
║ PRIVATE SPACE EDITION v3.0 ║
|
| 584 |
╚════════════════════════════════════════════════════════════════════════╝
|
| 585 |
|
| 586 |
EXECUTIVE SUMMARY
|
| 587 |
─────────────────────────────────────────────────────────────────────────
|
| 588 |
Target: {target}
|
| 589 |
Assessment Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 590 |
+
Assessed By: Red Team Framework v3.0 (Private Space)
|
| 591 |
Classification: CONFIDENTIAL
|
| 592 |
+
Assessment Type: Comprehensive Web Application Security Assessment
|
| 593 |
|
| 594 |
RISK OVERVIEW
|
| 595 |
─────────────────────────────────────────────────────────────────────────
|
| 596 |
+
Critical Findings: {len([t for t in vulns if t.cvss_score >= 9.0])}
|
| 597 |
+
High Findings: {len([t for t in vulns if 7.0 <= t.cvss_score < 9.0])}
|
| 598 |
+
Medium Findings: {len([t for t in vulns if 4.0 <= t.cvss_score < 7.0])}
|
| 599 |
+
Low Findings: {len([t for t in vulns if t.cvss_score < 4.0])}
|
| 600 |
|
| 601 |
+
Overall Risk Level: {"🔴 CRITICAL" if len([t for t in vulns if t.cvss_score >= 9.0]) > 0 else "🟠 HIGH" if len([t for t in vulns if t.cvss_score >= 7.0]) > 0 else "🟡 MEDIUM"}
|
| 602 |
|
| 603 |
ATTACK SURFACE
|
| 604 |
─────────────────────────────────────────────────────────────────────────
|
| 605 |
+
Technologies Identified: {len(recon_data.get('technologies', {}).get('cms', [])) + len(recon_data.get('technologies', {}).get('frameworks', []))}
|
| 606 |
API Endpoints: {len(recon_data.get('endpoints', []))}
|
| 607 |
Forms Discovered: {len(recon_data.get('forms', []))}
|
| 608 |
Subdomains Found: {len(recon_data.get('subdomains', []))}
|
| 609 |
+
JavaScript Files Analyzed: {len(recon_data.get('js_files', []))}
|
| 610 |
+
Security Headers Score: {recon_data.get('security_headers', {}).get('score', 0):.1f}%
|
| 611 |
|
| 612 |
TECHNOLOGIES DETECTED
|
| 613 |
─────────────────────────────────────────────────────────────────────────
|
| 614 |
+
Web Server: {recon_data.get('technologies', {}).get('web_server', 'Unknown')}
|
| 615 |
+
CMS: {', '.join(recon_data.get('technologies', {}).get('cms', ['None detected']))}
|
| 616 |
+
Frameworks: {', '.join(recon_data.get('technologies', {}).get('frameworks', ['None detected']))}
|
| 617 |
+
JavaScript Libraries: {', '.join(recon_data.get('technologies', {}).get('javascript', ['None detected']))}
|
| 618 |
+
CDN: {', '.join(recon_data.get('technologies', {}).get('cdn', ['None detected']))}
|
| 619 |
+
|
| 620 |
+
VULNERABILITY DETAILS
|
| 621 |
+
─────────────────────────────────────────────────────────────────────────
|
| 622 |
+
"""
|
| 623 |
+
|
| 624 |
+
for i, vuln in enumerate(vulns, 1):
|
| 625 |
+
report += f"""
|
| 626 |
+
[{i}] {vuln.name}
|
| 627 |
+
Severity: {vuln.severity}
|
| 628 |
+
CVSS Score: {vuln.cvss_score}
|
| 629 |
+
CVSS Vector: {vuln.cvss_vector}
|
| 630 |
+
CWE ID: {vuln.cwe_id or 'N/A'}
|
| 631 |
+
OWASP Category: {vuln.owasp_category or 'N/A'}
|
| 632 |
+
Location: {vuln.location}
|
| 633 |
+
|
| 634 |
+
Description:
|
| 635 |
+
{vuln.description}
|
| 636 |
+
|
| 637 |
+
Evidence:
|
| 638 |
+
{vuln.evidence}
|
| 639 |
+
|
| 640 |
+
Remediation:
|
| 641 |
+
{vuln.remediation}
|
| 642 |
+
|
| 643 |
+
MITRE ATT&CK Techniques: {', '.join(vuln.mitre_techniques)}
|
| 644 |
+
|
| 645 |
+
{'─' * 70}
|
| 646 |
+
"""
|
| 647 |
+
|
| 648 |
+
report += f"""
|
| 649 |
|
| 650 |
THREAT VECTORS
|
| 651 |
─────────────────────────────────────────────────────────────────────────
|
|
|
|
| 657 |
Location: {vector.location}
|
| 658 |
Risk Score: {vector.risk_score}/10
|
| 659 |
CVSS Score: {vector.cvss_score if vector.cvss_score else 'N/A'}
|
| 660 |
+
CWE ID: {vector.cwe_id or 'N/A'}
|
| 661 |
MITRE ATT&CK: {', '.join(vector.techniques)}
|
| 662 |
Description: {vector.description}
|
| 663 |
+
Evidence: {vector.evidence or 'N/A'}
|
| 664 |
"""
|
| 665 |
|
| 666 |
report += f"""
|
|
|
|
| 672 |
for threat_type, threat_data in stride_report.items():
|
| 673 |
report += f"""
|
| 674 |
{threat_type}:
|
| 675 |
+
Risk Level: {threat_data.get('risk_level', 'LOW')}
|
| 676 |
Description: {threat_data['description']}
|
| 677 |
+
Potential Impacts:
|
| 678 |
"""
|
| 679 |
+
for impact in threat_data.get('potential_impacts', []):
|
| 680 |
+
report += f" • {impact}\\n"
|
| 681 |
+
|
| 682 |
+
report += f" Affected Components:\\n"
|
| 683 |
+
for component in threat_data.get('affected_components', []):
|
| 684 |
+
report += f" • {component}\\n"
|
| 685 |
+
|
| 686 |
+
report += f" Mitigations: {', '.join(threat_data['mitigations'])}\\n"
|
| 687 |
|
| 688 |
report += f"""
|
| 689 |
|
|
|
|
| 697 |
Entry Point: {path.entry_point}
|
| 698 |
Complexity: {path.complexity}/1.0
|
| 699 |
Risk Level: {path.risk_level}
|
| 700 |
+
MITRE ATT&CK Techniques: {', '.join(path.mitre_techniques)}
|
| 701 |
Steps:
|
| 702 |
"""
|
| 703 |
for step in path.intermediate_steps:
|
| 704 |
+
report += f" → {step}\\n"
|
| 705 |
|
| 706 |
report += """
|
| 707 |
|
| 708 |
RECOMMENDATIONS
|
| 709 |
─────────────────────────────────────────────────────────────────────────
|
| 710 |
+
1. IMMEDIATE (Critical - Fix within 24 hours):
|
| 711 |
+
• Patch all critical CVEs (CVSS 9.0+)
|
| 712 |
+
• Disable exposed sensitive files (.env, .git)
|
| 713 |
+
• Enable WAF rules for SQL injection protection
|
| 714 |
+
• Implement rate limiting on authentication endpoints
|
| 715 |
+
• Enable security headers (CSP, HSTS, X-Frame-Options)
|
| 716 |
|
| 717 |
+
2. SHORT-TERM (High - Fix within 1 week):
|
| 718 |
+
• Update outdated technologies and frameworks
|
| 719 |
+
• Implement input validation on all forms
|
| 720 |
+
• Enable HTTPS enforcement (HSTS)
|
| 721 |
+
• Setup security monitoring and alerting
|
| 722 |
+
• Conduct code review for injection vulnerabilities
|
| 723 |
|
| 724 |
+
3. MEDIUM-TERM (Medium - Fix within 1 month):
|
| 725 |
+
• Implement Web Application Firewall (WAF)
|
| 726 |
+
• Conduct penetration testing
|
| 727 |
+
• Implement secure session management
|
| 728 |
+
• Setup vulnerability disclosure program
|
| 729 |
+
• Regular security training for developers
|
| 730 |
+
|
| 731 |
+
4. LONG-TERM (Ongoing):
|
| 732 |
+
• Implement Secure SDLC
|
| 733 |
+
• Regular automated security scanning
|
| 734 |
+
• Bug bounty program
|
| 735 |
+
• Incident response planning
|
| 736 |
+
• Compliance auditing (OWASP ASVS)
|
| 737 |
+
|
| 738 |
+
COMPLIANCE MAPPING
|
| 739 |
+
─────────────────────────────────────────────────────────────────────────
|
| 740 |
+
OWASP Top 10 2021:
|
| 741 |
+
"""
|
| 742 |
+
|
| 743 |
+
owasp_categories = defaultdict(list)
|
| 744 |
+
for vuln in vulns:
|
| 745 |
+
if vuln.owasp_category:
|
| 746 |
+
owasp_categories[vuln.owasp_category].append(vuln.name)
|
| 747 |
+
|
| 748 |
+
for category, vuln_list in owasp_categories.items():
|
| 749 |
+
report += f" {category}: {len(vuln_list)} findings\\n"
|
| 750 |
+
for v in vuln_list[:3]: # Limit to 3 per category
|
| 751 |
+
report += f" • {v}\\n"
|
| 752 |
+
|
| 753 |
+
report += f"""
|
| 754 |
+
|
| 755 |
+
MITRE ATT&CK MAPPING
|
| 756 |
+
─────────────────────────────────────────────────────────────────────────
|
| 757 |
+
"""
|
| 758 |
+
|
| 759 |
+
mitre_techniques = set()
|
| 760 |
+
for vuln in vulns:
|
| 761 |
+
mitre_techniques.update(vuln.mitre_techniques)
|
| 762 |
+
for path in attack_paths:
|
| 763 |
+
mitre_techniques.update(path.mitre_techniques)
|
| 764 |
+
|
| 765 |
+
for tech in sorted(mitre_techniques):
|
| 766 |
+
report += f" • {tech}"
|
| 767 |
+
# Add technique name if available
|
| 768 |
+
for category, techniques in MITRE_TECHNIQUES.items():
|
| 769 |
+
if tech in techniques:
|
| 770 |
+
report += f" - {techniques[tech]}"
|
| 771 |
+
break
|
| 772 |
+
report += "\\n"
|
| 773 |
+
|
| 774 |
+
report += f"""
|
| 775 |
|
| 776 |
METHODOLOGY
|
| 777 |
─────────────────────────────────────────────────────────────────────────
|
| 778 |
+
1. Passive OSINT (Non-intrusive):
|
| 779 |
+
• DNS record enumeration (A, AAAA, MX, NS, TXT)
|
| 780 |
+
• SSL/TLS certificate analysis
|
| 781 |
+
• Certificate Transparency log queries (crt.sh)
|
| 782 |
+
• GitHub reconnaissance
|
| 783 |
+
• Wayback Machine historical data
|
| 784 |
+
• Shodan/Censys intelligence (if API available)
|
| 785 |
+
|
| 786 |
+
2. Active Reconnaissance (Low impact):
|
| 787 |
+
• HTTP header analysis
|
| 788 |
+
• Technology fingerprinting
|
| 789 |
+
• Endpoint discovery
|
| 790 |
+
• Form analysis
|
| 791 |
+
• JavaScript endpoint extraction
|
| 792 |
+
• Security headers assessment
|
| 793 |
+
|
| 794 |
+
3. Vulnerability Analysis:
|
| 795 |
+
• Pattern-based detection
|
| 796 |
+
• Configuration weakness identification
|
| 797 |
+
• Information disclosure checks
|
| 798 |
+
• Injection vulnerability probes (safe)
|
| 799 |
+
|
| 800 |
+
4. Threat Modeling:
|
| 801 |
+
• STRIDE analysis
|
| 802 |
+
• Attack path generation
|
| 803 |
+
• MITRE ATT&CK mapping
|
| 804 |
+
• Risk scoring (CVSS v3.1)
|
| 805 |
+
|
| 806 |
+
5. Reporting:
|
| 807 |
+
• Executive summary
|
| 808 |
+
• Technical findings
|
| 809 |
+
• Remediation guidance
|
| 810 |
+
• Compliance mapping
|
| 811 |
+
|
| 812 |
+
TOOLS & TECHNIQUES
|
| 813 |
+
─────────────────────────────────────────────────────────────────────────
|
| 814 |
+
• Framework: Red Team Recon Framework v3.0
|
| 815 |
+
• Standards: OWASP Testing Guide, PTES, CVSS v3.1
|
| 816 |
+
• Threat Model: STRIDE, MITRE ATT&CK v12
|
| 817 |
+
• Visualization: NetworkX, Plotly
|
| 818 |
+
• OSINT: DNS, SSL, crt.sh, GitHub, Wayback
|
| 819 |
+
|
| 820 |
+
LIMITATIONS
|
| 821 |
+
─────────────────────────────────────────────────────────────────────────
|
| 822 |
+
• Assessment limited to authorized scope
|
| 823 |
+
• No active exploitation performed
|
| 824 |
+
• Rate limiting may affect scan completeness
|
| 825 |
+
• Some checks require manual verification
|
| 826 |
+
• API keys needed for full OSINT features
|
| 827 |
|
| 828 |
═══════════════════════════════════════════════════════════════════════════
|
| 829 |
Report Generated: {datetime.now().isoformat()}
|
| 830 |
Classification: CONFIDENTIAL - DO NOT DISTRIBUTE
|
| 831 |
+
Private Space Assessment - Authorized Testing Only
|
| 832 |
═══════════════════��═══════════════════════════════════════════════════════
|
| 833 |
"""
|
| 834 |
return report
|
| 835 |
+
|
| 836 |
+
@staticmethod
|
| 837 |
+
def generate_executive_summary(target: str, recon_data: Dict, vulnerabilities: List[Vulnerability]) -> str:
|
| 838 |
+
"""Generate executive summary for C-level"""
|
| 839 |
+
|
| 840 |
+
critical = len([v for v in vulnerabilities if v.cvss_score >= 9.0])
|
| 841 |
+
high = len([v for v in vulnerabilities if 7.0 <= v.cvss_score < 9.0])
|
| 842 |
+
medium = len([v for v in vulnerabilities if 4.0 <= v.cvss_score < 7.0])
|
| 843 |
+
|
| 844 |
+
summary = f"""
|
| 845 |
+
EXECUTIVE SUMMARY
|
| 846 |
+
═══════════════════════════════════════════════════════════════════════════
|
| 847 |
+
|
| 848 |
+
Target Organization: {target}
|
| 849 |
+
Assessment Period: {datetime.now().strftime('%Y-%m-%d')}
|
| 850 |
+
Overall Risk Rating: {"CRITICAL" if critical > 0 else "HIGH" if high > 0 else "MEDIUM"}
|
| 851 |
+
|
| 852 |
+
KEY FINDINGS:
|
| 853 |
+
• {critical} Critical vulnerabilities requiring immediate attention
|
| 854 |
+
• {high} High-risk vulnerabilities to address within 1 week
|
| 855 |
+
• {medium} Medium-risk vulnerabilities for next sprint
|
| 856 |
+
|
| 857 |
+
BUSINESS IMPACT:
|
| 858 |
+
"""
|
| 859 |
+
|
| 860 |
+
if critical > 0:
|
| 861 |
+
summary += "• CRITICAL: Immediate risk of data breach or system compromise\\n"
|
| 862 |
+
if high > 0:
|
| 863 |
+
summary += "• HIGH: Significant risk to business operations and data integrity\\n"
|
| 864 |
+
|
| 865 |
+
summary += f"""
|
| 866 |
+
IMMEDIATE ACTIONS REQUIRED:
|
| 867 |
+
1. Convene security incident response team
|
| 868 |
+
2. Prioritize critical vulnerability remediation
|
| 869 |
+
3. Review and enhance monitoring capabilities
|
| 870 |
+
4. Consider temporary WAF rules for protection
|
| 871 |
+
|
| 872 |
+
ESTIMATED REMEDIATION EFFORT:
|
| 873 |
+
• Critical issues: 1-3 days
|
| 874 |
+
• High issues: 1-2 weeks
|
| 875 |
+
• Full remediation: 1-3 months
|
| 876 |
+
|
| 877 |
+
RECOMMENDED INVESTMENT:
|
| 878 |
+
• Immediate security patches: $5K-$15K
|
| 879 |
+
• Security infrastructure improvements: $25K-$75K
|
| 880 |
+
• Ongoing security program: $100K-$300K annually
|
| 881 |
+
|
| 882 |
+
═══════════════════════════════════════════════════════════════════════════
|
| 883 |
+
"""
|
| 884 |
+
return summary
|
| 885 |
|
| 886 |
# ════════════════════════════════════════════════════════════════════════════
|
| 887 |
# SECTION 9: MAIN ORCHESTRATOR
|
|
|
|
| 905 |
"target": target_url,
|
| 906 |
"timestamp": datetime.now().isoformat(),
|
| 907 |
"subdomains": [],
|
| 908 |
+
"technologies": {},
|
| 909 |
"endpoints": [],
|
| 910 |
"forms": [],
|
| 911 |
"js_files": [],
|
| 912 |
+
"security_headers": {},
|
| 913 |
+
"vulnerabilities": [],
|
| 914 |
"threat_vectors": [],
|
| 915 |
"attack_paths": [],
|
| 916 |
"stride_analysis": {},
|
|
|
|
| 920 |
|
| 921 |
try:
|
| 922 |
# PHASE 1: Passive OSINT
|
| 923 |
+
print("[1/5] Passive OSINT gathering...")
|
| 924 |
passive_data = await self.passive_engine.gather_dns_intel(target_url)
|
| 925 |
results["subdomains"] = passive_data.get("subdomains", [])
|
| 926 |
|
|
|
|
| 931 |
for san in ssl_data["subjectAltNames"]
|
| 932 |
])
|
| 933 |
|
| 934 |
+
# Certificate Transparency logs
|
| 935 |
+
ct_subdomains = await self.passive_engine.crt_sh_lookup(target_url)
|
| 936 |
+
for sub in ct_subdomains:
|
| 937 |
+
if sub not in [s.get("subdomain") for s in results["subdomains"]]:
|
| 938 |
+
results["subdomains"].append({"subdomain": sub, "ip": "from_ct"})
|
| 939 |
+
|
| 940 |
+
# GitHub recon
|
| 941 |
github_data = await self.passive_engine.github_reconnaissance(target_url.replace(".com", ""))
|
| 942 |
results["github_intel"] = github_data
|
| 943 |
|
| 944 |
+
# Wayback Machine
|
| 945 |
+
wayback_urls = await self.passive_engine.wayback_machine_lookup(target_url)
|
| 946 |
+
results["historical_urls"] = wayback_urls
|
| 947 |
+
|
| 948 |
# PHASE 2: Active Reconnaissance
|
| 949 |
+
print("[2/5] Active reconnaissance...")
|
| 950 |
technologies = await self.active_engine.fingerprint_technologies(target_url)
|
| 951 |
results["technologies"] = technologies
|
| 952 |
|
| 953 |
+
endpoints = await self.active_engine.discover_endpoints(target_url, COMMON_ENDPOINTS)
|
| 954 |
+
results["endpoints"] = endpoints
|
|
|
|
|
|
|
|
|
|
| 955 |
|
| 956 |
forms = await self.active_engine.analyze_forms(target_url)
|
| 957 |
results["forms"] = forms
|
|
|
|
| 959 |
js_endpoints = await self.active_engine.extract_javascript_endpoints(target_url)
|
| 960 |
results["js_files"] = js_endpoints
|
| 961 |
|
| 962 |
+
security_headers = await self.active_engine.analyze_security_headers(target_url)
|
| 963 |
+
results["security_headers"] = security_headers
|
| 964 |
+
|
| 965 |
+
# PHASE 3: Vulnerability Analysis
|
| 966 |
+
print("[3/5] Vulnerability analysis...")
|
| 967 |
+
vulnerabilities = await self.active_engine.check_common_vulnerabilities(target_url)
|
| 968 |
+
results["vulnerabilities"] = [asdict(v) for v in vulnerabilities]
|
| 969 |
+
|
| 970 |
+
# PHASE 4: Threat Modeling
|
| 971 |
+
print("[4/5] Threat modeling...")
|
| 972 |
threat_vectors = self.threat_model.analyze_web_app(results)
|
| 973 |
results["threat_vectors"] = [asdict(tv) for tv in threat_vectors]
|
| 974 |
|
|
|
|
| 978 |
stride_analysis = self.threat_model.generate_stride_report(results)
|
| 979 |
results["stride_analysis"] = stride_analysis
|
| 980 |
|
| 981 |
+
# PHASE 5: Attack Graph
|
| 982 |
+
print("[5/5] Generating attack graph...")
|
| 983 |
+
graph_data = self.graph_engine.create_enhanced_attack_graph(
|
| 984 |
+
threat_vectors, attack_paths, vulnerabilities
|
| 985 |
+
)
|
| 986 |
results["graph_data"] = graph_data
|
| 987 |
|
| 988 |
+
# PHASE 6: Reporting
|
| 989 |
+
print("[6/6] Generating report...")
|
| 990 |
report = self.reporting.generate_assessment_report(
|
| 991 |
+
target_url, results, threat_vectors, attack_paths, stride_analysis, vulnerabilities
|
| 992 |
)
|
| 993 |
results["report"] = report
|
| 994 |
|
| 995 |
+
print("✅ Assessment complete!")
|
| 996 |
+
|
| 997 |
except Exception as e:
|
| 998 |
results["error"] = str(e)
|
| 999 |
logging.error(f"Assessment failed: {e}")
|
| 1000 |
+
import traceback
|
| 1001 |
+
results["traceback"] = traceback.format_exc()
|
| 1002 |
|
| 1003 |
return results
|
| 1004 |
|
|
|
|
| 1013 |
"""Gradio wrapper function"""
|
| 1014 |
|
| 1015 |
try:
|
| 1016 |
+
if not target_url:
|
| 1017 |
+
return "Error: Please enter a target domain", "{}", go.Figure(), "No report generated"
|
| 1018 |
+
|
| 1019 |
+
# Clean target URL
|
| 1020 |
+
target_url = target_url.replace("https://", "").replace("http://", "").strip("/")
|
| 1021 |
+
|
| 1022 |
progress(0.1, desc="🔍 Validating target...")
|
| 1023 |
|
| 1024 |
# Update threat level
|
|
|
|
| 1048 |
else:
|
| 1049 |
fig = go.Figure()
|
| 1050 |
|
| 1051 |
+
# Calculate stats
|
| 1052 |
+
vulns = results.get("vulnerabilities", [])
|
| 1053 |
+
critical = len([v for v in vulns if v.get("cvss_score", 0) >= 9.0])
|
| 1054 |
+
high = len([v for v in vulns if 7.0 <= v.get("cvss_score", 0) < 9.0])
|
| 1055 |
+
medium = len([v for v in vulns if 4.0 <= v.get("cvss_score", 0) < 7.0])
|
| 1056 |
+
|
| 1057 |
# Summary
|
| 1058 |
summary = f"""
|
| 1059 |
## 🔴 ASSESSMENT COMPLETE
|
| 1060 |
|
| 1061 |
**Target:** {target_url}
|
| 1062 |
+
**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 1063 |
+
**Threat Level:** {threat_level}
|
| 1064 |
|
| 1065 |
### Quick Stats
|
| 1066 |
- 🌐 Subdomains: {len(results.get('subdomains', []))}
|
| 1067 |
+
- 🔧 Technologies: {len(results.get('technologies', {}).get('cms', [])) + len(results.get('technologies', {}).get('frameworks', []))}
|
| 1068 |
+
- 📍 Endpoints:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|