Marshall Yanis Security • RE • Embedded
GitHub LinkedIn Resume
offensive-security completed

Spoofing the Sky: Building an ADS-B Ghost Aircraft Injector

Building a tool that injects synthetic aircraft into a live dump1090-fa feed using crafted DF17 ADS-B messages and exploring the security implications of an unauthenticated broadcast protocol.

PythonRTL-SDRdump1090-fa

Spoofing the Sky: Building an ADS-B Ghost Aircraft Injector

Part 1 of a series on ADS-B security research


Introduction

This project sits at the intersection of two things I care deeply about: understanding how critical infrastructure communicates, and finding the gaps in that communication that an attacker could exploit. ADS-B is the protocol that aircraft use to broadcast their position to the world and has no authentication. Any receiver, anywhere, can hear any aircraft. And as this project demonstrates, any transmitter can pretend to be one.

This is the first post in a series on ADS-B security research. In this post I’ll walk through the protocol itself, how I set up a live capture environment using an RTL-SDR V4 and a V-dipole antenna, and how I built a tool that injects fully synthetic aircraft into a live dump1090-fa feed: complete with callsign, position, altitude, speed, and heading. The ghost aircraft appear on SkyAware alongside real traffic with no visual distinction between them.

My goal with researching this specific protocol is its possible similarity to spacecraft telemetry links. If a system solely relies on unidirectional broadcast protocols with little or no source authentication, that is an easily spoofed target. And it was fun. That’s important.

ADS-B is a mature, and well documented, target that lets us build and test spoofing techniques with an immediate visual feedback.

The full source code is available on my GitHub: mars-sec/adsb-ghost-injector

Ghost_And_Real_Traffic


What is ADS-B?

ADS-B stands for Automatic Dependent Surveillance-Broadcast. It is the system modern aircraft use to broadcast their identity and position to anyone who is listening: air traffic control, other aircraft, and since the advent of cheap software-defined radios, hobbyists and researchers like you and me.

Breaking down the name tells you everything about how it works:

  • Automatic — the aircraft broadcasts continuously without any prompting from the ground
  • Dependent — it depends on the aircraft’s own GPS receiver to know its position
  • Surveillance — it serves the same situational awareness function as radar
  • Broadcast — it transmits to everyone simultaneously, not to a specific receiver

Aircraft equipped with ADS-B transmit on 1090 MHz using a protocol called Mode S Extended Squitter. Every second or so, the transponder broadcasts a packet containing the aircraft’s ICAO address (a unique 24-bit identifier), its GPS-derived position, altitude, speed, heading, and callsign. Any receiver within line of sight, roughly 200-300 nautical miles at altitude, can decode and display this information.

ADS-B Out became mandatory for aircraft operating in most controlled US airspace in 2020. It has largely replaced radar as the primary surveillance mechanism at many facilities.

ADS-B_Broadcast_Diagram Diagram from https://trig-avionics.com/knowledge-bank/ads-b/ads-b-explanations/

Why It Has No Authentication

ADS-B was designed in the 1990s and standardized in the early 2000s, when the threat model for aviation communication was very different from today. The protocol was designed for performance and interoperability, not security. Broadcasting a cryptographic signature alongside every position update would have required more bandwidth and more processing power than the transponder hardware of that era could support.

The result is a protocol where any receiver must accept any message it receives. There is no way to verify that the aircraft claiming to be at a given position actually is there, or that the ICAO address in the message belongs to the aircraft that sent it. The receiver has no mechanism to distinguish a real transmission from a crafted one.

The aviation community has been aware of the problem for over a decade. Authentication extensions have been proposed and studied, but retrofitting authentication onto a globally deployed, safety-critical system is an extraordinarily complex undertaking. As of this writing, unauthenticated ADS-B remains the operational standard.


The Security Problem

The lack of authentication creates several attack surfaces worth understanding:

Ghost injection is what this project demonstrates: inserting synthetic aircraft into receiver displays by crafting valid-looking messages and feeding them into a decoder. A ghost aircraft appears visually indistinguishable from a real one. At scale, an attacker could flood a display with hundreds of phantom aircraft, obscuring real traffic or triggering automated conflict avoidance systems.

Identity spoofing involves transmitting with a real aircraft’s ICAO address, causing that aircraft to appear in two places simultaneously or to show conflicting position data. This can confuse ATC tracking systems that correlate ADS-B data with radar returns.

Track manipulation involves replaying captured messages with modified fields: shifting a real aircraft’s reported position, changing its altitude, or altering its squawk code. The aircraft continues flying normally while its digital representation shows something different.

TCAS interference is the most safety-critical concern. TCAS (Traffic Collision Avoidance System) uses transponder interrogation rather than ADS-B for its resolution advisories, which provides some isolation from ADS-B spoofing. The interaction between ADS-B spoofing and TCAS behavior is an active area of research, and the boundary between what TCAS uses and what it ignores is not always clear from the outside.

It is important to be direct about the scope of this research: everything in this project operates entirely within a local software environment. No RF is transmitted. Messages are injected into a local dump1090 instance over TCP, and they appear only on a local SkyAware map. RF transmission of false ADS-B signals would implicate 18 U.S.C. § 32, 47 U.S.C. §§ 325 and 333, and 47 C.F.R. Part 87, among other statutes. This tool has no RF transmission path and is intended solely for local security research.

The parallels to space systems are worth noting. CCSDS, the dominant protocol suite for spacecraft telemetry, does not include authentication in its baseline specification, treating security as an optional add-on layer (CCSDS 350.0-G-3). The SPARTA framework, maintained by The Aerospace Corporation, catalogs authentication weaknesses as documented threat vectors against spacecraft. The techniques developed here for understanding broadcast protocol vulnerabilities are directly applicable to that domain.


The Current Setup

The physical setup is straightforward: an RTL-SDR V4 connected to a V-dipole antenna, running into dump1090-fa on a Windows 11 host.

RTL-SDR and V-Dipole Antenna

Hardware

RTL-SDR V4 is a software-defined radio receiver built around the RTL2832U chip with a Rafael Micro R828D tuner. The V4 revision adds a built-in upconverter and improved filtering compared to earlier versions. For ADS-B work at 1090 MHz it performs extremely well. The noise floor is low and the sensitivity is sufficient to track aircraft at 200+ nautical miles on a clear day. I am also near enough to an airport, so thankfully clear LOS isn’t hard for me to achieve.

V-dipole antenna is tuned for 1090 MHz. A V-dipole is two elements arranged in a V shape, angled at roughly 120 degrees, and each pole is about 2.7 inches or 68mm. For ADS-B it outperforms a simple whip antenna because the angled elements provide better gain toward the horizon where aircraft are located, while rejecting some of the noise from directly overhead and below.

Software

dump1090-fa is FlightAware’s fork of the original dump1090 decoder. It receives the raw IQ samples from the RTL-SDR, performs the Mode S demodulation and decoding, and exposes the results over several TCP ports:

  • Port 30002 — raw AVR format output, one message per line as *HEXDATA;\r\n
  • Port 30001 — raw AVR format input, accepts injected messages in the same format
  • Port 8080 — the SkyAware web interface

SkyAware is dump1090-fa’s built-in web map. It connects to the decoder over a WebSocket and renders aircraft positions in real time. This is where our pretty ghost aircraft appear.

Data Flow

Real aircraft
    ↓ 1090 MHz radio wave
V-Dipole Antenna
    ↓ Analog electrical signal
RTL-SDR V4 (USB)
    ↓ IQ samples
dump1090-fa ← Our injected message enters here via TCP
    ↓ Demodulation
    ↓ Bit extraction
    ↓ CRC validation ← Our injected message skips straight to this step
    ↓ Field decoding and storing
SkyAware

Data flow diagram


How ADS-B Messages Are Structured

Understanding the message format is essential to building a tool that can construct them. Every ADS-B message follows the same basic structure.

The DF17 Frame

ADS-B messages use Downlink Format 17 (DF17), also called Extended Squitter. Every DF17 frame is exactly 14 bytes:

Byte 0:      [DF=17 (5 bits)] [CA=5 (3 bits)]
Bytes 1-3:   ICAO address (24 bits)
Bytes 4-10:  ME: Message Extended payload (56 bits)
Bytes 11-13: CRC-24 checksum (24 bits)

The first byte is always 0x8D, that is (17 << 3) | 5, the downlink format shifted into the top 5 bits with capability code 5 in the bottom 3 bits.

The ICAO address is the aircraft’s unique 24-bit identifier. Every aircraft in the world has one, assigned by its country of registration. It is the primary key that receivers use to track individual aircraft across multiple messages.

The ME field is where the actual data lives. The top 5 bits of the ME field contain the Type Code (TC), which tells the receiver what kind of information the rest of the field contains:

CRC-24

Every message is protected by a 24-bit cyclic redundancy check using the generator polynomial 0x1FFF409. This is defined in ICAO Doc 9684 and is non-negotiable… dump1090 validates the CRC on every incoming message and silently drops any message that fails.

The CRC is computed over the first 11 bytes of the frame and appended as the final 3 bytes.

CRC24 generator polynomial: 0x1FFF409
Derived from: x^24 + x^23 + x^18 + x^17 + x^14 + x^11 + x^10 + x^7 + x^6 + x^5 + x^4 + x^3 + 1

The Wire Format

dump1090 accepts injected messages over TCP in AVR format, a simple text wrapper:

*8DAABBCC203414931438205781B5;\r\n

The asterisk signals the start of a message, the semicolon signals the end, and the hex string between them is the raw frame bytes. That is the entire protocol.

Raw AVR formatted ADS-B messages


CPR Position Encoding

CPR (Compact Position Reporting) is the most technically interesting part of ADS-B. Rather than transmitting raw latitude and longitude coordinates, ADS-B encodes position as a fractional offset within a latitude/longitude zone. This encoding scheme achieves higher precision in fewer bits than a direct coordinate representation would allow.

If you are interested in understanding this beyond the surface that I cover here, please check out Junzi Sun’s writeup covering The 1090 Megahertz Riddle, which includes ADS-B and Mode S.

The Core Concept

The globe is divided into a grid of latitude zones. For ADS-B, there are 60 zones for even frames and 59 zones for odd frames. The zone sizes are slightly different between the two frame types:

Even frame zone size: 360° / 60 = 6.0° per zone
Odd frame zone size:  360° / 59 = 6.101° per zone

Instead of saying “I am at latitude 42.36°”, an aircraft says “I am 6% of the way through zone 7.” The receiver already knows where zone 7 starts and ends, so it can reconstruct the position, only approximately, because it doesn’t know which of the 60 zones you mean without additional information.

This is where the even/odd pairing comes in. Because even and odd frames use slightly different zone sizes, the pair of values (even fraction, odd fraction) maps to exactly one set of absolute coordinates within a large unambiguous range. A receiver that collects both an even and an odd frame within about 10 seconds can compute the exact position to within a few meters.

Simplified CPR Position Encoding

Simplified CPR Position Encoding, all position possibilities Pulled from Junzi Sun’s writeup covering The 1090 Megahertz Riddle

The Longitude Zone Problem

Longitude zones are more complex because they vary with latitude. Near the equator, longitude lines are far apart and there are many zones. Near the poles, longitude lines converge and there are fewer. The number of longitude zones at a given latitude is called NL(lat) and is calculated using this formula from the ADS-B specification:

NL(lat) = floor(2π / arccos(1 - (1 - cos(π/30)) / cos(π × lat / 180)²))

For latitudes above 87°, NL is set to 1. At the poles, longitude effectively becomes meaningless.

The Encoding

For each coordinate, the CPR value is the fractional position within the zone, scaled to a 17-bit integer (0 to 131071):

lat_cpr = floor((lat / d_lat - floor(lat / d_lat)) × 131072 + 0.5) mod 131072

The result is a 17-bit value that, combined with its even/odd counterpart, uniquely describes a position anywhere on Earth to within about 5 meters.

Diagram showing latitude zones and CPR fractional encoding concept Pulled from Junzi Sun’s writeup covering The 1090 Megahertz Riddle


Building the Ghost Injector

With the protocol understood, building the injector is a matter of implementing each message type correctly and wiring them together.

Architecture

The tool has a clean layered structure:

GhostAircraft class
    ↓ calls
Message builders (build_callsign_message, airborne_position_message, velocity_message)
    ↓ call
Encoding utilities (encode_icao, encode_altitude, encode_cpr)
    ↓ call
CRC utilities (crc24, append_crc)

TCP send (connect, send)

dump1090-fa port 30001

Each layer has a single responsibility and can be tested independently. The encoding utilities were all verified against known-good messages captured from real aircraft on port 30002 before any injection was attempted.

Callsign Message (TC=4)

The identification message encodes 8 characters of callsign into 48 bits using a 64-character ADS-B charset where each character maps to a 6-bit index. The characters are packed left to right, first character occupies the most significant 6 bits.

The ADS-B charset is not ASCII. It starts with @ at index 0, followed by A-Z, then special characters, then space at index 32, then digits 0-9 starting at index 48. Any character not in the set falls back to space.

Altitude Encoding

Altitude is encoded as a 13-bit field using the Q-bit method. Rather than encoding feet directly, the protocol works in 25-foot increments with a 1000-foot offset to handle negative altitudes:

N = (altitude_ft + 1000) / 25

The Q-bit (bit 4 of the 13-bit field) is set to 1 to signal that this encoding is in use. N is then split across the Q-bit, the upper 7 bits of N go above it, the lower 4 bits go below it. This split is necessary because the Q-bit sits in the middle of the field rather than at one end. Bit 4 was likely chosen because it corresponds to a position in the legacy Gillham encoding that carries no meaningful data in valid altitude codes, though I have not found primary documentation confirming this reasoning.

Position Message (TC=11)

The position message assembles six fields into a 56-bit ME payload:

bits 56-52: TC = 11
bits 51-50: surveillance status = 0
bit  49:    NIC supplement = 0
bits 48-36: altitude (13 bits, Q-bit encoded)
bit  35:    time flag = 0
bit  34:    F flag (0=even, 1=odd)
bits 33-17: lat-CPR (17 bits)
bits 16-0:  lon-CPR (17 bits)

The F flag alternates on each transmission, producing the alternating even/odd CPR frames that receivers need to resolve absolute position. Even and odd frames must be sent back to back. Sending them more than about 10 seconds apart prevents position resolution.

Velocity Message (TC=19)

Speed and heading are decomposed into East/West and North/South components using basic trigonometry, then encoded separately with direction bits and 10-bit magnitudes. Every magnitude gets a +1 offset because 0 is reserved to mean “not available.”

The GhostAircraft Class

The GhostAircraft class ties everything together. It holds aircraft state and implements two methods:

update_position(dt_sec) performs dead reckoning where, given elapsed time in seconds, it calculates how far the aircraft has moved based on speed and heading, updates lat/lon, and adjusts altitude based on vertical rate. The longitude update includes a cos(lat) correction because longitude degrees get shorter as you approach the poles.

get_messages() returns the list of messages to send on the current tick. Position is sent every tick. Velocity is sent every 3 ticks. Callsign is sent every 5 ticks. Even/odd CPR frames alternate on each call using the tick counter.

Terminal when running injector


What This Means for Security

For aviation directly, the concern is not that a single ghost aircraft causes a collision, pilots have instruments and procedures that don’t rely on ADS-B. The concern is at the system level: ATC tools that ingest ADS-B data, automated conflict detection systems, and ground-based tools that use ADS-B for airspace management. A coordinated injection of many ghost aircraft could degrade the utility of these systems significantly.

For TCAS, the interaction is more contained. TCAS resolution advisories rely on active transponder interrogation where TCAS sends out a directed query and listens for a reply from the target aircraft’s transponder. This is a fundamentally different mechanism from ADS-B’s passive broadcast, which means TCAS resolution advisories have natural isolation from ADS-B injection. A ghost aircraft created by this tool has no real transponder and will not respond to TCAS interrogations, so it will not trigger resolution advisories on nearby aircraft. The boundary of risk is therefore at the display and awareness layer rather than the collision avoidance layer. The interaction between ADS-B spoofing and TCAS behavior at the edges. For example, in implementations that use ADS-B for supplemental traffic awareness rather than resolution advisories it is an active area of academic research. Strohmeier et al., “On the Security of the Automatic Dependent Surveillance-Broadcast Protocol” (IEEE Communications Surveys, 2015) covers this boundary in detail for readers who want to go deeper.

For the space domain, the relevance of this research is documented rather than speculative. CCSDS, the Consultative Committee for Space Data Systems, defines the dominant protocol suite for spacecraft telemetry. The baseline CCSDS telemetry specification does not include authentication. CCSDS 350.0-G-3, the Green Book on space data security, explicitly describes authentication as an optional add-on layer rather than a baseline requirement. The SPARTA framework, maintained by The Aerospace Corporation and published at sparta.aerospace.org, catalogs authentication weaknesses and link-layer attacks as documented threat vectors against spacecraft, the same class of vulnerability demonstrated here against ADS-B. Pavur and Martinovic’s “A Tale of Sea and Sky” (IEEE Security & Privacy, 2020), while focused on maritime satellite links, demonstrated live interception and manipulation of broadcast telemetry and noted the broader applicability to space link security. The specific techniques in this project, understanding frame structure, computing valid checksums, and injecting crafted messages that pass receiver validation, are the same primitives that appear in space link attack research. The protocols are different, but the attack surface is structurally similar.

It is important to note that this is not a novel observation. The aerospace security community has been aware of these vulnerabilities for years. What this project contributes is a concrete, working demonstration of the attack mechanics using an accessible protocol, with the explicit goal of informing defensive approaches.


What’s Next

This is the first tool in what I’m building out as an ADS-B security research platform. Two more posts are in progress:

Capture and Replay: A tool that connects to port 30002, decodes live aircraft messages in real time, and lets you modify any field before re-injecting the modified message. Clone an aircraft’s identity, shift its reported position, change its squawk. This is the manipulation side of the research.

Sky Writer: A tool that converts a text string into a formation of ghost aircraft that spell out the text on the SkyAware map. Each lit pixel in a 5×7 bitmap font becomes one stationary ghost aircraft positioned at a calculated lat/lon offset. Frivolous, but a good demonstration of coordinated multi-aircraft injection at scale. And it’s fun. That’s important. Again.

If you want to understand the implementation in detail,the CPR math, the Q-bit altitude encoding, the bit packing for each message type, the source code is heavily commented and structured to be readable as a learning resource. The GitHub repo is the companion to these posts. Also see the next section for reading I had referenced while making this tool.


References and Further Reading

Primary Sources

  • ICAO Doc 9684Technical Provisions for Mode S Services and Extended Squitter: The official specification. Dense and dry but authoritative. The ultimate reference for message formats, encoding schemes, and protocol behavior.

  • The 1090 Megahertz Riddle by Junzi Sun — mode-s.org/1090mhz: The most readable technical reference on ADS-B available. Covers every message type with clear explanations and worked examples. Essential reading before implementing any ADS-B tooling.

  • ADS-B Spoofing by STERVA — blog.exploit.org/tag/ads-b: A foundational writeup on CPR encoding and ADS-B spoofing that provided a significant portion of the practical knowledge underlying this project. Highly recommended.

  • “On the Security of the Automatic Dependent Surveillance-Broadcast Protocol” by Strohmeier, Lenders, and Martinovic — IEEE Communications Surveys & Tutorials, vol. 17, no. 2, 2015 — doi:10.1109/COMST.2014.2365951: Comprehensive security analysis of ADS-B covering attack vectors including ghost injection, identity spoofing, and TCAS interaction.

  • “Experimental Analysis of Attacks on Next Generation Air Traffic Communication” by Schäfer et al. (2013) https://lenders.ch/publications/conferences/acns13.pdf: Practical analysis of attacks against ADS-B and related protocols including TCAS interaction. Cited for its treatment of the boundary between ADS-B spoofing and collision avoidance system behavior.

Tools and Libraries

This Project


Questions, corrections, or collaboration inquiries: feel free to reach out.