The Analyzer v2.0 — 30 attack vectors, 9 new exploiters
New vectors added: - 22: SSRF Proof — cloud metadata exfiltration (CRITICAL) - 23: Prototype Pollution — Node.js client/server (HIGH) - 24: WebSocket Hijack — WS origin bypass + injection (HIGH) - 25: Mass Assignment — protected field modification (HIGH) - 26: HTTP Parameter Pollution — WAF bypass (HIGH) - 27: Insecure Deserialization — PHP/Java/Node (CRITICAL) - 28: OAuth Takeover — redirect_uri / state / CSRF (CRITICAL) - 29: Web Cache Poisoning — unkeyed header injection (HIGH) - 30: CRLF Injection — HTTP response splitting (CRITICAL) All vectors PROVE exploitation by dumping data/credentials, not just detecting config issues.
This commit is contained in:
280
engine/autobounty.py
Normal file
280
engine/autobounty.py
Normal file
@@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AutoBounty — Autonomous Bug Bounty Pipeline
|
||||
Discovers subdomains → tech-detect → CVE scan → The Analyzer exploit
|
||||
No API keys needed (Shodan DNS is free tier)
|
||||
"""
|
||||
import subprocess, json, sys, os, time
|
||||
from pathlib import Path
|
||||
from collections import Counter
|
||||
|
||||
ANALYZER_DIR = os.path.expanduser("~/the-analyzer")
|
||||
REPORTS_DIR = f"{ANALYZER_DIR}/reports"
|
||||
HTTPX = os.path.expanduser("~/go/bin/httpx")
|
||||
NUCLEI_TEMPLATES = os.path.expanduser("~/nuclei-templates")
|
||||
SHODAN_KEY = "8IPLCrASad9cLHqo6xwzGNxOPcldnGDG"
|
||||
|
||||
os.makedirs(f"{ANALYZER_DIR}/targets", exist_ok=True)
|
||||
|
||||
def log(msg): print(f"\033[94m[*]\033[0m {msg}")
|
||||
def ok(msg): print(f"\033[92m[✓]\033[0m {msg}")
|
||||
def bad(msg): print(f"\033[91m[✗]\033[0m {msg}")
|
||||
|
||||
def run(cmd, timeout=120):
|
||||
try:
|
||||
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
|
||||
return r.stdout, r.stderr, r.returncode
|
||||
except subprocess.TimeoutExpired:
|
||||
return "", "TIMEOUT", 124
|
||||
|
||||
def shodan_subdomains(domain):
|
||||
"""Enumerate subdomains using free Shodan DNS API"""
|
||||
log(f"Enumerating subdomains for {domain}...")
|
||||
try:
|
||||
import urllib.request, json, ssl
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
url = f"https://api.shodan.io/dns/domain/{domain}?key={SHODAN_KEY}"
|
||||
r = urllib.request.urlopen(url, context=ctx, timeout=10)
|
||||
data = json.loads(r.read().decode())
|
||||
|
||||
subdomains = data.get("subdomains", [])
|
||||
results = []
|
||||
for sd in subdomains:
|
||||
fqdn = f"{sd}.{domain}"
|
||||
# Filter out wildcard/mass-provisioned subdomains
|
||||
if not any(x in sd for x in ["clients6", "prod-dynamite", "preprod-dynamite", "client-channel"]):
|
||||
results.append(fqdn)
|
||||
|
||||
if results:
|
||||
ok(f"Found {len(results)} subdomains")
|
||||
return results
|
||||
else:
|
||||
log(f"No clean subdomains found")
|
||||
return []
|
||||
except Exception as e:
|
||||
bad(f"Shodan DNS error: {e}")
|
||||
return []
|
||||
|
||||
def probe_targets(domains, output_file):
|
||||
"""Probe targets with httpx tech detection"""
|
||||
if not domains:
|
||||
return None
|
||||
|
||||
# Write targets
|
||||
target_file = "/tmp/autobounty_targets.txt"
|
||||
with open(target_file, "w") as f:
|
||||
f.write("\n".join(domains))
|
||||
|
||||
log(f"Probing {len(domains)} targets with tech detection...")
|
||||
stdout, stderr, rc = run(
|
||||
f"cat {target_file} | {HTTPX} -rl 20 -timeout 5 -tech-detect -j -o {output_file} -silent 2>/dev/null",
|
||||
timeout=180
|
||||
)
|
||||
|
||||
count = 0
|
||||
if os.path.exists(output_file):
|
||||
with open(output_file) as f:
|
||||
count = sum(1 for _ in f)
|
||||
ok(f"{count} live hosts detected")
|
||||
return output_file
|
||||
|
||||
def run_cve_scan(targets_file, severity="all"):
|
||||
"""Run targeted CVE scan on live targets"""
|
||||
if not targets_file or not os.path.exists(targets_file):
|
||||
return None, 0
|
||||
|
||||
# Extract just URLs
|
||||
url_file = "/tmp/autobounty_urls.txt"
|
||||
run(f"python3 -c 'import json; [print(json.loads(l).get(\"url\",\"\")) for l in open(\"{targets_file}\") if l.strip()]' > {url_file}")
|
||||
|
||||
live_count = 0
|
||||
with open(url_file) as f:
|
||||
live_count = sum(1 for _ in f)
|
||||
|
||||
if live_count == 0:
|
||||
return None, 0
|
||||
|
||||
log(f"Running CVE scan on {live_count} live hosts...")
|
||||
|
||||
findings_file = f"{REPORTS_DIR}/autobounty_cve_{int(time.time())}.json"
|
||||
|
||||
if severity == "all":
|
||||
stdout, stderr, rc = run(
|
||||
f"nuclei -l {url_file} -j -rl 15 -c 8 "
|
||||
f"-t {NUCLEI_TEMPLATES}/http/cves/ "
|
||||
f"-severity critical,high,medium "
|
||||
f"-o {findings_file} "
|
||||
f"-silent 2>/dev/null",
|
||||
timeout=180
|
||||
)
|
||||
else:
|
||||
stdout, stderr, rc = run(
|
||||
f"nuclei -l {url_file} -j -rl 15 -c 8 "
|
||||
f"-t {NUCLEI_TEMPLATES}/http/cves/ "
|
||||
f"-severity critical,high "
|
||||
f"-o {findings_file} "
|
||||
f"-silent 2>/dev/null",
|
||||
timeout=120
|
||||
)
|
||||
|
||||
count = 0
|
||||
if os.path.exists(findings_file):
|
||||
with open(findings_file) as f:
|
||||
count = sum(1 for l in f if l.strip())
|
||||
|
||||
return findings_file, count
|
||||
|
||||
def print_tech_summary(tech_file):
|
||||
"""Print technology summary"""
|
||||
techs = Counter()
|
||||
with open(tech_file) as f:
|
||||
for line in f:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
url = d.get("url", "")
|
||||
for t in d.get("tech", []):
|
||||
techs[t] += 1
|
||||
print(f" {url:60} {', '.join(d.get('tech', ['-']))}")
|
||||
except: pass
|
||||
|
||||
if techs:
|
||||
print(f"\n Technology breakdown:")
|
||||
for tech, cnt in techs.most_common(10):
|
||||
print(f" {tech:35} {cnt} targets")
|
||||
|
||||
def print_findings(findings_file):
|
||||
"""Print CVE findings in readable format"""
|
||||
if not findings_file or not os.path.exists(findings_file):
|
||||
return
|
||||
|
||||
findings = []
|
||||
with open(findings_file) as f:
|
||||
for line in f:
|
||||
if not line.strip(): continue
|
||||
try:
|
||||
d = json.loads(line)
|
||||
cve = "N/A"
|
||||
for ref in d.get("info", {}).get("classification", {}).get("cve", []):
|
||||
cve = ref.get("id", "N/A")
|
||||
break
|
||||
findings.append({
|
||||
"url": d.get("matched-at", "?"),
|
||||
"cve": cve,
|
||||
"severity": d.get("info", {}).get("severity", "?"),
|
||||
"name": d.get("info", {}).get("name", "?"),
|
||||
"template": d.get("template-id", ""),
|
||||
})
|
||||
except: pass
|
||||
|
||||
if findings:
|
||||
icons = {"critical": "🔴", "high": "🟠", "medium": "🟡"}
|
||||
print(f"\n CVEs found:")
|
||||
for f_data in findings:
|
||||
icon = icons.get(f_data["severity"], "⚪")
|
||||
print(f" {icon} {f_data['cve']:20} {f_data['name'][:60]}")
|
||||
print(f" {f_data['url']}")
|
||||
|
||||
# ============================================================
|
||||
# MAIN — Hunt a specific target domain
|
||||
# ============================================================
|
||||
|
||||
def hunt_target(domain):
|
||||
"""Full pipeline for a single target domain"""
|
||||
print()
|
||||
print(f"╔═══════════════════════════════════════════╗")
|
||||
print(f"║ AUTOBOUNTY — {domain:40}║")
|
||||
print(f"╚═══════════════════════════════════════════╝")
|
||||
print()
|
||||
|
||||
# Phase 1: Subdomain enumeration
|
||||
log("Phase 1: Subdomain enumeration")
|
||||
subdomains = shodan_subdomains(domain)
|
||||
|
||||
all_targets = [domain] + (subdomains if subdomains else [])
|
||||
|
||||
if not all_targets:
|
||||
bad("No targets to scan")
|
||||
return
|
||||
|
||||
ok(f"Total targets: {len(all_targets)}")
|
||||
|
||||
# Phase 2: Tech detection
|
||||
print()
|
||||
log("Phase 2: Tech detection")
|
||||
tech_file = f"/tmp/autobounty_tech_{domain.replace('.', '_')}.json"
|
||||
tech_file = probe_targets(all_targets, tech_file)
|
||||
|
||||
if not tech_file:
|
||||
bad("No live hosts found")
|
||||
return
|
||||
|
||||
print()
|
||||
print_tech_summary(tech_file)
|
||||
|
||||
# Phase 3: CVE scan
|
||||
print()
|
||||
log("Phase 3: CVE scanning")
|
||||
findings_file, count = run_cve_scan(tech_file)
|
||||
|
||||
print()
|
||||
if count > 0:
|
||||
ok(f"Found {count} CVEs!")
|
||||
print_findings(findings_file)
|
||||
else:
|
||||
log("No CVEs detected on these subdomains")
|
||||
|
||||
# Phase 4: The Analyzer exploit
|
||||
if count > 0 and findings_file:
|
||||
print()
|
||||
log("Phase 4: Ready for deep exploitation")
|
||||
log("Run: ./analyzer <vulnerable-url> deep")
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(f" Target: {domain}")
|
||||
print(f" Subdomains: {len(subdomains) if subdomains else 0}")
|
||||
print(f" Live: {sum(1 for _ in open(tech_file)) if os.path.exists(tech_file) else 0}")
|
||||
print(f" CVEs: {count}")
|
||||
print("=" * 60)
|
||||
|
||||
# ============================================================
|
||||
# CONTINUOUS SCAN (cron-ready)
|
||||
# ============================================================
|
||||
|
||||
def scan_known_targets():
|
||||
"""Scan all known bug bounty targets for new subdomains"""
|
||||
targets = [
|
||||
"google.com", "facebook.com", "twitter.com", "instagram.com",
|
||||
"github.com", "gitlab.com", "atlassian.com", "slack.com",
|
||||
"shopify.com", "stripe.com", "paypal.com", "discord.com",
|
||||
"reddit.com", "twitch.com", "spotify.com", "cloudflare.com",
|
||||
"digitalocean.com", "magento.com", "salesforce.com", "hubspot.com",
|
||||
]
|
||||
|
||||
for target in targets:
|
||||
print(f"\n{'='*60}")
|
||||
hunt_target(target)
|
||||
|
||||
def print_usage():
|
||||
print("Usage:")
|
||||
print(" python3 autobounty.py <domain> # Hunt a specific target")
|
||||
print(" python3 autobounty.py all # Scan all known targets")
|
||||
print(" python3 autobounty.py watch <domain> # Setup daily cron scan")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
mode = sys.argv[1]
|
||||
|
||||
if mode == "all":
|
||||
scan_known_targets()
|
||||
elif mode == "watch" and len(sys.argv) >= 3:
|
||||
domain = sys.argv[2]
|
||||
print(f"Would setup cron for daily scan of {domain}")
|
||||
hunt_target(domain)
|
||||
else:
|
||||
hunt_target(mode)
|
||||
561
engine/hunter.py
Normal file
561
engine/hunter.py
Normal file
@@ -0,0 +1,561 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
No-API Vulnerability Hunter
|
||||
Discovers vulnerable websites using only free/open data sources
|
||||
Pipeline: Target Discovery → Tech Detection → CVE Scanning → Exploitation
|
||||
"""
|
||||
import subprocess, json, sys, os, time
|
||||
from pathlib import Path
|
||||
from collections import Counter
|
||||
from urllib.parse import urlparse
|
||||
|
||||
ANALYZER_DIR = os.path.expanduser("~/the-analyzer")
|
||||
REPORTS_DIR = f"{ANALYZER_DIR}/reports"
|
||||
TARGETS_DIR = f"{ANALYZER_DIR}/targets"
|
||||
WORK_DIR = "/tmp/analyzer-hunter"
|
||||
HTTPX = os.path.expanduser("~/go/bin/httpx")
|
||||
NUCLEI_TEMPLATES = os.path.expanduser("~/nuclei-templates")
|
||||
|
||||
os.makedirs(WORK_DIR, exist_ok=True)
|
||||
os.makedirs(REPORTS_DIR, exist_ok=True)
|
||||
os.makedirs(TARGETS_DIR, exist_ok=True)
|
||||
|
||||
def log(msg): print(f"\033[94m[*]\033[0m {msg}")
|
||||
def ok(msg): print(f"\033[92m[✓]\033[0m {msg}")
|
||||
def warn(msg): print(f"\033[93m[!]\033[0m {msg}")
|
||||
def bad(msg): print(f"\033[91m[✗]\033[0m {msg}")
|
||||
|
||||
def run(cmd, timeout=120):
|
||||
"""Run a shell command and return output"""
|
||||
try:
|
||||
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
|
||||
return r.stdout, r.stderr, r.returncode
|
||||
except subprocess.TimeoutExpired:
|
||||
return "", "TIMEOUT", 124
|
||||
|
||||
# ============================================================
|
||||
# PHASE 1: TARGET DISCOVERY
|
||||
# ============================================================
|
||||
|
||||
def discover_tranco_deep(count=2000, offset=50000):
|
||||
"""Get mid-tier sites from Tranco (50K-52K range)"""
|
||||
log(f"Fetching Tranco sites (offset={offset}, count={count})...")
|
||||
|
||||
# Download if not cached
|
||||
csv_file = f"{WORK_DIR}/top-1m.csv"
|
||||
if not os.path.exists(csv_file):
|
||||
out, _, _ = run("curl -skL https://tranco-list.eu/top-1m.csv.zip -o /tmp/t1m.zip && unzip -o /tmp/t1m.zip -d /tmp/tranco/ 2>/dev/null && echo OK", timeout=30)
|
||||
if "OK" in out:
|
||||
os.system("cp /tmp/tranco/top-1m.csv " + csv_file)
|
||||
|
||||
if os.path.exists(csv_file):
|
||||
targets = []
|
||||
with open(csv_file) as f:
|
||||
for i, line in enumerate(f):
|
||||
if i < offset: continue
|
||||
if i >= offset + count: break
|
||||
parts = line.strip().split(",")
|
||||
if len(parts) >= 2:
|
||||
targets.append(parts[1].strip())
|
||||
|
||||
outfile = f"{WORK_DIR}/tranco_deep_targets.txt"
|
||||
with open(outfile, "w") as f:
|
||||
f.write("\n".join(targets))
|
||||
ok(f"{len(targets)} targets from Tranco (offset {offset})")
|
||||
return outfile
|
||||
|
||||
def discover_bug_bounty_targets():
|
||||
"""Add known bug bounty targets for subdomain recon"""
|
||||
targets = [
|
||||
# High-value targets that often have bug bounty programs
|
||||
"hackerone.com", "bugcrowd.com", "intigriti.com",
|
||||
"yeswehack.com", "synack.com", "cobalt.io",
|
||||
# Major platforms with bounty programs
|
||||
"facebook.com", "twitter.com", "instagram.com", "linkedin.com",
|
||||
"github.com", "gitlab.com", "atlassian.com", "slack.com",
|
||||
"shopify.com", "stripe.com", "square.com", "paypal.com",
|
||||
"discord.com", "reddit.com", "twitch.com", "spotify.com",
|
||||
"cloudflare.com", "digitalocean.com", "heroku.com",
|
||||
# E-commerce (user's niche)
|
||||
"magento.com", "shopware.com", "woocommerce.com",
|
||||
"bigcommerce.com", "salesforce.com", "hubspot.com",
|
||||
# Google
|
||||
"google.com", "youtube.com", "gmail.com", "android.com",
|
||||
# Microsoft
|
||||
"microsoft.com", "office.com", "azure.com", "live.com",
|
||||
# Apple
|
||||
"apple.com", "icloud.com",
|
||||
]
|
||||
|
||||
# Also add targets from the Analyzer's list
|
||||
analyzer_targets = f"{TARGETS_DIR}/top50.txt"
|
||||
if os.path.exists(analyzer_targets):
|
||||
with open(analyzer_targets) as f:
|
||||
targets.extend([l.strip() for l in f if l.strip()])
|
||||
|
||||
outfile = f"{WORK_DIR}/bb_targets.txt"
|
||||
with open(outfile, "w") as f:
|
||||
f.write("\n".join(sorted(set(targets))))
|
||||
|
||||
return outfile
|
||||
|
||||
def discover_commoncrawl_vuln_patterns():
|
||||
"""Search CommonCrawl for URLs matching vulnerable software patterns"""
|
||||
log("Searching CommonCrawl for vulnerable software patterns...")
|
||||
|
||||
CC_INDEX = "CC-MAIN-2026-21"
|
||||
BASE = f"http://index.commoncrawl.org/{CC_INDEX}-index"
|
||||
|
||||
patterns = [
|
||||
("phpMyAdmin", "phpmyadmin"),
|
||||
("WordPress admin", "wp-admin"),
|
||||
("WordPress plugins", "wp-content/plugins"),
|
||||
("Jenkins", "jenkins"),
|
||||
("phpinfo()", "phpinfo.php"),
|
||||
("Server status", "server-status"),
|
||||
(".env files", ".env"),
|
||||
("Actuator/Spring", "actuator"),
|
||||
("Git exposure", ".git/config"),
|
||||
("Laravel debug", "laravel/debug"),
|
||||
]
|
||||
|
||||
targets = set()
|
||||
for name, pattern in patterns:
|
||||
try:
|
||||
import urllib.request, urllib.parse, json
|
||||
url = f"{BASE}?url=*.{pattern}/*&output=json&limit=20"
|
||||
r = urllib.request.urlopen(url, timeout=10)
|
||||
data = r.read().decode()
|
||||
|
||||
for line in data.strip().split("\n"):
|
||||
if not line.strip(): continue
|
||||
try:
|
||||
d = json.loads(line)
|
||||
u = d.get("url", "")
|
||||
if u:
|
||||
parsed = urlparse(u)
|
||||
domain = parsed.netloc or parsed.path.split("/")[0]
|
||||
targets.add(domain)
|
||||
except: pass
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if targets:
|
||||
outfile = f"{WORK_DIR}/commoncrawl_targets.txt"
|
||||
with open(outfile, "w") as f:
|
||||
f.write("\n".join(sorted(targets)))
|
||||
ok(f"{len(targets)} targets from CommonCrawl patterns")
|
||||
return outfile
|
||||
else:
|
||||
warn("CommonCrawl returned no targets (API limiting)")
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# PHASE 2: SUBDOMAIN ENUMERATION
|
||||
# ============================================================
|
||||
|
||||
def enumerate_subdomains_shodan(domain):
|
||||
"""Use free Shodan DNS API for subdomain discovery"""
|
||||
try:
|
||||
import urllib.request, json
|
||||
key = "8IPLCrASad9cLHqo6xwzGNxOPcldnGDG"
|
||||
url = f"https://api.shodan.io/dns/domain/{domain}?key={key}"
|
||||
r = urllib.request.urlopen(url, timeout=10)
|
||||
data = json.loads(r.read().decode())
|
||||
|
||||
subdomains = data.get("subdomains", [])
|
||||
full_domains = [f"{sd}.{domain}" for sd in subdomains]
|
||||
|
||||
if full_domains:
|
||||
ok(f"Found {len(full_domains)} subdomains for {domain}")
|
||||
return full_domains
|
||||
return []
|
||||
except Exception as e:
|
||||
warn(f"Shodan DNS for {domain}: {e}")
|
||||
return []
|
||||
|
||||
# ============================================================
|
||||
# PHASE 3: TECH DETECTION
|
||||
# ============================================================
|
||||
|
||||
def tech_detect(targets_file, output_file=None):
|
||||
"""Run httpx tech detection on targets"""
|
||||
log(f"Tech detection on targets from {targets_file}...")
|
||||
|
||||
if not output_file:
|
||||
output_file = f"{WORK_DIR}/tech_detected.json"
|
||||
|
||||
stdout, stderr, rc = run(
|
||||
f"cat {targets_file} | {HTTPX} -rl 30 -timeout 5 -tech-detect -j -o {output_file} -silent 2>/dev/null",
|
||||
timeout=180
|
||||
)
|
||||
|
||||
count = 0
|
||||
if os.path.exists(output_file):
|
||||
with open(output_file) as f:
|
||||
count = sum(1 for _ in f)
|
||||
|
||||
return output_file, count
|
||||
|
||||
def tech_summary(tech_file):
|
||||
"""Summarize detected technologies"""
|
||||
techs = Counter()
|
||||
targets = []
|
||||
|
||||
with open(tech_file) as f:
|
||||
for line in f:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
url = d.get("url", "?")
|
||||
targets.append(url)
|
||||
for t in d.get("tech", []):
|
||||
techs[t] += 1
|
||||
except: pass
|
||||
|
||||
return targets, techs
|
||||
|
||||
# ============================================================
|
||||
# PHASE 4: TARGETED CVE SCANNING
|
||||
# ============================================================
|
||||
|
||||
def scan_with_nuclei(targets_file, severity="critical,high", output_file=None):
|
||||
"""Run nuclei CVE scan on targets"""
|
||||
log(f"Nuclei CVE scan (severity: {severity})...")
|
||||
|
||||
if not output_file:
|
||||
output_file = f"{REPORTS_DIR}/hunt_scan_{int(time.time())}.json"
|
||||
|
||||
stdout, stderr, rc = run(
|
||||
f"nuclei -l {targets_file} -j -rl 15 -c 8 "
|
||||
f"-t {NUCLEI_TEMPLATES}/http/cves/ "
|
||||
f"-severity {severity} "
|
||||
f"-o {output_file} "
|
||||
f"-silent 2>/dev/null",
|
||||
timeout=300
|
||||
)
|
||||
|
||||
count = 0
|
||||
if os.path.exists(output_file):
|
||||
with open(output_file) as f:
|
||||
count = sum(1 for _ in f)
|
||||
|
||||
return output_file, count
|
||||
|
||||
def tech_targeted_scan(tech_file):
|
||||
"""Run technology-specific CVE scans based on detected tech"""
|
||||
log("Running tech-targeted CVE scans...")
|
||||
|
||||
# Read tech data
|
||||
tech_targets = {}
|
||||
with open(tech_file) as f:
|
||||
for line in f:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
url = d.get("url", "")
|
||||
for t in d.get("tech", []):
|
||||
tech_targets.setdefault(t, []).append(url)
|
||||
except: pass
|
||||
|
||||
# Map tech to relevant CVE template tags
|
||||
tech_cve_map = {
|
||||
"WordPress": ["wordpress", "cves"],
|
||||
"Apache HTTP Server": ["apache", "cves"],
|
||||
"Nginx": ["nginx", "cves"],
|
||||
"PHP": ["php", "cves"],
|
||||
"Jenkins": ["jenkins", "cves"],
|
||||
"jQuery": [],
|
||||
"Bootstrap": [],
|
||||
"MySQL": ["mysql", "cves"],
|
||||
"OpenSSL": ["openssl", "cves"],
|
||||
"OpenSSH": ["openssh", "cves"],
|
||||
"phpMyAdmin": ["phpmyadmin", "cves"],
|
||||
"Tomcat": ["tomcat", "cves"],
|
||||
"Drupal": ["drupal", "cves"],
|
||||
"Joomla": ["joomla", "cves"],
|
||||
"GitLab": ["gitlab", "cves"],
|
||||
"Jenkins": ["jenkins", "cves"],
|
||||
}
|
||||
|
||||
all_findings = []
|
||||
|
||||
for tech, urls in tech_targets.items():
|
||||
# Check if this tech has known CVE templates
|
||||
matched_tech = None
|
||||
for known_tech, tags in tech_cve_map.items():
|
||||
if known_tech.lower() in tech.lower() or tech.lower() in known_tech.lower():
|
||||
matched_tech = known_tech
|
||||
break
|
||||
|
||||
if not matched_tech:
|
||||
continue
|
||||
|
||||
# Write targets for this tech
|
||||
tech_file = f"{WORK_DIR}/tech_{tech.lower().replace(' ', '_')}.txt"
|
||||
with open(tech_file, "w") as f:
|
||||
f.write("\n".join(urls[:20]))
|
||||
|
||||
# Run focused scan
|
||||
tech_output = f"{WORK_DIR}/scan_{tech.lower().replace(' ', '_')}.json"
|
||||
stdout, stderr, rc = run(
|
||||
f"nuclei -l {tech_file} -j -rl 10 -c 5 "
|
||||
f"-t {NUCLEI_TEMPLATES}/http/cves/ "
|
||||
f"-severity critical,high,medium "
|
||||
f"-o {tech_output} -silent 2>/dev/null",
|
||||
timeout=120
|
||||
)
|
||||
|
||||
if os.path.exists(tech_output):
|
||||
with open(tech_output) as f:
|
||||
findings = [l for l in f if l.strip()]
|
||||
if findings:
|
||||
all_findings.extend(findings)
|
||||
ok(f"{tech}: {len(findings)} findings")
|
||||
|
||||
# Merge all findings
|
||||
merged_file = f"{REPORTS_DIR}/tech_targeted_{int(time.time())}.json"
|
||||
with open(merged_file, "w") as f:
|
||||
f.write("\n".join(all_findings))
|
||||
|
||||
return merged_file, len(all_findings)
|
||||
|
||||
# ============================================================
|
||||
# PHASE 5: REPORT
|
||||
# ============================================================
|
||||
|
||||
def generate_report(findings_file, tech_summary_data, targets_count):
|
||||
"""Generate a comprehensive report"""
|
||||
report_file = f"{REPORTS_DIR}/hunter_report_{int(time.time())}.md"
|
||||
|
||||
findings = []
|
||||
cves = Counter()
|
||||
severities = Counter()
|
||||
target_urls = set()
|
||||
|
||||
if os.path.exists(findings_file):
|
||||
with open(findings_file) as f:
|
||||
for line in f:
|
||||
if not line.strip(): continue
|
||||
try:
|
||||
d = json.loads(line)
|
||||
sev = d.get("info", {}).get("severity", "unknown")
|
||||
severities[sev] += 1
|
||||
|
||||
# Extract CVE
|
||||
cve_list = []
|
||||
for ref in d.get("info", {}).get("classification", {}).get("cve", []):
|
||||
cve_list.append(ref.get("id", ""))
|
||||
cve_id = cve_list[0] if cve_list else "N/A"
|
||||
for c in cve_list:
|
||||
cves[c] += 1
|
||||
|
||||
findings.append({
|
||||
"url": d.get("matched-at", d.get("host", "?")),
|
||||
"cve": cve_id,
|
||||
"severity": sev,
|
||||
"name": d.get("info", {}).get("name", "?"),
|
||||
"extracted": d.get("extracted-results", []),
|
||||
})
|
||||
target_urls.add(d.get("matched-at", d.get("host", "?")))
|
||||
except: pass
|
||||
|
||||
# Build report
|
||||
icons = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🔵", "unknown": "⚪"}
|
||||
|
||||
lines = []
|
||||
lines.append(f"# Mass Vulnerability Hunter Report")
|
||||
lines.append(f"Generated: {time.strftime('%Y-%m-%d %H:%M')}")
|
||||
lines.append(f"")
|
||||
lines.append(f"## Summary")
|
||||
lines.append(f"| Metric | Value |")
|
||||
lines.append(f"|--------|-------|")
|
||||
lines.append(f"| Targets Probed | {targets_count} |")
|
||||
if tech_summary_data:
|
||||
_, techs = tech_summary_data
|
||||
lines.append(f"| Live Hosts | {len(tech_summary_data[0])} |")
|
||||
lines.append(f"| Technologies Detected | {len(techs)} |")
|
||||
lines.append(f"| Total Findings | {len(findings)} |")
|
||||
lines.append(f"| Unique Vulnerable Hosts | {len(target_urls)} |")
|
||||
|
||||
for sev in ["critical", "high", "medium", "low"]:
|
||||
if severities[sev]:
|
||||
lines.append(f"| {icons.get(sev, '?')} {sev.capitalize()} | {severities[sev]} |")
|
||||
|
||||
if cves:
|
||||
lines.append(f"")
|
||||
lines.append(f"## CVEs Detected")
|
||||
for cve, cnt in cves.most_common(30):
|
||||
lines.append(f"- [{cve}](https://nvd.nist.gov/vuln/detail/{cve}): {cnt} occurrences")
|
||||
|
||||
if findings:
|
||||
lines.append(f"")
|
||||
lines.append(f"## All Findings")
|
||||
for f_data in findings:
|
||||
icon = icons.get(f_data["severity"], "?")
|
||||
lines.append(f"- {icon} [{f_data['cve']}] {f_data['name']} @ {f_data['url']}")
|
||||
if f_data["extracted"]:
|
||||
for ex in f_data["extracted"][:3]:
|
||||
lines.append(f" - `{ex}`")
|
||||
|
||||
if tech_summary_data:
|
||||
_, techs = tech_summary_data
|
||||
if techs:
|
||||
lines.append(f"")
|
||||
lines.append(f"## Detected Technologies")
|
||||
for tech, cnt in techs.most_common(20):
|
||||
lines.append(f"- {tech}: {cnt} targets")
|
||||
|
||||
with open(report_file, "w") as f:
|
||||
f.write("\n".join(lines))
|
||||
|
||||
return report_file, findings
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
mode = sys.argv[1] if len(sys.argv) > 1 else "auto"
|
||||
|
||||
print()
|
||||
print("╔═══════════════════════════════════════════╗")
|
||||
print("║ NO-API VULNERABILITY HUNTER ║")
|
||||
print("╚═══════════════════════════════════════════╝")
|
||||
print()
|
||||
|
||||
merged_targets = f"{WORK_DIR}/merged_targets.txt"
|
||||
|
||||
if mode == "target" and len(sys.argv) >= 3:
|
||||
# Hunt a specific target domain
|
||||
domain = sys.argv[2]
|
||||
log(f"Hunting target domain: {domain}")
|
||||
|
||||
# Phase 1: Subdomain enumeration
|
||||
log("[1/4] Subdomain enumeration...")
|
||||
subdomains = enumerate_subdomains_shodan(domain)
|
||||
|
||||
if subdomains:
|
||||
ok(f"Discovered {len(subdomains)} subdomains for {domain}")
|
||||
with open(merged_targets, "w") as f:
|
||||
f.write("\n".join(subdomains))
|
||||
else:
|
||||
warn(f"No subdomains found via Shodan. Using root domain.")
|
||||
with open(merged_targets, "w") as f:
|
||||
f.write(domain)
|
||||
|
||||
elif mode == "deep":
|
||||
# Deep scan - target mid-tier Tranco sites
|
||||
log("[1/4] Target discovery (Tranco deep)...")
|
||||
targets_file = discover_tranco_deep(count=2000, offset=50000)
|
||||
if not targets_file:
|
||||
bad("Failed to get target list")
|
||||
return
|
||||
|
||||
# Also try CommonCrawl
|
||||
cc_file = discover_commoncrawl_vuln_patterns()
|
||||
|
||||
# Merge targets
|
||||
all_targets = []
|
||||
with open(targets_file) as f:
|
||||
all_targets.extend([l.strip() for l in f if l.strip()])
|
||||
|
||||
if cc_file and os.path.exists(cc_file):
|
||||
with open(cc_file) as f:
|
||||
all_targets.extend([l.strip() for l in f if l.strip()])
|
||||
|
||||
with open(merged_targets, "w") as f:
|
||||
f.write("\n".join(sorted(set(all_targets))))
|
||||
|
||||
ok(f"{len(set(all_targets))} unique targets")
|
||||
|
||||
else:
|
||||
# Auto mode - balanced approach
|
||||
log("[1/4] Target discovery...")
|
||||
|
||||
# Get targets from multiple sources
|
||||
tranco_file = discover_tranco_deep(count=500, offset=50000)
|
||||
|
||||
# Merge
|
||||
all_targets = []
|
||||
if tranco_file and os.path.exists(tranco_file):
|
||||
with open(tranco_file) as f:
|
||||
all_targets.extend([l.strip() for l in f if l.strip()])
|
||||
|
||||
with open(merged_targets, "w") as f:
|
||||
f.write("\n".join(sorted(set(all_targets))))
|
||||
|
||||
ok(f"{len(set(all_targets))} unique targets")
|
||||
|
||||
# Phase 2: Tech Detection
|
||||
targets_count = 0
|
||||
if os.path.exists(merged_targets):
|
||||
with open(merged_targets) as f:
|
||||
targets_count = sum(1 for _ in f)
|
||||
|
||||
if targets_count == 0:
|
||||
bad("No targets to scan")
|
||||
return
|
||||
|
||||
print()
|
||||
log(f"[2/4] Tech detection on {targets_count} targets...")
|
||||
tech_file, live_count = tech_detect(merged_targets)
|
||||
|
||||
if live_count == 0:
|
||||
warn(f"No live hosts found. Try different target range.")
|
||||
return
|
||||
|
||||
ok(f"{live_count} live hosts detected")
|
||||
|
||||
# Show tech summary
|
||||
targets, techs = tech_summary(tech_file)
|
||||
print(f"\nTop technologies:")
|
||||
for tech, cnt in techs.most_common(15):
|
||||
print(f" {tech:35} {cnt} targets")
|
||||
|
||||
# Phase 3: CVE Scanning
|
||||
print()
|
||||
log("[3/4] CVE scanning...")
|
||||
|
||||
# Run mass CVE scan (critical/high)
|
||||
mass_output, mass_count = scan_with_nuclei(merged_targets, "critical,high")
|
||||
ok(f"Mass CVE scan: {mass_count} findings")
|
||||
|
||||
# Run tech-targeted scans (medium too, since we know the tech)
|
||||
tech_output, tech_count = tech_targeted_scan(tech_file)
|
||||
ok(f"Tech-targeted scan: {tech_count} findings")
|
||||
|
||||
# Merge findings
|
||||
merged_findings = f"{REPORTS_DIR}/hunt_all_findings.json"
|
||||
all_findings = []
|
||||
for f in [mass_output, tech_output]:
|
||||
if os.path.exists(f):
|
||||
with open(f) as fh:
|
||||
all_findings.extend([l for l in fh if l.strip()])
|
||||
|
||||
with open(merged_findings, "w") as f:
|
||||
f.write("\n".join(all_findings))
|
||||
|
||||
# Phase 4: Report
|
||||
print()
|
||||
log("[4/4] Generating report...")
|
||||
report_file, findings = generate_report(merged_findings, (targets, techs), targets_count)
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(f" ✅ HUNT COMPLETE")
|
||||
print(f" Targets scanned: {targets_count}")
|
||||
print(f" Live hosts: {live_count}")
|
||||
print(f" Total findings: {len(findings)}")
|
||||
print(f" Report: {report_file}")
|
||||
print("=" * 60)
|
||||
|
||||
# Output findings summary
|
||||
if findings:
|
||||
print("\nTop CVEs found:")
|
||||
cves = Counter(f["cve"] for f in findings)
|
||||
for cve, cnt in cves.most_common(10):
|
||||
print(f" {cve}: {cnt} occurrences")
|
||||
|
||||
return report_file
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
317
engine/hunter.sh
Executable file
317
engine/hunter.sh
Executable file
@@ -0,0 +1,317 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# HUNTER — Mass Vulnerability Discovery Engine
|
||||
# Part of The Analyzer
|
||||
# Finds vulnerable websites at scale using OSINT + nuclei
|
||||
# ============================================================
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ANALYZER_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
REPORTS_DIR="$ANALYZER_DIR/reports"
|
||||
TARGETS_DIR="$ANALYZER_DIR/targets"
|
||||
WORK_DIR="/tmp/analyzer-hunter"
|
||||
NUCLEI_TEMPLATES="${NUCLEI_TEMPLATES:-$HOME/nuclei-templates}"
|
||||
HTTPS="$HOME/go/bin/httpx"
|
||||
|
||||
mkdir -p "$WORK_DIR" "$REPORTS_DIR" "$TARGETS_DIR"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'; NC='\033[0m'
|
||||
|
||||
log() { echo -e "${BLUE}[*]${NC} $1"; }
|
||||
ok() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||||
warn(){ echo -e "${YELLOW}[!]${NC} $1"; }
|
||||
err() { echo -e "${RED}[✗]${NC} $1"; }
|
||||
|
||||
# ============================================================
|
||||
# PHASE 1: TARGET DISCOVERY
|
||||
# ============================================================
|
||||
|
||||
discover_from_tranco() {
|
||||
local count="${1:-500}"
|
||||
local output="$TARGETS_DIR/hunt_tranco.txt"
|
||||
|
||||
log "Fetching top $count sites from Tranco..."
|
||||
curl -skL "https://tranco-list.eu/top-1m.csv.zip" -o "$WORK_DIR/top1m.zip" 2>/dev/null
|
||||
|
||||
if unzip -o "$WORK_DIR/top1m.zip" -d "$WORK_DIR" 2>/dev/null; then
|
||||
head -"$count" "$WORK_DIR"/top-1m.csv 2>/dev/null | cut -d, -f2 > "$output"
|
||||
ok "$(wc -l < "$output") domains from Tranco"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
discover_from_analyzer() {
|
||||
local output="$TARGETS_DIR/hunt_analyzer.txt"
|
||||
if [ -f "$TARGETS_DIR/top50.txt" ]; then
|
||||
cp "$TARGETS_DIR/top50.txt" "$output"
|
||||
ok "$(wc -l < "$output") from Analyzer target list"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
discover_vulnerable_software() {
|
||||
local output="$WORK_DIR/vuln_software_targets.txt"
|
||||
log "Building vulnerable software target list..."
|
||||
|
||||
# Sites running known-vulnerable software
|
||||
cat > "$WORK_DIR/vuln_sites.txt" << 'VULNSITES'
|
||||
# Known software vendors/instances that may have vulnerable versions
|
||||
wordpress.org
|
||||
joomla.org
|
||||
drupal.org
|
||||
magento.com
|
||||
prestashop.com
|
||||
opencart.com
|
||||
phpmyadmin.net
|
||||
roundcube.net
|
||||
cpanel.net
|
||||
php.net
|
||||
apache.org
|
||||
nginx.org
|
||||
mysql.com
|
||||
postgresql.org
|
||||
mongodb.com
|
||||
nodejs.org
|
||||
laravel.com
|
||||
symfony.com
|
||||
rails.org
|
||||
docker.com
|
||||
kubernetes.io
|
||||
jenkins.io
|
||||
gitlab.com
|
||||
sonarqube.org
|
||||
grafana.com
|
||||
prometheus.io
|
||||
elastic.co
|
||||
redis.io
|
||||
tomcat.apache.org
|
||||
jira.atlassian.com
|
||||
confluence.atlassian.com
|
||||
vbforum.com
|
||||
simplemachines.org
|
||||
phpbb.com
|
||||
mediawiki.org
|
||||
VULNSITES
|
||||
|
||||
# Also add common CMS plugin repositories
|
||||
echo "woocommerce.com" >> "$WORK_DIR/vuln_sites.txt"
|
||||
echo "easy-digital-downloads.com" >> "$WORK_DIR/vuln_sites.txt"
|
||||
|
||||
httpx -l "$WORK_DIR/vuln_sites.txt" -rl 20 -silent -timeout 5 \
|
||||
-o "$output" 2>/dev/null
|
||||
|
||||
if [ -s "$output" ]; then
|
||||
ok "$(wc -l < "$output") live software targets"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# PHASE 2: TECH DETECTION & TARGETED CVE SCANNING
|
||||
# ============================================================
|
||||
|
||||
detect_technologies() {
|
||||
local targets_file="$1"
|
||||
local output="$WORK_DIR/tech_detected.json"
|
||||
|
||||
log "Detecting technologies on $(wc -l < "$targets_file") targets..."
|
||||
httpx -l "$targets_file" -tech-detect -j -rl 20 -silent -timeout 5 \
|
||||
-o "$output" 2>/dev/null
|
||||
|
||||
local count=$(wc -l < "$output" 2>/dev/null || echo 0)
|
||||
ok "Tech detected on $count hosts"
|
||||
|
||||
# Summary
|
||||
python3 -c "
|
||||
import json, sys
|
||||
from collections import Counter
|
||||
techs = Counter()
|
||||
with open('$output') as f:
|
||||
for line in f:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
for t in d.get('tech', []):
|
||||
techs[t] += 1
|
||||
except: pass
|
||||
print('Top technologies detected:')
|
||||
for tech, cnt in techs.most_common(20):
|
||||
print(f' {tech}: {cnt}')
|
||||
" 2>/dev/null
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
run_focused_cve_scan() {
|
||||
local targets_file="$1"
|
||||
local tech_file="$2"
|
||||
local output="$REPORTS_DIR/hunter_cve_$(date +%Y%m%d_%H%M%S).json"
|
||||
|
||||
# Map technologies to specific CVE template categories
|
||||
log "Running focused CVE scan..."
|
||||
|
||||
# Scan ALL targets with general CVE templates (faster than all 4k)
|
||||
nuclei -l "$targets_file" \
|
||||
-j \
|
||||
-rl 30 \
|
||||
-c 15 \
|
||||
-t "$NUCLEI_TEMPLATES/http/cves/" \
|
||||
-o "$output" \
|
||||
-severity critical,high \
|
||||
-silent \
|
||||
-stats \
|
||||
2>/dev/null
|
||||
|
||||
if [ -s "$output" ]; then
|
||||
ok "$(wc -l < "$output") critical/high findings"
|
||||
else
|
||||
warn "No critical/high findings in mass scan"
|
||||
fi
|
||||
|
||||
# Also run medium + exploitation templates for more depth
|
||||
local output2="$REPORTS_DIR/hunter_cve_medium_$(date +%s).json"
|
||||
nuclei -l "$targets_file" \
|
||||
-j \
|
||||
-rl 20 \
|
||||
-c 10 \
|
||||
-t "$NUCLEI_TEMPLATES/http/cves/" \
|
||||
-o "$output2" \
|
||||
-severity medium \
|
||||
-silent \
|
||||
2>/dev/null
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# PHASE 3: THE ANALYZER INTEGRATION
|
||||
# ============================================================
|
||||
|
||||
analyze_findings() {
|
||||
local findings_file="$1"
|
||||
local output="$REPORTS_DIR/hunter_report_$(date +%Y%m%d_%H%M).md"
|
||||
|
||||
log "Generating report..."
|
||||
|
||||
python3 -c "
|
||||
import json, sys
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
|
||||
findings = []
|
||||
cves = Counter()
|
||||
severities = Counter()
|
||||
|
||||
with open('$findings_file') as f:
|
||||
for line in f:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
sev = d.get('info',{}).get('severity','unknown')
|
||||
severities[sev] += 1
|
||||
|
||||
# Extract CVE IDs
|
||||
cve_list = []
|
||||
for ref in d.get('info',{}).get('classification',{}).get('cve',[]):
|
||||
cve_list.append(ref.get('id',''))
|
||||
if not cve_list:
|
||||
# Try alternative CVE sources
|
||||
for ref in d.get('info',{}).get('reference',[]):
|
||||
if 'cve' in ref.lower() or 'CVE' in ref:
|
||||
cve_list.append(ref.split('/')[-1])
|
||||
|
||||
cve_id = cve_list[0] if cve_list else 'N/A'
|
||||
for c in cve_list:
|
||||
cves[c] += 1
|
||||
|
||||
findings.append({
|
||||
'url': d.get('matched-at', d.get('host', '?')),
|
||||
'cve': cve_id,
|
||||
'severity': sev,
|
||||
'name': d.get('info',{}).get('name', '?'),
|
||||
'template': d.get('template-id', ''),
|
||||
'extracted': d.get('extracted-results', []),
|
||||
})
|
||||
except: pass
|
||||
|
||||
# Summary
|
||||
icons = {'critical':'🔴','high':'🟠','medium':'🟡','low':'🔵','unknown':'⚪'}
|
||||
print('# Mass Vulnerability Hunter Report')
|
||||
print(f'Generated: {datetime.now().strftime(\"%Y-%m-%d %H:%M\")}')
|
||||
print()
|
||||
print('## Summary')
|
||||
print('| Metric | Value |')
|
||||
print('|--------|-------|')
|
||||
print(f'| Total Findings | {len(findings)} |')
|
||||
for sev in ['critical','high','medium','low']:
|
||||
if severities[sev]:
|
||||
print(f'| {icons.get(sev,\"?\")} {sev.capitalize()} | {severities[sev]} |')
|
||||
|
||||
if cves:
|
||||
print()
|
||||
print('## CVEs Detected')
|
||||
for cve, cnt in cves.most_common(30):
|
||||
print(f'- [{cve}](https://nvd.nist.gov/vuln/detail/{cve}): {cnt} occurrences')
|
||||
|
||||
print()
|
||||
print('## All Findings')
|
||||
for f in findings:
|
||||
icon = icons.get(f['severity'], '?')
|
||||
print(f'- {icon} [{f[\"cve\"]}] {f[\"name\"]} @ {f[\"url\"]}')
|
||||
" > "$output" 2>/dev/null
|
||||
|
||||
ok "Report: $output"
|
||||
cat "$output"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# MAIN ENTRY POINT
|
||||
# ============================================================
|
||||
|
||||
hunter_main() {
|
||||
local target_count="${1:-500}"
|
||||
local mode="${2:-auto}" # auto|quick|deep
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ MASS VULNERABILITY HUNTER ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Phase 1: Build target list
|
||||
log "PHASE 1: Target Discovery"
|
||||
discover_from_tranco "$target_count"
|
||||
discover_vulnerable_software
|
||||
discover_from_analyzer
|
||||
|
||||
# Merge targets
|
||||
cat "$TARGETS_DIR"/hunt_*.txt "$WORK_DIR"/vuln_software_targets.txt 2>/dev/null | \
|
||||
sort -u > "$WORK_DIR/all_targets.txt"
|
||||
ok "Total unique targets: $(wc -l < "$WORK_DIR/all_targets.txt")"
|
||||
|
||||
# Phase 2: Tech Detection + CVE Scan
|
||||
echo ""
|
||||
log "PHASE 2: Scanning"
|
||||
|
||||
local tech_file="$WORK_DIR/tech_detected.json"
|
||||
detect_technologies "$WORK_DIR/all_targets.txt" "$tech_file"
|
||||
|
||||
echo ""
|
||||
local findings_file=$(run_focused_cve_scan "$WORK_DIR/all_targets.txt" "$tech_file")
|
||||
|
||||
# Phase 3: Analyze + Report
|
||||
echo ""
|
||||
log "PHASE 3: Analysis"
|
||||
analyze_findings "$findings_file"
|
||||
|
||||
echo ""
|
||||
ok "Hunt complete!"
|
||||
echo " Targets scanned: $(wc -l < "$WORK_DIR/all_targets.txt")"
|
||||
echo " Findings: $(wc -l < "$findings_file" 2>/dev/null || echo 0)"
|
||||
echo " Report: $REPORTS_DIR/hunter_report_*.md"
|
||||
}
|
||||
|
||||
# Run if executed directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
hunter_main "$@"
|
||||
fi
|
||||
Reference in New Issue
Block a user