5.3 Standing up a cell of your own
A catcher asks a question. A rogue cell changes the answer. Everything in this family is a way of being a network the handset will believe — and every one of them has the same cost: a real radio, a licence you do not have unless you are in a shielded room or hold one, and a plan file you should read before you key anything.
Two modules in this family are unusual in the toolkit because they are honest
about being unfinished: 57_evil_twin and 60_overshadow both have a
preflight that reports every remaining precondition rather than starting and
failing later.
5.3.1 The evil twin
Need: a survey (§5.1.6) to clone, and a radio to radiate.
modules/57_evil_twin.sh --prepare-lte loot/cell_recon/cells.tsv 3 --pci 42 --out loot/evil-twin
modules/57_evil_twin.sh --preflight-lte loot/evil-twin # what the twin still needs
modules/57_evil_twin.sh --run-lte loot/evil-twin 120 --radiate --with-capture --iface lo
modules/57_evil_twin.sh --evidence-collect loot/evil-twin --rat lte --run twin-1
modules/57_evil_twin.sh --evidence-tsv --run twin-1
--prepare-lte reads one row of a survey and writes a configuration directory
in which every field is traceable to that row: the PLMN, the TAC, the cell
identity, the EARFCN. --preflight-lte is the interesting verb — it lists what
is missing (a core, a radio, a key) and refuses to start until each is
satisfied, which is the difference between a lab exercise and a failed
transmission.
--evidence-collect has the honesty property the whole module is built around:
each evidence row is marked observed or advertised. An advertised row is
what the twin claims (the PLMN it broadcasts, the EARFCN it sits on); an
observed row is what a real receiver or a real handset actually did (attached,
sent an IMSI, sent an IMEI). A run that produced six advertised rows and no
observed rows is a run where the twin radiated and nobody believed it.
What you read: the evidence table, with the confidence column deciding what you may claim. The twin-feed window (§4.13.6) draws both kinds, with the advertised rows visibly worn.
When it refuses: every verb needs a prepared directory and says which; a
missing radio is listed by --preflight-* rather than discovered at transmit
time.
Read next: §5.3.2 for what to do when the handset refuses to attach, and §5.2.6 for how the same twins are detected.
5.3.2 Overshadowing and AdapOver
Need: a radio, and a plan. Overshadowing is the technique of making a legitimate cell unreadable at the moment a message must be read, so that the handset takes a signal you sent instead. It does not break ciphering; it removes the message that would have told the handset to distrust you.
modules/60_overshadow.sh --info # what this module does and refuses to do
modules/60_overshadow.sh --needs # bill of materials (b210, b205mini, x310, pluto)
modules/60_overshadow.sh --timing-budget # receive instant to transmit instant vs 2 ms and CP
modules/60_overshadow.sh --power-budget # required power and range for ul / dl modes
modules/60_overshadow.sh --subframe-map <tsv> # which subframe and RBs carry which message
modules/60_overshadow.sh --plan <target> # sample-indexed schedule
modules/60_overshadow.sh --collateral # what breaks around the target
modules/60_overshadow.sh --detect <tsv> # unscheduled TB, SIB change without paging, drift
--timing-budget and --power-budget are the two pages to read before believing
anybody's claim about this technique, including this module's. Overshadowing is
a deadline problem (the replacement must arrive inside a window measured in
microseconds) and a power problem (the replacement must be louder than the cell
it replaces at the handset, not at your antenna). Both verbs print the arithmetic
and the margin, and neither claims a plan will work — --plan produces a
schedule, and the module says in its own --info that it plans and does not
key.
--collateral is the honest part: a downlink overshadowing degrades the whole
cell, an uplink one degrades one grant. --detect is the defensive use of the
same knowledge: an unscheduled transport block, a SIB change without a paging
message, or a schedule that drifts are all evidence that somebody is doing this.
What you read: the budget pages for feasibility, the plan for a schedule, and
--detect for evidence.
When it refuses: --needs prints what hardware would work; every radiating
verb refuses with no radio.
Read next: §5.1.3, because paging timing is the mechanism this technique disturbs, and §5.7.3 for its tracking variant.
5.3.3 Force a downgrade with a reject
Need: nothing to build, a radio to radiate. The cheapest downgrade is a message the handset is required to believe: a reject with a cause code that sends it somewhere the attacker controls.
modules/15_downgrade.sh --reject-cause 15 EMM # what cause 15 means, from the spec table
modules/15_downgrade.sh --build-reject EMM 15 attach # the NAS message to send
modules/15_downgrade.sh --tx-reject EMM 15 attach # build it and put it on the air
modules/15_downgrade.sh --build-security-mode EEA0 # advertise no ciphering at all
modules/15_downgrade.sh --null-cipher-table # A5-0/UEA0/EEA0/NEA0 across generations
modules/15_downgrade.sh --detect <pcap|records.tsv> # find steering rejects in existing traffic
modules/15_downgrade.sh --path <name> # describe a downgrade mechanism
The cause table is worth knowing by heart if you work on the defensive side:
cause 15 ("No suitable cells in tracking area") steers a handset to another RAT,
cause 22 ("Congestion") makes it retry later, and the security-mode variants
propose a null algorithm. --build-reject produces the octets and --tx-reject
sends them; between the two there is no difference except the radio, which is
why the module separates them — you can prepare and inspect a message on a
machine with no hardware.
--detect is the reverse: it reads a capture or a procedure record and reports
steering rejects, RAT changes without cause, and security modes weaker than both
ends advertised.
What you read: the message and what a handset must do on receiving it;
--detect for the same pattern in traffic that already exists.
When it refuses: an unknown RAT string, a cause code outside the table, a transmit with no radio.
Read next: §5.1.4 for why a null cipher is the point of the exercise, and §5.2.1 for the catcher that follows it.
5.3.4 A femtocell's own management plane
Need: nothing to build a profile; a network path for the management verbs. Small cells are the highest-value rogue target in a real deployment, because they are an operator-managed box on a consumer-grade network.
modules/37_femtocell.sh --csg-encode 12345678 # 27-bit CSG id
modules/37_femtocell.sh --cell-profile 310260 2 2500 1 # PLMN, band, EARFCN, PCI
modules/37_femtocell.sh --sib9 home-node-1 # the SIB that publishes the HNB name
modules/37_femtocell.sh --discover 10.0.0.5 # what answers on the management plane
modules/37_femtocell.sh --apply 10.0.0.5 # write the profile to it
--cell-profile emits the whole commissioning profile — PLMN, band, EARFCN,
PCI, optional CSG identity and HNB name — which is the document a small cell
takes as its identity. --discover then asks what management surface answers,
and --apply writes the profile to a discovered surface. The two network verbs
are separated from the profile verbs for a reason: building a profile is offline
and safe, applying one is a change to somebody's infrastructure.
What you read: the profile as structured data, and for a live box what it claims about itself. The SIB9 name is often the give-away in a survey: it is whatever the installer typed.
When it refuses: a PLMN that is not 5 or 6 digits (a normalised 310-260 is
refused; the verb wants 310260), a CSG id outside 27 bits, an unreachable
management host.
Read next: §5.1.1 for the broadcast a small cell sends, and §4.13.5 for the live subscriber window the same module feeds.
5.3.5 A rogue cell at the message layer
Need: nothing. Two modules build the messages a rogue cell sends without building the cell: this is the part of the work that can be done entirely on a laptop, and the part that is worth doing before touching a radio.
modules/54_baseband_exploit.sh --forge-reg-accept # 5G Registration Accept, plaintext
modules/54_baseband_exploit.sh --forge-reg-reject 31 # reject with a redirect cause
modules/54_baseband_exploit.sh --forge-identity 1 # identity request by type
modules/54_baseband_exploit.sh --cp-check <hex> # control-plane property check
modules/55_nr_inject.sh --mac-pdu 1 4142434445 # a MAC-NR PDU with a chosen LCID
modules/55_nr_inject.sh --dci-parse <hex> 1_1 106 # decode a DCI against a bandwidth
The reason to separate these from §5.3.1 is that the message is the part that carries the finding. A Registration Accept in the clear is a protocol-level claim about what a core will accept; a MAC PDU with an LCID the scheduler never grants is a claim about what the receiver does with it. Neither needs a transmitter to be worth writing down, and both are refereed by their modules' selftests.
What you read: the octets plus the field-by-field construction
(--l2-build <name> shows how one malformed case is assembled, --l2-case
<layer> selects a layer). --cp-check reports which control-plane properties a
given NAS message violates.
When it refuses: --l2-case with an unknown layer name lists the layers it
knows; --dci-parse with a format it cannot size refuses rather than guessing
the bandwidth.
Read next: §5.10.2 and §5.10.3, which are the same message-level work organised as a corpus.