Something From 5G: Baseband Security Research Toolkit
Every baseband enabled device ships with two computers, the one you interact with, and the one that quietly interfaces with the network on your behalf. That second one - the baseband - is usually the least visible part of the device and, arguably, one of the most critical.

Introduction
Over the past few years baseband research has finally started to get some airtime. Work like 5ghoul has shown again and again that bugs in the baseband can be pretty nasty. But reading through disclosure after disclosure, there are a few recurring patterns that have, for a long time, really badly bugged me:
- The research and attacks are typically based on the attacker having a rogue base station (gNB) or access to the infrastructure.
- The attacks are demonstrated in a very controlled lab setting with one or two UEs.
- There is an assumption that the target UE will connect to the rogue base station, which is actually much much much more difficult to do than it is made out to be.
- Does any of this baseband security research even matter if it requires the attacker to have control of the infrastructure?
Something From 5G (SF5G) toolkit is my attempt to create baseband security research tooling that would work outside of a controlled lab setting. It is built on top of a modified OpenAirInterface 5G stack, with a strong bias towards real-world use. It is a project that utilizes all of my baseband security research work from the past 4 years.
Why build a toolkit?
If you read the Baseband fuzzing on budget posts, you have already seen the other side of the problem: you can get pretty far with open source RAN stacks and some fuzzing harnesses. But even in those setups, the visibility you get into the actual RF side is surprisingly thin. Let’s address the elephant in the room: if you don’t control the infrastructure, you have zero visibility. And all of the current research is assuming attacker‑controlled infrastructure.
This leaves a gigantic gap: real-world reproducibility. You find a cool baseband exploit that really badly crashes the device. Does it really matter? What hoops would a real‑world attacker have to jump through to get your UE to detach from its current network, attach to the attacker‑controlled one, and allow the attacker to exploit the vulnerability? Is it even possible to exploit in the real world? These are questions I feel like no one is asking.
SF5G is very much a “tool I wanted for myself” that has now grown to the point where it makes sense to publish it and hopefully get others to contribute to it.
What is SF5G?
Strong disclaimer: 5G operates in licensed frequency spectrum, so you either need a license to experiment or an appropriately shielded environment. Anything from this point forward assumes a private licensed 5G network or authorized access to a telco network.
SF5G is a modified OpenAirInterface stack that bolts the 5G NR gNB and UE softmodems into a single, dual‑radio binary, and allows processing of both the UL and DL links in the network simultaneously.
At a very high level:
- One radio acts as a downlink (DL) anchor. It behaves like a UE: locks on SSB/PBCH, decodes MIB/SIB1, follows CORESET0/PDCCH, and keeps track of how the live cell is configured.
- The other radio acts as an uplink (UL) monitor. It uses the live gNB configuration and timing derived from the DL side, and passively listens for PRACH, Msg3 PUSCH, and early UL traffic.
And then there is a GUI, a glorious GUI for finally being able to do things without modifying Python scripts.
SF5G also features a very comprehensive logging path (sniffer.log JSONL + binary dumps) to expose the guts of the RX/TX pipeline: channel estimates, DMRS grids, equalizer state, LDPC outcomes, and all the little bits you normally never get to see.
The goal is not to build another single‑use Python tool but to provide a nice scaffold for others to improve on and to enable real-world research on baseband.
SF5G focuses on:
- Pre‑authentication and early attach traffic – before AS/NAS security kicks in.
- Control and early data channels – RACH, Msg3, RAR, initial RRC/NAS cleartext.
- Rich metadata – RNTIs, TA, MCS, TBS, HARQ, per‑symbol/per‑PRB channel taps, LLRs, LDPC diagnostics.
- Real-world RF environment – built for experimenting with real devices in a real-world environment.
- Passive sniffing – the transmit path and selective jamming capabilities are deliberately left out for the first release.
After NAS, when the UE and network start encrypting communications, SF5G continues to monitor the unencrypted control channel traffic where possible.
High‑level architecture
Under the hood SF5G is OpenAirInterface with a fair bit of plumbing and instrumentation:
- The base OAI tree and build system are still intact.
- A small number of sniffer‑specific modules wire the dual radios into a single process and hook into the existing OAI PHY/MAC layers.
- A configuration layer (
sniffer_config) and a dual‑radio coordination layer (sniffer_dual) abstract away the details like radio synchronization and configuration. - A pile of logging and post‑processing tools turn binary dumps into something you can reason about.
The high-level functionality is split in the following way:
-
DL anchor (Radio 1 - Master, UE‑like)
- Listens for SSB, locks onto the cell, and decodes PBCH (MIB).
- Follows SIB1 to learn CORESET0, search space, slot structure, numerology and other configuration parameters.
- Tracks PDCCH/DCI, extracts RAR assignments, Msg3 grants, Msg4, and RNTIs.
- Exposes all of this as a clean configuration/timing feed to the UL side.
-
UL monitor (Radio 2 - Slave, gNB‑like)
- Uses the DL‑derived timing and numerology to schedule UL slot captures.
- Performs channel estimation using the reference signals with the DL‑side inferred timing.
- Adds a layer of heuristics to account for jitter and timing differences from not having the real gNB timing information.
- Runs a PRACH energy detector that logs every Msg1 sighting with slot/frame/RA occasion context.
- Once Msg2/TC‑RNTI appears on the DL, schedules the corresponding Msg3 PUSCH capture and snaps a slot‑sized IQ buffer around the expected transmission, with timing‑advance‑aware guard bands.
- Feeds the captures into a modified, re‑wired copy of the OAI gNB demod + decode path.
-
Instrumentation and GUI
- The decoder side logs everything that is even remotely useful into
sniffer.log: DMRS grids, channel taps, equalizer state, LDPC segment handling, CRC outcomes, RNTI transitions, and a lot of “what was I thinking” debug. - ImScope (the built‑in GUI) can tap into the same buffers and show live:
- DL/UL spectrums and constellations
- Equalized and non‑equalized grids
- Channel responses per antenna and per symbol
- Slot‑level timing deltas and CFO estimates
- LLR decisions
- The decoder side logs everything that is even remotely useful into
-
Offline tooling
- Binary IQ dumps (
sniffer_*.bin) and small JSON manifests are written alongside the logs whenever detailed debugging is enabled. - Python helpers under
tools/sniffer/andutils/can:- Plot LLRs, compare them against gNB ground truth, and sanity‑check the LDPC layout.
- View raw IQ/constellation/PSD slices to debug RF issues.
- Regenerate rate‑matched code blocks for Msg3 offline using the same encoder/LDPC path as OAI (
sniffer_msg3_rm_dump).
- Binary IQ dumps (
Hardware
In its current form SF5G is tuned around the following setup:
- Two Nuand bladeRF 2.0 Micro xA4 SDRs
- One acts as the master/DL anchor (Radio 1).
- One is the slave/UL monitor (Radio 2).
- Common time/frequency base
- A GPSDO provides a 10 MHz reference to the master.
- The master forwards a 38.4 MHz clock to the slave via the bladeRF clock out/in.
- A trigger line (J51‑1) is used to start UL captures in a deterministic way.
It is possible to adapt the system to different SDRs, but you’ll need to redo the low‑level driver work and timing plumbing.
For TDD‑based deployments a single radio can be enough, but for FDD two radios are a must, as pretty much all of the commercial SDRs are MIMO. Meaning the RX/TX ports run off the same LO, resulting in the inability to tune the ports to different frequencies.
Based on my experiments, two radios are the best alternative even for TDD as that allows a fully segregated gain control, bias-tee and different antenna setups.
Software
The bulk of the tree is unmodified OpenAirInterface. The interesting bits live in a small set of files:
common/sniffer_config.[ch]
- Tiny, thread‑safe configuration store.
- Seeds defaults from environment variables, CLI arguments, and the GUI.
- Provides convenient getters so that the UE/UL paths do not poke global state directly.
common/sniffer_dual.[ch]
- Manages shared state for the dual‑radio path:
- Captured IQ buffers and their metadata.
- Frame/slot tags and timestamp deltas.
- GUI log ring and gain/restart/shutdown flags.
openair1/PHY/NR_UE_TRANSPORT/nr_prach_sniffer.c
- PRACH energy detector that:
- Learns the PRACH layout from the live cell.
- Marks Msg1 hits with enough context to later tie them to Msg3 and beyond.
openair1/PHY/NR_UE_TRANSPORT/nr_ul_sniffer.[ch]
- Schedules Msg3/PUSCH candidates based on DCI from the DL.
- Copies slot‑sized IQ windows with timing‑advance‑aware guard bands.
- Hands immutable IQ snapshots off to the decoder.
openair1/PHY/NR_UE_TRANSPORT/nr_ul_decoder_sniffer.c
- Re‑uses the gNB PUSCH demodulation pipeline to:
- Apply coarse and fine CFO correction.
- Build DMRS‑based channel estimates and equalize the grid.
- Run LDPC decoding and probe TB CRCs.
- Mirrors all interesting intermediate buffers to the GUI and logs them to
sniffer.log.
executables/sniffer_msg3_rm_dump.c
- Offline helper that reconstructs Msg3 code blocks identically to what the real UE pipeline would have produced, making LLR/TB comparisons easier to do.
tools/sniffer/ and utils/sniffer_iq_view.py
- Python helpers for:
- Visualizing IQ/constellation/PSD and sanity‑checking timing.
- Comparing sniffer‑side demodulation against gNB ground truth.
- Instrumenting and debugging the Msg3 pipeline.
In other words, SF5G attempts to use the stock OAI stack where possible by only gluing the two radios into a single process, exposing all the useful internal state for debugging and analysis and making the LDPC/code-block side of early UL traffic observable.
How this fits into the bigger picture
SF5G is designed to play nicely with the rest of the baseband tooling I have been building over the years. For example, the ZMQ‑based fuzzing harnesses from the Baseband fuzzing on budget series can be wired into SF5G so you can easily mutate selected PDUs.
SF5G attempts to fill in the gap on the real-world observability by enabling the possibility to move away from a typical bench setup and perform real-world testing.
Current limitations and future work
This is an early release. A lot of things are already useful, but there are also plenty of rough edges:
Passive, receive‑only sniffer on purpose
- The focus is on UL/DL sniffing and decode. Tx is disabled in this initial release.
bladeRF‑centric
- The dual‑radio path is only implemented and tested on bladeRF 2.0 Micro.
- Support for other SDRs is possible, but someone needs to add that support.
Msg3 decoding is flaky
- After my recent large refactor of the codebase to use two radios, something went sideways on the demapping.
On the roadmap:
More clever PRACH energy detector
- Capturing PRACH over longer distances introduces everything from multipath to noise.
- Revisit the PRACH detection to account for various channel conditions
Better channel estimation and code-block heuristics and instrumentation
- More robust code-block handling.
- Cleaner mapping between TB bytes and over‑the‑air resources.
Richer GUI
- Streamline the views for common debugging tasks.
- Easier navigation between events and scopes.
Integrating my other existing tooling, like selective reference signal jamming and fuzzing hooks
- Tools to force the UEs through controlled state transitions.
- Integration with the existing ZMQ/Python fuzzing harnesses and payload delivery without having to recompile code.
- End‑to‑end pipeline: sync to cell, selectively jam a UE back into attach, passively observe RNTIs and early traffic, then deliver a mutated payload
Closing thoughts
Baseband security research is one of those areas where the barrier to entry is in my opinion artificially high, not because the concepts are inherently impossible, but because the tooling keeps getting in the way. A lot of the work that went into SF5G has been about lowering that barrier and bringing the real-world into the research.
SF5G is very much a living project. There are bugs, missing features, and lots of “TODO: make less ugly” comments in the code. But it is also already useful enough that it has been the backbone of my own baseband experiments for quite some time.
If you end up using SF5G in your research, I’d be genuinely curious to hear what you build on top of it – whether that is integrating it with fuzzers, new analysis tools, or completely different applications that benefit from having a 5G UE/gNB hybrid you can poke at.
Enjoy!



