Mechanism
ADS-B ‘out’ is a periodic, one-way broadcast in which an aircraft reports its own
state, identity, position, velocity, with no interrogation, no association, no
encryption and no authentication [costin2012ghost][strohmeier2013survey]. Worldwide
it rides the 1090 MHz Mode S Extended Squitter (1090ES); in the US, lower-altitude
general aviation additionally uses a separate 978 MHz UAT link [strohmeier2017perception].
On 1090 MHz the signal is pulse-position modulation at 1 Mbps, and an Extended
Squitter is a fixed 112-bit frame (an 8 µs preamble followed by 112 µs of data
bits) [sun2021riddle]. There is no frequency hopping and no channelisation: every
aircraft squitters on the same carrier, so a single ~2 MHz receiver sees the whole
picture, and the only contention is overlapping bursts. On 1090 MHz the bit period
is 1 µs (a pulse in the first half of the period is a 1, in the second half a 0),
giving the 1 Mbps rate; the 978 MHz UAT link instead uses CPFSK at 1.041667 Mbps with
a 272-bit long message [sun2021riddle].
The 112-bit frame begins with a 5-bit downlink format. ADS-B uses DF17 for transponder-equipped aircraft and DF18 for non-transponder / TIS-B transmitters; it then carries the 24-bit ICAO aircraft address and a 5-bit type code that selects the payload, aircraft identification (the 8-character callsign), airborne or surface position (latitude/longitude in Compact Position Reporting, CPR, encoding), or velocity [sun2021riddle]. A 24-bit parity field lets a receiver validate the frame. Crucially, none of the identifiers is authenticated: the ICAO address, callsign and CPR position are broadcast in the clear with no signature and no integrity over the source, so a receiver cannot tell a genuine aircraft from a forged one [costin2012ghost][strohmeier2013survey].
This control verifies only the receive-and-decode baseline, the passive eavesdropping that the literature established is trivially feasible with a cheap SDR [costin2012ghost]. That same absent authentication is what makes the active attack families possible: experimental work has demonstrated message injection (‘ghost aircraft’), track modification, jamming and flooding against ADS-B receivers [schafer2013experimental][strohmeier2017perception]. Those are legally sensitive transmit operations on protected aviation safety spectrum and are assessed under the Attack-layer control, not here; this PHY control stays receive-only.
Procedure
Receive-only throughout. Capturing and decoding ADS-B is passive and generally lawful, but transmitting on 1090/978 MHz is not, do not transmit at any step here.
-
Confirm the band is alive before committing a decoder. Tune an SDR to 1090 MHz in a waterfall viewer and watch for the short, bursty Extended-Squitter pulses (ADS-B sits above the noise floor, so they are visibly bursty):
gqrx # set the device to your RTL-SDR, tune 1090.000 MHz, sample rate ~2.4 MSPSExpected: intermittent narrow pulses popping up at the carrier as aircraft squitter. If you see nothing, check the antenna/filter chain (a 1090 MHz band-pass filter + LNA dramatically lifts weak traffic) before blaming the decoder.
-
Decode the 1090ES link with a primary decoder. dump1090-fa demodulates the PPM bursts, validates the parity and decodes DF17/DF18, with an interactive table:
dump1090-fa --device-type rtlsdr --gain -10 --interactiveExpected: a live table of aircraft keyed by ICAO hex address, with callsign, altitude, position (once a CPR even/odd pair is collected) and speed. A handful of rows means a few local aircraft; a busy sky fills the table.
--gain -10selects the tuner’s automatic gain. -
Serve the decoded feed for downstream tooling. For a permanent or busy receiver, run readsb and emit network output (Beast/raw/JSON) instead of (or as well as) the interactive view:
readsb --device-type rtlsdr --net --write-json /run/readsbExpected: readsb starts, tracks many aircraft at once, and serves a JSON
aircraft.json(consumed by a map such as tar1090) plus Beast/raw ports, the handoff point to the Application-layer air-picture and plausibility controls. -
(US only) Add the 978 MHz UAT link. The 1090 decoders do not cover UAT; tune a second SDR to 978 MHz and run dump978 alongside:
dump978-fa --sdr driver=rtlsdr | readsb --net --net-only --uat-in-port 30978Expected: UAT downlink frames from lower-altitude general aviation, merged into the same aircraft picture.
-
Verify decode correctness on individual frames with pyModeS, the decode you can reason about by hand. Feed a hex frame to the CLI:
modes decode 8D406B902015A678D4D220AA4BDAExpected:
df 17,icao 406B90,typecode 4(identification), callsignEZY85MH, confirming the demodulated bits decode to a sensible identity. This is the per-frame ground truth behind the live table. -
(Optional) Demodulate inside a flowgraph instead of a black-box decoder, when you want to see each DSP stage (preamble correlation, bit slicing):
uhd_modes.py # gr-air-modes receiver, or run its GNU Radio flowgraphExpected: the same DF17/DF18 decode, with the signal processing exposed for inspection or modification.
Field case
A reproducible bench check using pyModeS’s own published example frames (no air capture or transmitter required), confirming the decode chain end to end. Decode a matched CPR even/odd airborne-position pair plus an identification and a velocity frame:
modes decode 8D40058B58C901375147EFD09357,8D40058B58C904A87F402D3B8C59,8D406B902015A678D4D220AA4BDA
The two 8D40058B… frames are the even and odd halves of one CPR position for ICAO
40058B; together they resolve to a single latitude/longitude. The
8D406B902015A678D4D220AA4BDA frame is a DF17 type-code-4 identification for ICAO
406B90, decoding to callsign EZY85MH. A globally-referenced position decode for a
single even frame (no pair needed) confirms the CPR maths against a known receiver
location:
modes decode 8D40058B58C901375147EFD09357 --reference 49.0 6.0
These are the canonical pyModeS test vectors, so the expected outputs are stable: a
40058B position near the 49.0 N, 6.0 E reference and the 406B90 / EZY85MH
identity. This is the verifiable, reproducible core of the field case, the decode
chain confirmed against fixed, published frames, with no air capture or transmitter
required.
Illustrative walkthrough, substitute the values you capture: on a real over-the-air session you would replace these vectors with live frames from step 2/3 and record the receiver-side numbers for the local environment. No author-measured live ADS-B capture is recorded here; the representative over-the-air figures, distinct aircraft seen over a session, fraction of frames passing parity, maximum range with/without a 1090 MHz LNA+filter, are [FILL: measured receiver statistics], to be filled from an authorised on-site capture.
Remediation
ADS-B’s exposure is architectural, the link is plaintext and unauthenticated by design [costin2012ghost][strohmeier2013survey], so “remediation” at this layer is about not over-trusting the feed rather than securing the radio.
-
Developer (avionics / receiver firmware): do not treat a decoded DF17/DF18 frame as a trusted assertion of position or identity. Parity (the 24-bit CRC) proves the frame arrived intact, not that it came from the aircraft it names [sun2021riddle]. Where feasible, design toward the authenticated/integrity-protected ADS-B extensions and broadcast-authentication schemes proposed in the literature rather than the bare link [strohmeier2017perception].
-
Integrator (tracking / display / fusion systems): never rely on ADS-B as a sole source of truth. Fuse it with independent sensors (primary/secondary radar, multilateration that times the same frame at several stations to fix an aircraft independently of what it claims) and run plausibility checks, impossible kinematics, positions inconsistent across receivers, ICAO addresses that should not be airborne [schafer2013experimental][strohmeier2017perception]. These detections are implemented at the Application layer; this PHY capture is their input.
-
Operator (researcher / SOC running a receiver): keep receive-only, capturing and decoding ADS-B is passive and generally lawful, but transmitting on 1090/978 MHz is protected aviation safety spectrum and must never be radiated; any spoofing/ injection assessment belongs to the Attack-layer control and is done only on authorised research equipment over a conducted (cabled) or shielded (Faraday) path, never on-air [strohmeier2017perception]. Log receiver statistics so an anomalous flood or a ghost track is visible against a known baseline.