ziffir commited on
Commit
d5aac00
·
verified ·
1 Parent(s): 3a0665a

Upload improved_app_v2.0.py

Browse files
Files changed (1) hide show
  1. improved_app_v2.0.py +1081 -0
improved_app_v2.0.py ADDED
@@ -0,0 +1,1081 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ═══════════════════════════════════════════════════════════════════════════════
3
+ PROFESSIONAL RED TEAM WEB RECONNAISSANCE FRAMEWORK v2.0
4
+ ─────────────────────────────────────────────────────────────────────────
5
+ Advanced Web Application Security Assessment Tool
6
+ Features: OSINT, Active Recon, Threat Modeling, STRIDE, MITRE ATT&CK
7
+ ═══════════════════════════════════════════════════════════════════════════════
8
+ """
9
+
10
+ import gradio as gr
11
+ import asyncio
12
+ import json
13
+ import aiohttp
14
+ from typing import Dict, List, Tuple, Set, Optional
15
+ from dataclasses import dataclass, asdict
16
+ from datetime import datetime
17
+ from collections import defaultdict
18
+ import re
19
+ import logging
20
+ import random
21
+ import time
22
+ import hashlib
23
+ from enum import Enum
24
+ import requests
25
+ from bs4 import BeautifulSoup
26
+ import networkx as nx
27
+ 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
34
+ # ════════════════════════════════════════════════════════════════════════════
35
+
36
+ class ThreatLevel(Enum):
37
+ """Threat/Risk Assessment Levels"""
38
+ LOW = 0
39
+ MEDIUM = 1
40
+ HIGH = 2
41
+ CRITICAL = 3
42
+
43
+ class CVESSeverity(Enum):
44
+ """CVSS Severity Ratings"""
45
+ CRITICAL = (9.0, 10.0)
46
+ HIGH = (7.0, 8.9)
47
+ MEDIUM = (4.0, 6.9)
48
+ LOW = (0.1, 3.9)
49
+
50
+ # STRIDE Threat Model
51
+ STRIDE_THREATS = {
52
+ "Spoofing": {
53
+ "description": "Identity spoofing",
54
+ "techniques": ["T1027", "T1556"],
55
+ "mitigations": ["MFA", "SAML", "OAuth"]
56
+ },
57
+ "Tampering": {
58
+ "description": "Data/Code manipulation",
59
+ "techniques": ["T1565", "T1491"],
60
+ "mitigations": ["Input validation", "WAF", "HTTPS"]
61
+ },
62
+ "Repudiation": {
63
+ "description": "Action denial",
64
+ "techniques": ["T1562"],
65
+ "mitigations": ["Logging", "Audit trails"]
66
+ },
67
+ "InformationDisclosure": {
68
+ "description": "Data leakage",
69
+ "techniques": ["T1041", "T1048"],
70
+ "mitigations": ["Encryption", "DLP"]
71
+ },
72
+ "DenialOfService": {
73
+ "description": "Service unavailability",
74
+ "techniques": ["T1561"],
75
+ "mitigations": ["Rate limiting", "DDoS protection"]
76
+ },
77
+ "ElevationOfPrivilege": {
78
+ "description": "Privilege escalation",
79
+ "techniques": ["T1134", "T1548"],
80
+ "mitigations": ["RBAC", "Least privilege"]
81
+ }
82
+ }
83
+
84
+ # Technology fingerprints
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\.css"],
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\.js"],
105
+ "Vue": [r"__VUE", r"vue\.js"],
106
+ "Angular": [r"ng-app", r"angular\.js"]
107
+ }
108
+ }
109
+
110
+ # Vulnerability database (simplified)
111
+ VULNERABILITY_DATABASE = {
112
+ "wordpress_plugins": {"severity": "HIGH", "avg_cvss": 7.5},
113
+ "outdated_framework": {"severity": "HIGH", "avg_cvss": 7.8},
114
+ "exposed_api": {"severity": "CRITICAL", "avg_cvss": 9.2},
115
+ "sql_injection": {"severity": "CRITICAL", "avg_cvss": 9.9},
116
+ "xss": {"severity": "HIGH", "avg_cvss": 6.1},
117
+ }
118
+
119
+ # ════════════════════════════════════════════════════════════════════════════
120
+ # SECTION 2: DATA MODELS
121
+ # ════════════════════════════════════════════════════════════════════════════
122
+
123
+ @dataclass
124
+ class IntelligenceIndicator:
125
+ """IOC - Indicator of Compromise"""
126
+ type: str # domain, subdomain, ip, email, tech, endpoint
127
+ value: str
128
+ confidence: float # 0.0-1.0
129
+ source: str
130
+ timestamp: str
131
+ metadata: Optional[Dict] = None
132
+
133
+ @dataclass
134
+ class ThreatVector:
135
+ """Attack surface element"""
136
+ category: str
137
+ location: str
138
+ risk_score: float
139
+ techniques: List[str]
140
+ description: str
141
+ cvss_score: Optional[float] = None
142
+
143
+ @dataclass
144
+ class AttackPath:
145
+ """End-to-end attack chain"""
146
+ entry_point: str
147
+ intermediate_steps: List[str]
148
+ objective: str
149
+ risk_level: str
150
+ complexity: float # 0.0 to 1.0
151
+
152
+ # ════════════════════════════════════════════════════════════════════════════
153
+ # SECTION 3: STEALTH & OPSEC ENGINE
154
+ # ════════════════════════════════════════════════════════════════════════════
155
+
156
+ class StealthConfig:
157
+ """Anti-detection & evasion configuration"""
158
+
159
+ def __init__(self, threat_level: ThreatLevel = ThreatLevel.MEDIUM):
160
+ self.threat_level = threat_level
161
+
162
+ self.delay_ranges = {
163
+ ThreatLevel.LOW: (100, 300),
164
+ ThreatLevel.MEDIUM: (500, 2000),
165
+ ThreatLevel.HIGH: (2000, 5000),
166
+ ThreatLevel.CRITICAL: (5000, 15000)
167
+ }
168
+
169
+ self.max_concurrent = {
170
+ ThreatLevel.LOW: 1,
171
+ ThreatLevel.MEDIUM: 2,
172
+ ThreatLevel.HIGH: 5,
173
+ ThreatLevel.CRITICAL: 10
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"""
186
+ min_d, max_d = self.delay_ranges[self.threat_level]
187
+ return random.uniform(min_d, max_d) / 1000
188
+
189
+ def get_headers(self) -> Dict[str, str]:
190
+ """Anti-fingerprinting headers"""
191
+ return {
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
204
+ # ════════════════════════════════════════════════════════════════════════════
205
+
206
+ class PassiveOSINTEngine:
207
+ """Passive reconnaissance without alerting target"""
208
+
209
+ def __init__(self, config: StealthConfig):
210
+ self.config = config
211
+ self.indicators: Dict[str, List[IntelligenceIndicator]] = defaultdict(list)
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:
219
+ """DNS records, subdomains from public sources"""
220
+ intel = {
221
+ "subdomains": [],
222
+ "mx_records": [],
223
+ "ns_records": [],
224
+ "txt_records": []
225
+ }
226
+
227
+ try:
228
+ import dns.resolver
229
+
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:
237
+ try:
238
+ full_domain = f"{sub}.{domain}"
239
+ result = dns.resolver.resolve(full_domain, 'A')
240
+ for rdata in result:
241
+ intel["subdomains"].append({
242
+ "subdomain": full_domain,
243
+ "ip": str(rdata)
244
+ })
245
+ except:
246
+ pass
247
+
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
+
255
+ # TXT records (SPF, DKIM, DMARC)
256
+ try:
257
+ txt = dns.resolver.resolve(domain, 'TXT')
258
+ intel["txt_records"] = [str(r) for r in txt]
259
+ except:
260
+ pass
261
+
262
+ except ImportError:
263
+ self.logger.warning("dnspython not installed")
264
+
265
+ return intel
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:
281
+ context = ssl.create_default_context()
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', []):
293
+ if alt_name[0] == 'DNS':
294
+ cert_intel["subjectAltNames"].append(alt_name[1])
295
+ except Exception as e:
296
+ self.logger.error(f"SSL cert grab failed: {e}")
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
+
312
+ async with aiohttp.ClientSession() as session:
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[:10]: # Limit to 10
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
+ except Exception as e:
327
+ self.logger.error(f"GitHub recon failed: {e}")
328
+
329
+ return github_intel
330
+
331
+ async def exposed_data_check(self, domain: str) -> List[Dict]:
332
+ """Check if domain in breach databases"""
333
+ breaches = []
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
+ if "endpoints" in recon_data and len(recon_data["endpoints"]) > 0:
589
+ if threat_category == "InformationDisclosure":
590
+ stride_report[threat_category]["potential_impacts"].append(
591
+ "Sensitive data exposed via API endpoints"
592
+ )
593
+
594
+ return stride_report
595
+
596
+ # ════════════════════════════════════════════════════════════════════════════
597
+ # SECTION 7: ATTACK GRAPH VISUALIZATION (ENHANCED)
598
+ # ════════════════════════════════════════════════════════════════════════════
599
+
600
+ class AttackGraphEngine:
601
+ """Advanced attack surface visualization"""
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
716
+ # ════════════════════════════════════════════════════════════════════════════
717
+
718
+ class ReportingEngine:
719
+ """Professional security assessment reporting"""
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) -> str:
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 v2.0
737
+ Classification: CONFIDENTIAL
738
+
739
+ RISK OVERVIEW
740
+ ─────────────────────────────────────────────────────────────────────────
741
+ Critical Findings: {len([t for t in threat_vectors if t.cvss_score and t.cvss_score >= 9.0])}
742
+ High Findings: {len([t for t in threat_vectors if t.cvss_score and 7.0 <= t.cvss_score < 9.0])}
743
+ Medium Findings: {len([t for t in threat_vectors if t.cvss_score and 4.0 <= t.cvss_score < 7.0])}
744
+ Low Findings: {len([t for t in threat_vectors if t.cvss_score and t.cvss_score < 4.0])}
745
+
746
+ Overall Risk Level: {"🔴 CRITICAL" if len([t for t in threat_vectors if t.cvss_score and t.cvss_score >= 9.0]) > 0 else "🟠 HIGH" if len([t for t in threat_vectors if t.cvss_score and t.cvss_score >= 7.0]) > 0 else "🟡 MEDIUM"}
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
+ Exposed Services: {len(recon_data.get('exposed_services', []))}
755
+
756
+ TECHNOLOGIES DETECTED
757
+ ─────────────────────────────────────────────────────────────────────────
758
+ {', '.join(recon_data.get('technologies', ['None detected']))}
759
+
760
+ THREAT VECTORS
761
+ ─────────────────────────────────────────────────────────────────────────
762
+ """
763
+
764
+ for i, vector in enumerate(threat_vectors[:10], 1):
765
+ report += f"""
766
+ {i}. [{vector.category.upper()}]
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"""
775
+
776
+ STRIDE THREAT MODEL
777
+ ─────────────────────────────────────────────────────────────────────────
778
+ """
779
+
780
+ for threat_type, threat_data in stride_report.items():
781
+ report += f"""
782
+ {threat_type}:
783
+ Description: {threat_data['description']}
784
+ Mitigations: {', '.join(threat_data['mitigations'])}
785
+ """
786
+
787
+ report += f"""
788
+
789
+ ATTACK PATH ANALYSIS
790
+ ─────────────────────────────────────────────────────────────────────────
791
+ """
792
+
793
+ for i, path in enumerate(attack_paths, 1):
794
+ report += f"""
795
+ 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}\n"
803
+
804
+ report += """
805
+
806
+ RECOMMENDATIONS
807
+ ─────────────────────────────────────────────────────────────────────────
808
+ 1. IMMEDIATE (Critical):
809
+ - Patch all critical CVEs
810
+ - Enable WAF rules
811
+ - Implement rate limiting
812
+ - Enable security headers (CSP, X-Frame-Options, etc.)
813
+
814
+ 2. SHORT-TERM (High):
815
+ - Update outdated technologies
816
+ - Implement input validation
817
+ - Enable HTTPS enforcement
818
+ - Setup security monitoring
819
+
820
+ 3. LONG-TERM (Medium):
821
+ - Implement secure SDLC
822
+ - Regular security training
823
+ - Penetration testing program
824
+ - Bug bounty program
825
+
826
+ METHODOLOGY
827
+ ─────────────────────────────────────────────────────────────────────────
828
+ 1. Passive OSINT: DNS records, SSL certificates, public databases
829
+ 2. Active Reconnaissance: Technology fingerprinting, endpoint discovery
830
+ 3. Threat Modeling: STRIDE analysis, attack path mapping
831
+ 4. Risk Assessment: CVSS scoring, impact analysis
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
842
+ # ════════════════════════════════════════════════════════════════════════════
843
+
844
+ class RedTeamReconFramework:
845
+ """Master orchestrator"""
846
+
847
+ def __init__(self):
848
+ self.stealth_config = StealthConfig(ThreatLevel.MEDIUM)
849
+ self.passive_engine = PassiveOSINTEngine(self.stealth_config)
850
+ self.active_engine = ActiveReconEngine(self.stealth_config)
851
+ self.threat_model = ThreatModelingEngine()
852
+ self.graph_engine = AttackGraphEngine()
853
+ self.reporting = ReportingEngine()
854
+
855
+ async def execute_assessment(self, target_url: str) -> Dict:
856
+ """Execute full security assessment"""
857
+
858
+ results = {
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": {},
869
+ "graph_data": {},
870
+ "report": ""
871
+ }
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
+
878
+ ssl_data = await self.passive_engine.gather_ssl_cert_intel(target_url)
879
+ if ssl_data.get("subjectAltNames"):
880
+ results["subdomains"].extend([
881
+ {"subdomain": san, "ip": "from_cert"}
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
+ "", "admin", "api", "login", "test", "debug", "config",
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
900
+
901
+ js_endpoints = await self.active_engine.extract_javascript_endpoints(target_url)
902
+ results["js_files"] = js_endpoints
903
+
904
+ # PHASE 3: Threat Modeling
905
+ threat_vectors = self.threat_model.analyze_web_app(results)
906
+ results["threat_vectors"] = [asdict(tv) for tv in threat_vectors]
907
+
908
+ attack_paths = self.threat_model.build_attack_paths(threat_vectors, technologies)
909
+ results["attack_paths"] = [asdict(ap) for ap in attack_paths]
910
+
911
+ stride_analysis = self.threat_model.generate_stride_report(results)
912
+ results["stride_analysis"] = stride_analysis
913
+
914
+ # PHASE 4: Attack Graph
915
+ graph_data = self.graph_engine.create_enhanced_attack_graph(threat_vectors, attack_paths)
916
+ results["graph_data"] = graph_data
917
+
918
+ # PHASE 5: Reporting
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
+
930
+ # ════════════════════════════════════════════════════════════════════════════
931
+ # SECTION 10: GRADIO INTERFACE
932
+ # ════════════════════════════════════════════════════════════════════════════
933
+
934
+ # Initialize framework
935
+ framework = RedTeamReconFramework()
936
+
937
+ def run_assessment(target_url: str, threat_level: str, progress=gr.Progress(track_tqdm=True)):
938
+ """Gradio wrapper function"""
939
+
940
+ try:
941
+ progress(0.1, desc="🔍 Validating target...")
942
+
943
+ # Update threat level
944
+ threat_map = {
945
+ "Low (Stealthy)": ThreatLevel.LOW,
946
+ "Medium (Balanced)": ThreatLevel.MEDIUM,
947
+ "High (Aggressive)": ThreatLevel.HIGH,
948
+ }
949
+ framework.stealth_config = StealthConfig(threat_map.get(threat_level, ThreatLevel.MEDIUM))
950
+
951
+ progress(0.2, desc="🕵️ Starting passive OSINT...")
952
+ progress(0.4, desc="📡 Running active reconnaissance...")
953
+ progress(0.6, desc="🎯 Analyzing threats...")
954
+ progress(0.8, desc="📊 Generating attack graph...")
955
+
956
+ # Run assessment
957
+ loop = asyncio.new_event_loop()
958
+ asyncio.set_event_loop(loop)
959
+ results = loop.run_until_complete(framework.execute_assessment(target_url))
960
+ loop.close()
961
+
962
+ progress(0.95, desc="📝 Finalizing report...")
963
+
964
+ # Create visualization
965
+ if results.get("graph_data"):
966
+ fig = framework.graph_engine.visualize_attack_graph_plotly(results["graph_data"])
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: {len(results.get('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)