5.9 Traffic, jamming and interception
The last family before the kits is the one that treats the network as a system rather than as a protocol: what the traffic looks like in aggregate, what it looks like when somebody interferes with it, what it looks like when somebody is lawfully intercepting it, and how to run a sequence of the above.
5.9.1 Traffic analysis and call fingerprinting
Need: a capture. Packet-level identification answers "who"; traffic analysis answers "what were they doing", and it does so without reading a single payload.
modules/23_traffic_analysis.sh --flows captures/ue.pcap 1 # per-flow table
modules/23_traffic_analysis.sh --features captures/ue.pcap 0 1
modules/23_traffic_analysis.sh --calls-tsv captures/ue.pcap 1 # call table, media grouped
modules/23_traffic_analysis.sh --fingerprint-add whatsapp ref.pcap
modules/23_traffic_analysis.sh --classify captures/ue.pcap 3
modules/23_traffic_analysis.sh --refs-tsv
The flow table carries the columns that make classification possible: packets and
bytes each way, duration, mean size, burst count, maximum idle gap, and a
shaping verdict. --calls-tsv groups media streams into calls, which is the
step that turns anonymous UDP into a conversation with two ends and a duration.
What you read: per flow, the shape of the conversation; for --classify, the
top-k matches and the reference set size — the module refuses to classify against
an empty set (no fingerprints stored) rather than returning a confident
nothing.
When it refuses: a non-numeric idle threshold; an empty reference store.
Read next: §5.7.4 for the RF-layer equivalent, and §5.6.2 for the voice service this analysis is looking at.
5.9.2 Detecting jamming
Need: an IQ recording. Jamming is the one attack that cannot be defeated cryptographically, so the useful work is telling it apart from congestion and from a hole in coverage.
modules/33_jamming_detect.sh --fixture clean /tmp/j.f32 # a known-clean recording
modules/33_jamming_detect.sh --analyse /tmp/j.f32 cf32 2000000 # features, saved as the record
modules/33_jamming_detect.sh --noise-floor /tmp/j.f32 cf32 2000000
modules/33_jamming_detect.sh --characterise /tmp/j.f32 cf32 2000000 20 # narrowband vs barrage
modules/33_jamming_detect.sh --counters counters.txt # merge receiver counters
modules/33_jamming_detect.sh --discriminate # jamming / congestion / coverage hole
modules/33_jamming_detect.sh --report # regulatory report (jamming only)
--discriminate is the verb that matters: jamming raises the noise floor without
raising the error rate in the way congestion does, and a coverage hole raises
neither. The module reports which of the three the evidence supports, and
--report produces a regulatory-shaped document only when the verdict is
jamming — because filing a jamming report about congestion is how an operator
stops believing reports.
What you read: noise floor over time, the characterisation (narrowband or barrage, bandwidth, duty cycle), and the verdict with its evidence.
When it refuses: an IQ file whose format or rate does not match the declared
ones; --discriminate with no record to discriminate on.
Read next: §5.3.2, since overshadowing uses the same physical lever deliberately.
5.9.3 Lawful interception from the outside
Need: nothing for the reference; signalling events for the score. Interception interfaces are documented in TS 33.108 and the documentation is the interesting part: what an operator must be able to deliver says a lot about what exists.
modules/42_li_probe.sh --interfaces # X1/HI1, X2/HI2, X3/HI3 — who talks to whom
modules/42_li_probe.sh --iface X2 # one interface in detail
modules/42_li_probe.sh --architecture # ADMF/POI/DF2/DF3/LEMF roles
modules/42_li_probe.sh --score events.tsv # interception-posture score over signalling
modules/42_li_probe.sh --li-pdu-build # wrap a product in a delivery header
modules/42_li_probe.sh --li-pdu-parse <hex>
modules/42_li_probe.sh --report # what to record and where to escalate
The distinction the module keeps sharp: X2 carries IRI (who called whom, when),
X3 carries content. A posture score built only from signalling can say whether an
interception is likely active against a subscriber, and cannot say what was
said: the module's own --status-tsv lists what its PDU model does not cover,
so a report cannot drift into claiming content.
What you read: the interface map, the roles, and a score with the events behind it.
When it refuses: a PDU whose header is not the expected delivery header; a score run with no events.
Read next: §5.4.2, since SS7 is where most real interception capability is provisioned.
5.9.4 The user-plane integrity gap
Need: nothing. This is a single fact with a large blast radius, and it gets its own page because three other techniques depend on it.
modules/29_mac_layer.sh --integrity-gap
# integrity user_plane DRB integrity no no MAC-I over DRB payloads; ...
modules/29_mac_layer.sh --decode-mac <hex> [dl|ul] # an LTE MAC PDU, subheader chain
modules/29_mac_layer.sh --lcid-table # TS 36.321 6.2.1-1 / -2
modules/29_mac_layer.sh --rnti-table # the RNTI space and reserved values
modules/29_mac_layer.sh --rnti-track <pcap> # RNTI/LCID evidence across a capture
modules/29_mac_layer.sh --sched-pattern <pcap> # scheduling pattern
LTE ciphers the user plane but does not integrity-protect it (TS 36.323 6.2), so a flipped ciphertext bit decrypts to a flipped plaintext bit with nothing at the receiver to notice. NR closed this for signalling; the user plane story is configuration-dependent, which is why the module prints the plane, the bearer and the clause rather than a single "protected or not".
What you read: the gap table with its sources, the subheader chain of a MAC PDU, and per capture the RNTI/LCID evidence that identifies which bearer a payload belonged to.
When it refuses: an LCID it has no table entry for is reported as unknown, not mapped to the nearest neighbour.
Read next: §5.4.4 and §5.6.2, the two techniques that ride on this gap.
5.9.5 Chains and fleets
Need: whatever the steps need. A single technique rarely answers a question; a sequence of them does, and the toolkit has two ways to sequence: a chain run on this host, and a fleet of hosts the modules can read from.
modules/25_killchain.sh --list-chains # every chain, with step and hardware counts
modules/25_killchain.sh --show-chain survey # resolve the steps without running them
modules/25_killchain.sh --run survey --dry-run # what would happen
modules/25_killchain.sh --run survey --keep-going # run it, continuing past failures
modules/25_killchain.sh --pause # cooperative pause between steps
modules/25_killchain.sh --resume # resume from the checkpoint
modules/25_killchain.sh --run-multi gsm-sweep bands.tsv # once per first-column target
modules/59_remote_node.sh --list-tsv # every node, its class and its last sighting
modules/59_remote_node.sh --probe van-1 # ONLINE / OFFLINE / UNKNOWN
modules/59_remote_node.sh --dispatch van-1 02_cell_recon --scan lte 20
modules/59_remote_node.sh --stream van-1 --follow 5
--show-chain before --run is the habit worth forming: a chain that needs
hardware should be inspected, and --run --dry-run prints the resolved commands
without executing them. --pause/--resume exist because a chain that touches a
radio should be interruptible without losing its checkpoint.
For fleets, --dispatch runs a module verb on another host and returns its
output, and --list-tsv keeps the honesty column: a node is ONLINE, OFFLINE
or UNKNOWN, and UNKNOWN is a distinct state (the node has never been probed),
not a synonym for offline. --stream drains that node's spool from this side's
cursor, which is how a survey from a remote receiver arrives without a shared
filesystem.
What you read: the chain definition and its hardware count; for a run, per-step outcomes; for a fleet, per-node status with the reason for it.
When it refuses: --run on a chain whose hardware steps cannot be satisfied
reports which step and why; --dispatch to an offline node reports the
transport's failure rather than a timeout that looks like a hang.
Read next: §5.10 for the kits that catalogue what these chains are aimed at.