mirror of
https://github.com/SHOGGOTH-SECTOR/sica-fondt.git
synced 2026-08-01 08:30:20 +00:00
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):
- brain/ LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
dispatch, A51 channels, and the OSINT cluster
- knowledge/ LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
MITRE ATT&CK data
- reference/ defensive threat-reference (C3, shhbruh doc) + AdaYaml parser
License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.
Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.
https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
250 lines
8.7 KiB
Python
250 lines
8.7 KiB
Python
#!/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()
|