DOCUMENTATION / PART 5 — TECHNIQUE REFERENCE5.9

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.