5.4 What the core says about a subscriber
The air is only half of a mobile network. The other half is a set of protocols that were designed in an era when the only people who could reach them were carriers, and most of them still behave that way. Every technique in this family runs on a laptop, none of them needs a radio, and all of them need something you cannot get from a manual: an address, a port, a credential, or a lawful reason.
The toolkit's position on all of them is the same — it builds and parses the messages and does not send them at a network it was not pointed at. The verbs that would open a socket are marked as such in Part 4 and refuse without an explicit target.
5.4.1 Ask a core about a subscriber over S6a
Need: nothing for the messages; a reachable core for an answer. Diameter S6a is the interface between an MME and a home subscriber server, and four of its requests are enough to learn almost everything about a subscriber.
modules/11_lte_core.sh --build-air 310150123456789 # Authentication-Information-Request
modules/11_lte_core.sh --build-ulr 310150123456789 # Update-Location-Request
modules/11_lte_core.sh --build-clr 310150123456789 # Cancel-Location-Request (317)
modules/11_lte_core.sh --decode-diameter <hex> # walk a Diameter message and its AVPs
modules/11_lte_core.sh --decode-gtp-c <hex> # GTP-C v2 header and IEs
modules/11_lte_core.sh --gtp-csr-forge 310150123456789 internet 310 260
--build-air produces the Authentication-Information-Request an MME would send:
the IMSI, the number of vectors, the serving network. --build-clr produces the
Cancel-Location-Request, which is the interesting one defensively, because it is
how a subscriber gets detached from a network they are actually attached to.
--decode-diameter and --decode-gtp-* are the read direction: they name every
AVP, its vendor and its type, so a captured message is legible without a
protocol analyser licence.
What you read: for a built message, the command code, application id and every AVP; for a decoded one, the same in the other direction, with the fields that carry the subscriber identity called out.
When it refuses: a malformed Diameter header is refused by length; a hex string that is not GTP-C v2 is refused with the version it found.
Read next: §5.4.2 for the SS7 equivalent, which is older and still carries the same question.
5.4.2 Anywhere lookups over SS7 and MAP
Need: nothing for the messages; an SS7 network you are authorised to touch. Mobile Application Part is how a network asks "where is this subscriber" — and the reason SS7 is still a finding in 2024 is that the question has no authentication behind it.
modules/26_ss7_map.sh --build-sri 15551234567 # SendRoutingInfo, wire-ready MSU
modules/26_ss7_map.sh --build-sri-sm 15551234567 # the SMS variant
modules/26_ss7_map.sh --decode-map <hex> # decode MAP, unwrapping MSU or SCCP
modules/26_ss7_map.sh --decode-tcap <hex> # the transaction and its components
modules/26_ss7_map.sh --decode-msu <hex> # MTP3 and SCCP underneath
modules/26_ss7_map.sh --dialogue <req> <ans> # pair a request with what a peer sent back
modules/26_ss7_map.sh --build-response <kind> # the peer's side, for a lab
--dialogue is the verb that makes this module teach rather than merely encode:
it takes the request you built and the answer you captured and reports whether
the pair is consistent — the opcode matches, the invoke ids line up, the answer
is to that question. That comparison is also what tells you whether you are
looking at a real answer or at a lab fixture.
--build-response exists so both sides of a dialogue can be produced offline,
which is what a lab needs and what a manual about attacks should demonstrate
without a live SS7 link.
What you read: the operation (SRI, SRI-SM, PSI, ATI), the identity it carries, and for a response the routing information the network was willing to give.
When it refuses: an MSISDN that will not encode (a 15-digit IMSI is not an
MSISDN — the verb says cannot encode MSISDN and prints what it got).
Read next: §5.9.3 for the lawful-intercept interfaces that sit on the same network, and §5.10.1 for the kit that catalogues GSM-side SS7 exposure.
5.4.3 The 5G service-based architecture and its NRF
Need: nothing for the messages and paths; network reachability for discovery. The 5G core replaced point-to-point interfaces with an HTTP/2 service mesh, in which the NRF is a directory of every function in the core.
modules/13_nr_core.sh --nf-list # every NF with its real API root
modules/13_nr_core.sh --nf-discovery AMF # what an NRF would return
modules/13_nr_core.sh --decode-ngap <hex> # NGAP procedure and name
modules/13_nr_core.sh --decode-pfcp <hex> # PFCP message type, SEID, sequence
modules/13_nr_core.sh --decode-5g-guti <hex> # PLMN, AMF region/set/pointer, 5G-TMSI
modules/40_sba_pivot.sh --nrf amf # the NRF discovery request itself
modules/40_sba_pivot.sh --nf-paths # SBI service paths
modules/40_sba_pivot.sh --hpack <hex> # decode HPACK header blocks
modules/40_sba_pivot.sh --h2-parse <hex> # HTTP/2 frame header
modules/40_sba_pivot.sh --settings <hex> # SETTINGS payload
The reason this is one family and not five pages is that the attack surface is a
single shopping list: an NRF that answers unauthenticated discovery is a map of
the core, and every NF in that map speaks HTTP/2 with HPACK-compressed headers
that most capture tools display as binary. 40_sba_pivot reads that layer
directly, which is what makes a captured SBI exchange legible.
What you read: the NF types present, their API roots, and — the important
part — whether the discovery answer was conditional on the requester's identity.
A target-nf-type=amf request that returns every AMF is a finding; one that
returns nothing without credentials is the control working.
When it refuses: an unknown NF name (the verb wants a registered type such as
AMF, SMF, NRF, or a service name); an HTTP/2 frame shorter than nine
octets.
Read next: §5.4.5 for what the slice identifiers in these messages mean, and §5.10.3 for the kit that catalogues SBA exposure.
5.4.4 Cellular DNS and the aLTEr lever
Need: a capture. In an LTE network, DNS is the only plaintext application traffic the user plane carries by default, and the reason that matters is narrow: an attacker who can rewrite a DNS answer can redirect the user to their own server without breaking any cipher.
modules/27_cellular_dns.sh --build-query example.com A
modules/27_cellular_dns.sh --decode-dns <hex>
modules/27_cellular_dns.sh --resolver-discovery captures/lte.pcap # which resolver the bearer used
modules/27_cellular_dns.sh --detect captures/lte.pcap # rewrite and spoofing signals
modules/27_cellular_dns.sh --alter # the aLTEr sequence, step by step
modules/27_cellular_dns.sh --pco <hex> # walk protocol configuration options
--alter walks the published aLTEr sequence and, more usefully, states its
preconditions: user-plane integrity protection is not enabled in LTE, DNS is
unprotected, and the attacker must be able to rewrite a packet in flight while
leaving the cipher's counters consistent. --detect looks for the artefacts
that sequence leaves — answers that differ from a second vantage point, TTLs that
do not fit the resolver's pattern, a response whose size contradicts its
question.
What you read: the resolver the bearer actually used (it is often not the one the operator documents), and for an altered exchange, which of the signals fired.
When it refuses: a DNS message with a truncated name or a compression pointer that loops; a pcap with no DNS at all reports zero exchanges.
Read next: §5.9.4 for the integrity gap under this technique, and §5.6.2 for the voice equivalent.
5.4.5 Slice selection
Need: nothing. Network slicing is sold as isolation, and the question a security review asks is whether selection actually enforces it.
modules/34_slicing.sh --sst-table # standardised SST values, with sources
modules/34_slicing.sh --encode-s-nssai 1 # S-NSSAI octets for a slice
modules/34_slicing.sh --decode-s-nssai 01000001 # back again, with the SST name
modules/34_slicing.sh --selection 01 01,02 # requested / allowed / rejected outcome
modules/34_slicing.sh --isolation-check <pcap> # isolation evidence, and what it cannot show
modules/34_slicing.sh --detect <slice-events.tsv> # session-level slice anomaly rules
--selection is the verb worth reading: given what a handset requests and what
the network allows, it computes which slice the session lands in and why —
including the case where a rejected slice falls back to a default one, which is
the failure mode that turns isolation into a label. --isolation-check is
deliberately bounded: it reports evidence of shared resources and states plainly
that absence of evidence in one capture is not isolation.
What you read: the SST/SD pair, its standardised meaning, and the selection outcome; for a capture, which slices appear on which bearers.
When it refuses: an S-NSSAI whose declared length is not 1 or 4 (TS 24.501),
an SST outside the standardised table reported as unknown rather than guessed.
Read next: §5.4.3, where slices are requested in the first place, and §5.10.3 for the slicing findings in the 5G kit.
5.4.6 NAS at scale
Need: a capture. One NAS message is an event. Ten thousand of them is a posture: which procedures a network actually runs, which causes it returns, and whether it is under load.
modules/32_nas_signaling.sh --rate <pcap> # messages per second and per procedure
modules/32_nas_signaling.sh --procedure-mix <pcap> # distribution, and the reject share
modules/32_nas_signaling.sh --causes <pcap> # cause-code distribution
modules/32_nas_signaling.sh --storm-profile <pcap> # signalling-storm detection
modules/32_nas_signaling.sh --decode-nas eps <hex> # one message, header and cause
modules/32_nas_signaling.sh --build-nas 5gs registration-request
modules/32_nas_signaling.sh --cost-model # documented cost of each load pattern
The reject share is the single most informative number: a network whose attach
attempts are 40% rejected is either misconfigured or being steered, and the
cause distribution usually says which. --cost-model exists so that a load
figure can be quoted with the resource it consumes rather than as a bare rate.
What you read: rates, mixes, causes, and a storm verdict with the thresholds that produced it.
When it refuses: a capture with no NAS (an empty user-plane capture, say) reports zero messages rather than a zero rate that looks like health.
Read next: §4.13's windows for the live view of the same counters, and §5.6.1 for the attach procedure these messages belong to.