Skip to content

eldaeonuap/phantom-proof

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fantom Finder

Open-source physical verification of cooperative-broadcast claims (FAA Remote ID for drones, AIS for ships) using passive radar.

Built at the 3rd Annual National Security Hackathon (Shack15, San Francisco, May 2-3, 2026) on $300 of commercial SDR hardware (Pi 5 + Pluto+ + RTL-SDR), using the open-source blah2 passive-radar pipeline. From scratch this weekend.

Fantom Finder Operator View — verdicts dashboard left, live track map right

Operator view at http://localhost:8090/combined — single page combining the verdicts dashboard (left) with the live track map (right). Left pane shows live PHANTOM verdicts from the spoofer demo, with sub-millisecond latency badges, TAK/Delta-ready CoT XML output, and the raw verdict payload. Right pane shows 14 live blah2 tracks geolocated via bistatic ellipse + Doppler — yellow markers with translucent CE rings around the Shack15 receiver, receiver shown as the blue dot. Same architecture serves both airborne (drone Remote ID spoof defense) and maritime (AIS spoof defense) variants.

Three views, one source of truth

URL Purpose
http://localhost:8090/combined Operator view — dashboard + map side-by-side (recommended for the demo)
http://localhost:7879/ Verdicts dashboard alone (fusion's primary UI)
http://localhost:8090/ Map alone (mapserver's primary UI)

Why this matters

Russia launches three thousand Shahed drones a month at Ukraine. The best detection layer they have — Sky Fortress, a 14,000-microphone acoustic mesh — gets alerts to fire teams in 12 seconds. But it's signature-dependent and breaks on jet variants like Geran-3. Active radars cost $10M per unit and get hit by anti-radiation missiles within a week of deployment.

We wanted to see how much of a passive-radar capability you could build from scratch in a weekend, on commercial hardware, against three real defense problems at once:

  1. Drone detection — using a TV broadcast tower as transmitter (no emissions of our own)
  2. Indoor presence sensing — using ambient Wi-Fi reflections (live volunteer demo)
  3. Drone-ID spoof defense — physical verification of FAA Remote ID via radar truth

Same box, same code, three constituencies addressed by one platform.

Why Fantom Finder

Remote ID is the FAA's drone identification standard. It's broadcast over Wi-Fi NAN beacons or BLE 5 extended advertisements and tells anyone listening "drone X is at lat/lon Y, altitude Z, going N m/s heading H." It's how law enforcement, airports, and other operators identify drones in the airspace.

It can be spoofed in 10 seconds with $5 of hardware. A simple ESP32 sketch broadcasts arbitrary Remote ID frames, and any receiver believes them. There's no cryptographic signing on the protocol.

A defender can't tell a real drone from a phantom one — unless they have an independent physical sensor confirming the broadcast. Fantom Finder uses passive radar (FM, DTV, or Wi-Fi as illuminator of opportunity) to do exactly that. If a Remote ID claim comes in and there's no radar track at the claimed position, we flag PHANTOM. If a track exists but its rotor micro-Doppler signature contradicts the claimed UA type, we flag DECEPTION (cf. Kozlov et al., Nature Sci Reports 2025, on radar deception).

Three constituencies, one codebase

  1. Defense — drone spoof defense in contested airspace; counter-c-UAS deception.
  2. Aviation safety — uncorrelated tracks visible alongside ADS-B, OpenDroneID feeds.
  3. Anomaly research — physics-based filters (kinematic-impossibility, supersonic-Doppler) that the passive-radar research community (Greneker, Georgia Tech) has flagged as the unsolved problem in long-range anomaly detection.

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│ Nemesis (Pi 5 + Pluto+ SDR, 2 coherent RX channels)                 │
│  Reference antenna ──> Pluto Ch0 ──┐                                │
│  Surveillance ant ──> Pluto Ch1 ──┴──> blah2 (existing C++)         │
│                                       Wiener-Hopf clutter →        │
│                                       Cross-Ambiguity Function →   │
│                                       CFAR → Tracker                │
│                                                  │                  │
│                                                  ▼                  │
│                                       /api/tracks/live              │
│                                                  │                  │
│  ESP32-S3 / Linux libopendroneid ──> JSON ──┐    │                  │
│                                              ▼    ▼                  │
│  ┌──────── fusion.py (this repo) ───────────────────┐               │
│  │  Match Remote ID → radar tracks (haversine + class)             │
│  │  Verdict: CONFIRMED / PHANTOM / DECEPTION + provenance           │
│  │  HTTP/SSE to dashboard.html on :7879                             │
│  └──────────────────────────────────────────────────┘               │
└─────────────────────────────────────────────────────────────────────┘

Quick start (30 seconds)

Software-only demo (no hardware required):

git clone https://github.com/<yours>/phantom-proof
cd phantom-proof
sudo apt-get install -y python3-aiohttp python3-numpy python3-scipy

# Terminal 1: synthetic radar tracks (stand-in for blah2)
python3 fake_tracker.py --port 49256

# Terminal 2: fusion service + dashboard
python3 fusion.py --tracker http://localhost:49256 --dashboard-port 7879

# Browser: http://localhost:7879/
# Press SPACE → 6 verdicts cascade in 5.5s (CONFIRMED + PHANTOM × 3 + DECEPTION + CONFIRMED)

Hardware demo (Pi 5 + Pluto+)

# On the Pi, install Docker + build blah2
bash scripts/01-install-blah2-on-pi.sh

# Swap to indoor Wi-Fi config (5 GHz, 20 MHz BW)
bash scripts/03-switch-to-wifi-config.sh

# Start fusion against the real radar tracker
bash scripts/04-start-demo.sh

# Browser: http://<pi-ip>:7879/

Walk past the antennas — you'll see your own body Doppler track. Run the spoofer (or fire the on-stage adversary ESP32):

python3 spoofer.py --target localhost:7878 --count 3

PHANTOM verdicts appear immediately because the spoofed positions don't match any radar track.

Files

Airborne (drone Remote ID defense)

File Purpose
fusion.py OpenDroneID UDP listener + verdict engine + HTTP/SSE dashboard server (:7879)
dashboard.html Single-page operator UI with verdict feed, latency HUD, and CoT panel
spoofer.py Software adversary — emits fake Remote ID claims to fusion's UDP :7878
firmware/esp32_droneid_spoofer.ino Real-RF Remote ID spoofer (ESP32-S3 sketch)
fake_tracker.py Stand-in for nemesis-tracker /api/tracks/live; demos without radar
demo_show.py 38 s scripted CONFIRMED → PHANTOM × 3 → DECEPTION → CONFIRMED sequence
aural.py Convert rotor micro-Doppler spectrogram to audible WAV

Maritime (ship AIS defense)

File Purpose
ais_fusion.py AIS UDP listener + verdict engine + HTTP/SSE on :7876 (UDP :7877)
ais_spoofer.py Software adversary — fake AIS broadcasts (zombie tankers, identity-spoofers)

Geolocation, CoT, web map

File Purpose
geolocate.py Bistatic-ellipse + Doppler target geolocation; honest CE estimates
blah2_config.py Live fetch of rx/tx/fc from blah2's /api/config; hardcoded fallback
blah2_to_cot.py One-shot CLI: pull a single track from blah2/nemesis-tracker, emit CoT 2.0 XML; supports --with-rationale, --multicast, --unicast
cot_emitter.py Verdicts → CoT XML; UDP multicast to ATAK SA channel + HTTP/SSE on :7880
cot_tcp_bridge.py TCP server iTAK / WinTAK / TAK clients connect to (port 8087)
cot_verify.py CoT multicast listener for testing without a real TAK client
mapserver.py Web map server (proxies tracks + applies geolocation) on :8090
map.html Leaflet-based live map; renders position + CE ring per track

Operator rationale (LLM with rule-based fallback)

File Purpose
classifier/rationale.py Operator-grade rationale per track or verdict; rule-based default, optional Anthropic Claude path when ANTHROPIC_API_KEY is set

Validators, scripts, docs

File Purpose
test_blah2_cot.py Programmatic validator: pulls live tracks, runs conversion, asserts every CoT field (16 checks/track)
blah2-config/config-wifi-indoor.yml blah2 config for indoor 5 GHz Wi-Fi illuminator
scripts/0[0-9]-*.sh Bring-up: install blah2, deploy, switch config, start fusion, start CoT, software-only demo
pitch.md / pitch_maritime.md 3:00 pitch scripts (airborne / maritime variants) with stage cues + Q&A
docs/map_screenshot.png Reference screenshot (above)

Verdict logic

Remote ID claim arrives (UDP JSON, port 7878).

If claim has lat/lon AND any radar track has lat/lon:
    Find the geographically nearest track within MATCH_RADIUS_M (default 80 m).
    If none found: PHANTOM.
    Otherwise: candidate is the nearest track.

If claim has no lat/lon:
    Find any active track within MATCH_TIMEOUT_S (default 3 s).
    If none found: PHANTOM.

For the candidate track:
    If (claim.ua_type, observed_class) is a known contradiction
    (e.g. claim=Aeroplane but rotor harmonics show quadcopter):
        DECEPTION.
    Otherwise: CONFIRMED.

Every verdict carries a human-readable reason string (the "because") so the operator dashboard can surface provenance directly.

API

Endpoint Method Purpose
/ GET Dashboard HTML
/events GET SSE feed of verdicts
/verdicts GET JSON history (last 200 verdicts)
/tracks GET Last-polled radar tracks
/health GET Service health, uptime, counts
/demo POST Fire scripted CONFIRMED → PHANTOM × 3 → DECEPTION → CONFIRMED sequence
/clear POST Clear verdict history

UDP port 7878 receives Remote ID JSON envelopes:

{
  "ts": 1777755472.123,
  "basic_id": {"uas_id": "MAVIC-2A", "ua_type": "Helicopter_Multirotor"},
  "location": {"latitude": 37.79504, "longitude": -122.39349, "altitude_m": 30}
}

License

MIT. Built on top of 30hours/blah2 (BSD), with credit to the OpenDroneID community and cyber-defence-campus/droneRemoteIDSpoofer for the receiver/spoofer reference.

Acknowledgments

  • Gene Greneker (Georgia Tech) — kinematic-impossibility filter framing, supersonic-Doppler insight
  • Victor Chen, The Micro-Doppler Effect in Radar (Artech House, 2nd ed.) — bistatic micro-Doppler equations, rotor signature analysis
  • ELDAEON — Nemesis hardware platform
  • US Army xTech, Cerebral Valley, Shield Capital — hosting the hackathon that produced this work

Packages

 
 
 

Contributors