ag235772 commited on
Commit
7ed1c7a
·
1 Parent(s): 30a50c0

SOME ADDITIONS

Browse files
Files changed (3) hide show
  1. app.py +15 -12
  2. modules/nuclei_engine.py +29 -27
  3. templates/index.html +12 -2
app.py CHANGED
@@ -330,22 +330,25 @@ def handle_scan(data):
330
  web_log(f"⚠️ Nuclei Warning: {str(e)}")
331
  nuclei_vulns = []
332
 
 
333
  # Combine ZAP's dynamic findings with Nuclei's CVE template findings
334
  raw_vulns = zap_vulns + nuclei_vulns
335
 
336
- # 🔴 INJECT WAF FINDING INTO THE REPORT
337
- if detected_waf and detected_waf not in ["None Detected", "Unknown"]:
338
- raw_vulns.append({
339
- 'type': f"Security Control: {detected_waf} Detected",
340
- 'severity': "INFO",
341
- 'url': target,
342
- 'payload': f"Edge Security Signatures matched for {detected_waf}",
343
- 'proof_of_concept': "N/A",
344
- 'impact': "The target is actively defended by a Web Application Firewall. This mitigates many automated attacks, blocks malicious payloads, and actively challenges bots.",
345
- 'remediation': "This is a positive security control. Ensure the WAF is configured in blocking mode with updated rulesets."
346
- })
347
-
348
  web_log("--- PHASE 3: SMART DEDUPLICATION & THREAT SCORING ---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  try:
350
  exploiter = ExploiterEngine(verified_vulns, auth_header=auth_token, logger_callback=web_log)
351
  verified_vulns = exploiter.start()
 
330
  web_log(f"⚠️ Nuclei Warning: {str(e)}")
331
  nuclei_vulns = []
332
 
333
+ # Combine ZAP's dynamic findings with Nuclei's CVE template findings
334
  # Combine ZAP's dynamic findings with Nuclei's CVE template findings
335
  raw_vulns = zap_vulns + nuclei_vulns
336
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  web_log("--- PHASE 3: SMART DEDUPLICATION & THREAT SCORING ---")
338
+ web_log("[*] Starting Smart Analysis, Deduplication & Verification...")
339
+
340
+ # 🔴 BULLETPROOF FALLBACK: Always define the variable before the try block
341
+ verified_vulns = raw_vulns
342
+
343
+ try:
344
+ # Here is where your deduplication logic happens (e.g., removing duplicates)
345
+ unique_vulns = {v['type']: v for v in raw_vulns}.values()
346
+ verified_vulns = list(unique_vulns)
347
+ web_log(f"✅ Analysis Complete: Condensed {len(raw_vulns)} alerts into {len(verified_vulns)} unique threats.")
348
+ except Exception as e:
349
+ web_log(f"⚠️ Deduplication Warning: {str(e)}. Proceeding with raw data.")
350
+
351
+ web_log("--- PHASE 3.5: ACTIVE EXPLOIT VERIFICATION ---")
352
  try:
353
  exploiter = ExploiterEngine(verified_vulns, auth_header=auth_token, logger_callback=web_log)
354
  verified_vulns = exploiter.start()
modules/nuclei_engine.py CHANGED
@@ -33,41 +33,43 @@ class NucleiEngine:
33
  # Run Nuclei (Timeout after 5 minutes to keep it fast)
34
  subprocess.run(cmd, capture_output=True, text=True, timeout=300)
35
 
 
36
  # Parse the JSON results exported by Nuclei
37
  if os.path.exists(output_file):
38
  with open(output_file, "r") as f:
39
  for line in f:
40
  try:
41
- data = json.loads(line.strip())
42
 
43
- # BULLETPROOF PARSING: If Nuclei returns a list, grab the first item
44
- if isinstance(data, list):
45
- if not data: continue
46
- data = data[0]
47
-
48
- if not isinstance(data, dict):
49
- continue
50
 
51
- info = data.get('info', {})
52
-
53
- # Extract CVE ID if it exists
54
- cve_id = ""
55
- classification = info.get('classification', {})
56
- if isinstance(classification, dict) and 'cve-id' in classification and classification['cve-id']:
57
- cve_id = f"[{classification['cve-id'][0]}] "
 
 
 
 
 
 
58
 
59
- poc_payload = data.get('curl-command', 'N/A')
60
-
61
- finding = {
62
- 'type': f"NUCLEI: {cve_id}{info.get('name', 'Unknown Vulnerability')}",
63
- 'severity': info.get('severity', 'high').upper(),
64
- 'url': data.get('matched-at', self.target_url),
65
- 'payload': data.get('extracted-results', [''])[0] if data.get('extracted-results') else data.get('matcher-name', 'Template Match'),
66
- 'proof_of_concept': poc_payload,
67
- 'impact': info.get('description', 'Exploitable CVE identified by Nuclei template engine.'),
68
- 'remediation': info.get('remediation', 'Apply the latest vendor patches immediately.')
69
- }
70
- findings.append(finding)
71
  except json.JSONDecodeError:
72
  continue
73
  os.remove(output_file) # Cleanup
 
33
  # Run Nuclei (Timeout after 5 minutes to keep it fast)
34
  subprocess.run(cmd, capture_output=True, text=True, timeout=300)
35
 
36
+ # Parse the JSON results exported by Nuclei
37
  # Parse the JSON results exported by Nuclei
38
  if os.path.exists(output_file):
39
  with open(output_file, "r") as f:
40
  for line in f:
41
  try:
42
+ parsed = json.loads(line.strip())
43
 
44
+ # Force everything into a list so we can loop safely
45
+ items = parsed if isinstance(parsed, list) else [parsed]
 
 
 
 
 
46
 
47
+ for data in items:
48
+ if not isinstance(data, dict):
49
+ continue
50
+
51
+ info = data.get('info', {})
52
+ if not isinstance(info, dict):
53
+ info = {}
54
+
55
+ # Extract CVE ID if it exists
56
+ cve_id = ""
57
+ classification = info.get('classification', {})
58
+ if isinstance(classification, dict) and 'cve-id' in classification and classification['cve-id']:
59
+ cve_id = f"[{classification['cve-id'][0]}] "
60
 
61
+ poc_payload = data.get('curl-command', 'N/A')
62
+
63
+ finding = {
64
+ 'type': f"NUCLEI: {cve_id}{info.get('name', 'Unknown Vulnerability')}",
65
+ 'severity': info.get('severity', 'high').upper(),
66
+ 'url': data.get('matched-at', self.target_url),
67
+ 'payload': data.get('extracted-results', [''])[0] if data.get('extracted-results') else data.get('matcher-name', 'Template Match'),
68
+ 'proof_of_concept': poc_payload,
69
+ 'impact': info.get('description', 'Exploitable CVE identified by Nuclei template engine.'),
70
+ 'remediation': info.get('remediation', 'Apply the latest vendor patches immediately.')
71
+ }
72
+ findings.append(finding)
73
  except json.JSONDecodeError:
74
  continue
75
  os.remove(output_file) # Cleanup
templates/index.html CHANGED
@@ -513,8 +513,18 @@
513
  mapContainer.classList.remove('hidden');
514
  rootNodeId = url;
515
  graphData = { nodes: [{ id: rootNodeId, group: 'root' }], links: [] };
516
- if (!Graph) init3DGraph();
517
- else Graph.graphData(graphData);
 
 
 
 
 
 
 
 
 
 
518
  }
519
 
520
  const status = document.getElementById('statusIndicator');
 
513
  mapContainer.classList.remove('hidden');
514
  rootNodeId = url;
515
  graphData = { nodes: [{ id: rootNodeId, group: 'root' }], links: [] };
516
+
517
+ // We must wait 100ms for the CSS 'hidden' class to disappear so WebGL knows the canvas size!
518
+ setTimeout(() => {
519
+ if (!Graph) {
520
+ init3DGraph();
521
+ } else {
522
+ // Force resize and update
523
+ Graph.width(document.getElementById('mapContainer').clientWidth);
524
+ Graph.height(350);
525
+ Graph.graphData(graphData);
526
+ }
527
+ }, 100);
528
  }
529
 
530
  const status = document.getElementById('statusIndicator');