#!/usr/bin/env python3 """Dark web threat monitoring agent. Monitors for organization-specific threats on the dark web by checking breach databases (Have I Been Pwned API), paste sites, and public threat intelligence feeds for leaked credentials, exposed data, and mentions of organizational domains. """ import argparse import hashlib import json import os import sys import time from datetime import datetime, timezone try: import requests except ImportError: print("[!] 'requests' required: pip install requests", file=sys.stderr) sys.exit(1) def check_hibp_breaches(domain, api_key=None): """Check Have I Been Pwned for breaches involving a domain.""" findings = [] print(f"[*] Checking HIBP breaches for domain: {domain}") headers = {"user-agent": "dark-web-monitor-agent"} if api_key: headers["hibp-api-key"] = api_key try: resp = requests.get( f"https://haveibeenpwned.com/api/v3/breaches", headers=headers, timeout=15, ) resp.raise_for_status() breaches = resp.json() domain_breaches = [b for b in breaches if domain.lower() in b.get("Domain", "").lower()] for breach in domain_breaches: findings.append({ "type": "breach", "source": "HIBP", "name": breach.get("Name", ""), "domain": breach.get("Domain", ""), "breach_date": breach.get("BreachDate", ""), "added_date": breach.get("AddedDate", ""), "pwn_count": breach.get("PwnCount", 0), "data_classes": breach.get("DataClasses", []), "is_verified": breach.get("IsVerified", False), "severity": "CRITICAL" if breach.get("PwnCount", 0) > 10000 else "HIGH", }) print(f"[+] Found {len(domain_breaches)} breaches for {domain}") except requests.RequestException as e: print(f"[!] HIBP API error: {e}") return findings def check_hibp_email(email, api_key): """Check if a specific email appears in known breaches.""" if not api_key: return [] findings = [] headers = {"hibp-api-key": api_key, "user-agent": "dark-web-monitor-agent"} try: resp = requests.get( f"https://haveibeenpwned.com/api/v3/breachedaccount/{email}", headers=headers, params={"truncateResponse": "false"}, timeout=15, ) if resp.status_code == 200: breaches = resp.json() for breach in breaches: findings.append({ "type": "email_breach", "email": email, "breach": breach.get("Name", ""), "breach_date": breach.get("BreachDate", ""), "data_classes": breach.get("DataClasses", []), "severity": "HIGH", }) elif resp.status_code == 404: pass # Not found in any breaches time.sleep(1.5) # HIBP rate limit except requests.RequestException: pass return findings def check_hibp_password(password): """Check if a password appears in known breaches using k-anonymity.""" sha1 = hashlib.sha1(password.encode("utf-8")).hexdigest().upper() prefix = sha1[:5] suffix = sha1[5:] try: resp = requests.get( f"https://api.pwnedpasswords.com/range/{prefix}", timeout=10, ) resp.raise_for_status() for line in resp.text.splitlines(): parts = line.split(":") if parts[0] == suffix: count = int(parts[1]) return {"compromised": True, "count": count, "severity": "CRITICAL"} return {"compromised": False, "count": 0, "severity": "INFO"} except requests.RequestException: return {"compromised": None, "error": "API unavailable"} def check_paste_dumps(domain, api_key=None): """Check for organization mentions in paste sites via HIBP.""" findings = [] if not api_key: return findings # HIBP paste API requires per-email queries return findings def search_threat_intel_feeds(domain): """Search public threat intelligence for domain mentions.""" findings = [] print(f"[*] Checking public threat intelligence for: {domain}") # Check URLhaus for malicious URLs from domain try: resp = requests.post( "https://urlhaus-api.abuse.ch/v1/host/", data={"host": domain}, timeout=15, ) if resp.status_code == 200: data = resp.json() if data.get("query_status") == "ok": urls = data.get("urls", []) if urls: findings.append({ "type": "malicious_urls", "source": "URLhaus", "domain": domain, "count": len(urls), "severity": "HIGH", "detail": f"{len(urls)} malicious URLs associated with domain", "samples": [u.get("url", "")[:80] for u in urls[:5]], }) except requests.RequestException: pass # Check AbuseIPDB abuse_key = os.environ.get("ABUSEIPDB_KEY", "") if abuse_key: try: resp = requests.get( "https://api.abuseipdb.com/api/v2/check-block", headers={"Key": abuse_key, "Accept": "application/json"}, params={"network": domain}, timeout=15, ) except requests.RequestException: pass return findings def format_summary(all_findings, domain): """Print monitoring summary.""" print(f"\n{'='*60}") print(f" Dark Web Threat Monitoring Report") print(f"{'='*60}") print(f" Target Domain: {domain}") print(f" Total Findings: {len(all_findings)}") by_type = {} for f in all_findings: t = f.get("type", "unknown") by_type[t] = by_type.get(t, 0) + 1 if by_type: print(f"\n By Type:") for t, count in by_type.items(): print(f" {t:20s}: {count}") breaches = [f for f in all_findings if f["type"] == "breach"] if breaches: print(f"\n Known Breaches ({len(breaches)}):") for b in breaches: print(f" [{b['severity']:8s}] {b['name']:25s} | " f"Date: {b['breach_date']} | Records: {b.get('pwn_count', 'N/A')}") if b.get("data_classes"): print(f" Data: {', '.join(b['data_classes'][:5])}") severity_counts = {} for f in all_findings: sev = f.get("severity", "INFO") severity_counts[sev] = severity_counts.get(sev, 0) + 1 return severity_counts def main(): parser = argparse.ArgumentParser(description="Dark web threat monitoring agent") parser.add_argument("--domain", required=True, help="Organization domain to monitor") parser.add_argument("--emails", nargs="+", help="Specific emails to check") parser.add_argument("--hibp-key", help="HIBP API key (or HIBP_API_KEY env)") parser.add_argument("--check-passwords", nargs="+", help="Check passwords against breach DB") parser.add_argument("--output", "-o", help="Output JSON report") parser.add_argument("--verbose", "-v", action="store_true") args = parser.parse_args() hibp_key = args.hibp_key or os.environ.get("HIBP_API_KEY", "") all_findings = [] all_findings.extend(check_hibp_breaches(args.domain, hibp_key)) if args.emails and hibp_key: for email in args.emails: all_findings.extend(check_hibp_email(email, hibp_key)) if args.check_passwords: for pwd in args.check_passwords: result = check_hibp_password(pwd) if result.get("compromised"): all_findings.append({ "type": "compromised_password", "severity": "CRITICAL", "detail": f"Password found in {result['count']} breaches", }) all_findings.extend(search_threat_intel_feeds(args.domain)) severity_counts = format_summary(all_findings, args.domain) report = { "timestamp": datetime.now(timezone.utc).isoformat(), "tool": "Dark Web Monitor", "domain": args.domain, "findings": all_findings, "severity_counts": severity_counts, "risk_level": ( "CRITICAL" if severity_counts.get("CRITICAL", 0) > 0 else "HIGH" if severity_counts.get("HIGH", 0) > 0 else "MEDIUM" if all_findings else "LOW" ), } if args.output: with open(args.output, "w") as f: json.dump(report, f, indent=2) print(f"\n[+] Report saved to {args.output}") elif args.verbose: print(json.dumps(report, indent=2)) if __name__ == "__main__": main()