Files
Shadowbroker/backend/services/fetchers/malware.py
T
BigBodyCobain af9b3d08cc feat: Telegram OSINT map layer, Osiris intel ports, and maritime settings
Add Telegram OSINT with hourly incremental t.me scraping, metro geocoding
separate from news centroids, threat-intercept popup UI with inline media,
and HTML markers above alert boxes so pins stay clickable. Expose GFW_API_TOKEN
in onboarding and Settings Maritime; harden GFW/CCTV/geo fetchers. Port Osiris-
derived recon, SCM, entity graph, malware/cyber feeds, sanctions, and submarine
cable layers with tests and documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 21:04:08 -06:00

108 lines
4.3 KiB
Python

"""Malware C2 / URLhaus feed (abuse.ch, Osiris port)."""
from __future__ import annotations
import logging
from datetime import datetime, timezone
from typing import Any
from services.fetchers._store import _data_lock, _mark_fresh, is_any_active, latest_data
from services.network_utils import fetch_with_curl
logger = logging.getLogger(__name__)
COUNTRY_CENTROIDS: dict[str, tuple[float, float]] = {
"AF": (65, 33), "AL": (20, 41), "DZ": (3, 28), "AR": (-64, -34), "AU": (134, -25),
"AT": (14, 47.5), "BE": (4, 50.8), "BR": (-51, -10), "CA": (-96, 62), "CN": (105, 35),
"DE": (10, 51), "FR": (2, 46), "GB": (-2, 54), "IN": (79, 22), "IR": (53, 32),
"IT": (12.5, 42.8), "JP": (138, 36), "KR": (128, 36), "MX": (-102, 23.5), "NL": (5.5, 52.5),
"PL": (19.5, 52), "RU": (100, 60), "SG": (103.8, 1.35), "TW": (121, 23.7), "UA": (32, 49),
"US": (-97, 38), "VN": (106, 16),
}
def fetch_malware_threats() -> list[dict[str, Any]]:
if not is_any_active("malware_c2"):
return latest_data.get("malware_threats") or []
threats: list[dict[str, Any]] = []
threat_id = 0
try:
resp = fetch_with_curl(
"https://feodotracker.abuse.ch/downloads/ipblocklist.json",
timeout=10,
headers={"User-Agent": "Shadowbroker/1.0", "Accept": "application/json"},
)
if resp.status_code == 200:
entries = resp.json()
if not isinstance(entries, list):
entries = []
for entry in entries[:200]:
cc = entry.get("country")
if not cc or cc not in COUNTRY_CENTROIDS:
continue
lng, lat = COUNTRY_CENTROIDS[cc]
j_lng = ((threat_id * 173.7) % 200 - 100) / 100 * 4
j_lat = ((threat_id * 293.1) % 200 - 100) / 100 * 4
threats.append(
{
"id": f"feodo-{threat_id}",
"lat": lat + j_lat,
"lng": lng + j_lng,
"ip": entry.get("ip_address") or "unknown",
"port": entry.get("dst_port") or 0,
"malware": entry.get("malware") or "unknown",
"status": entry.get("status") or "active",
"first_seen": entry.get("first_seen"),
"last_online": entry.get("last_online"),
"country": cc,
"threat_type": "botnet_c2",
}
)
threat_id += 1
except Exception as exc:
logger.warning("Feodo fetch failed: %s", exc)
try:
resp = fetch_with_curl(
"https://urlhaus-api.abuse.ch/v1/urls/recent/limit/100/",
timeout=8,
)
if resp.status_code == 200:
urls = (resp.json() or {}).get("urls") or []
for u in urls:
cc = u.get("country")
if not cc or cc not in COUNTRY_CENTROIDS:
cc = next(iter(COUNTRY_CENTROIDS))
lng, lat = COUNTRY_CENTROIDS[cc]
j_lng = ((threat_id * 137.3) % 200 - 100) / 100 * 5
j_lat = ((threat_id * 211.7) % 200 - 100) / 100 * 5
threats.append(
{
"id": f"urlhaus-{threat_id}",
"lat": lat + j_lat,
"lng": lng + j_lng,
"ip": u.get("host") or "unknown",
"port": 0,
"malware": ", ".join(u.get("tags") or []) or u.get("threat") or "malware",
"status": u.get("url_status") or "online",
"first_seen": u.get("dateadded"),
"country": cc,
"threat_type": "malware_url",
}
)
threat_id += 1
except Exception as exc:
logger.debug("URLhaus supplement failed: %s", exc)
payload = {
"threats": threats,
"total": len(threats),
"timestamp": datetime.now(timezone.utc).isoformat(),
"source": "abuse.ch Feodo Tracker + URLhaus",
}
with _data_lock:
latest_data["malware_threats"] = payload
_mark_fresh("malware_threats")
return threats