返回资讯中心
外部精选
软件工程
#开发者实时流

IMSIsting – GTK4 cellular security toolkit for Linux

A GTK4 cellular security toolkit for Linux, with a full CLI behind it. Shell

Hacker News 最新yslxotwod2026/10/28 · 今天30 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

A GTK4 cellular security toolkit for Linux, with a full CLI behind it. Shell modules covering 2G/GSM, 3G/UMTS, 4G/LTE and 5G/NR, plus passive analysis over captures and per-generation CVE kits.

Every module is a standalone script. The GUI is a view over them, not a container — nothing is locked behind the interface.

Early development, and honest about it. No module in this tree has been run against a real radio. There is no SDR on the machine it was built on, so every over-the-air path is written and reviewed but not tested. The section What actually works says exactly which is which, and it is worth reading before you file a bug.

Cellular tooling is split by layer and by generation. gr-gsm is 2G. srsRAN is 4G/5G. Osmocom is the stack underneath. Wireshark dissects what you captured but will not capture it, and none of them share a target view.

This tree is wide on purpose: one desk, one launcher, one place where a cell survey, a NAS decode, a Diameter message and a cipher audit all land in the same TSV.

The other thing it does differently: most tools tell you they worked. This one is built to tell you when they didn't. Every module has a --selftest, the hardware-gated ones name the radio they are missing instead of returning an empty result, and a module that cannot do its job exits non-zero rather than reporting success.

No module has an approval gate. Nothing refuses because a flag or an environment variable was not set first. The retired --i-have-a-lab-and-authorisation, --ack-isolated-lab, LTE_ARMED, NR_ARMED, MAP_ARMED, FEMT_S1_ARMED, SBA_ARMED, BEXP_TX_ARMED, NRJ_TX_ARMED and JAMD_LAB_AUTHORISED are accepted and ignored, so old command lines keep working. bash modules/00_deps.sh --preflight prints the state of the box in one page.

cd native meson setup builddir meson compile -C builddir

Then, from the project root:

sudo ./imsisting.sh # CLI menu ./imsisting.sh --list # module list ./imsisting.sh --index # the module index as TSV ./imsisting.sh --gui # launch the GUI ./imsisting.sh --tui # launch the TUI (modules listed by their menu keys)

Or launch the built binary directly:

./native/builddir/imsisting-gui

The GUI asks for your password per action via pkexec, not once at startup.

Required: GTK4 (4.14+), meson, ninja, a C compiler, python3.

Debian / Ubuntu

sudo apt install build-essential meson ninja-build libgtk-4-dev
python3 python3-numpy python3-scipy

Arch

sudo pacman -S base-devel meson ninja gtk4 python python-numpy python-scipy

Optional but used by specific modules: gnuradio + gr-gsm, srsRAN, Open5GS/free5GC, tshark, pcsc-tools, gpsd, python3-cryptography. 00_deps reports what is present and what is missing, and distinguishes a tool that is installed from a stack that is actually complete.

A decode gives you an identity; the reference tables give you an owner. They are public but not shipped, because they are hundreds of thousands of rows and go stale — run the fetcher once per checkout:

tools/fetch-reference-data.sh # ~2 500 PLMNs, ~6 300 ISPCs, ~67 000 PENs tools/fetch-reference-data.sh --check # what is present, without downloading

Lookups distinguish three states and the toolkit never collapses them: ok (the operator), absent (the register was read and holds no such row — that is the finding), and silent (the table is not on this machine — the answer is unobserved, not negative). 02_cell_recon --status-tsv reports the register under plmn_register; 26_ss7_map --ispc prints owner_state on every lookup.

data/opops/ is the private half: operator-supplied tables for global-title prefixes, cell identity blocks, core address ranges and SMSC identities. The tree ships the loader and the schema, never the contents, and reports a missing file as silent rather than as an empty answer.

The GUI opens on a Dashboard — every module as a card, grouped by category. Click a card and the module opens as its own tab. Six tabs are permanent:

Module tabs appear alongside these and can be closed; the permanent tabs cannot.

Settings → Interface → Theme switches the whole desk between two palettes: Night, the blue-black palette the app was drawn in, and Ember, the same desk one temperature over — near-black surfaces with a warm bias and a single ember accent.

A theme is one stylesheet and it restates colours, nothing else. It is not maintained by hand: tools/gen-theme.py derives it from native/resources/style.css (the base sheet), so a change there reaches both, and a theme that falls behind shows up as a diff instead of as one stale panel. The derivation warms the greys, turns the accent family ember, deepens the surfaces, and deliberately leaves every status hue alone — green still means ok and red still means danger, because a theme that recolours them makes the honest chips lie. GTK's own widgets (entries, popovers, tooltips, switches) are restated at the end of the generated file, since the base sheet never spoke for them and the system theme's version kept its navy field in a warm window.

tools/gen-theme.py # write native/resources/theme-ember.css tools/check-theme.sh # packaged? generated? in step with the base sheet? cd native && ninja -C builddir

tools/check-theme.sh exists because a theme that is not packaged fails silently: GTK draws the base sheet and the dropdown still reads "Ember". The GUI's --selftest asserts the same thing (gui-theme-ember PASS packaged).

A survey does not have to happen on the machine in front of you. Any module that reads the air can be pointed at a registered node, and the node answers with what it actually measured:

modules/02_cell_recon.sh --node desk # survey through the node, store rows here modules/03_gsmtap.sh --node desk # fetch its newest capture and decode it modules/17_pcap_analysis.sh --node desk # list the captures that node holds modules/18_imsi_exposure.sh --node desk # audit the node's newest capture tools/node_source.py support # what each transport can answer tools/node_source.py cells desk # the node's cells, in the store's table tools/node_source.py events desk # the node's spool, as event rows tools/node_source.py captures desk # the node's capture store

Fetched captures land in captures/nodes/<name>/, so every existing verb works on a local path afterwards and the store keeps both files.

What a node can honestly deliver depends on its transport, and the toolkit says so rather than filling the gap: local and ssh nodes run a real survey, adb handsets report their own serving cell and neighbours with withheld fields marked, serial/qmi/mbim modems report one serving cell and are labelled that way, and diag/sms refuse with the missing clause named. Every row carries source node:<name>:<transport>:<kind>, so a table never loses where a cell was heard. A node with an empty store is a handoff (exit 3), not an empty survey.

A module page is a left menu of views with the content beside it, grouped into cards — STATUS, ACTIONS and ALL MODULE VERBS. The action buttons cover the verbs you reach for most; the generated selector is built from the module index and exposes everything else, with a separate arguments field and command copy button, so nothing is unreachable.

Live Traffic is a real table (sequence, time, type, channel, ARFCN, timeslot, signal, direction, length, payload) with a filter box above it that matches on type, channel or payload. Uplink rows are marked.

The dashboard is configurable, and it remembers. Every card carries a star: pinned modules lead the grid whatever the sort is set to. Sort offers Workflow (category order), Most used (by run count), Name and Category, and Density switches Compact, Comfortable or Spacious card sizing. All of it survives a restart, because it lives in state/ rather than in the binary — and both searches say no match instead of going quietly blank.

Stats shows headline counts as tiles, a per-category breakdown as bars, and where everything lives on disk. It recounts when you open it, so a module that has just written loot is not still showing the numbers from launch.

The module list on the left collapses — the Modules button in the header bar. Collapse it when a module page needs the full width.

The header strip carries the live cellular state, read from the modules themselves so it cannot disagree with them:

SDR the selected radio (01_radio --status-tsv) TX whether that radio can transmit — most attack verbs need this FREQ the tuned frequency CELLS cells in the survey store (02_cell_recon) GPS the survey position source (04_tower_map)

--tab N opens straight to a tab (0 Dashboard, 1 Live Traffic, 2 Casebook, 3 Stats, 4 Notifications, 5 Help, 6 Settings, 7 Workflows, 8 Map, 9 Fleet):

./native/builddir/imsisting-gui --tab 1

Live Traffic — what it is, and what it is not

There is no way to demodulate GSM or LTE inside a GUI process; that needs a full PHY. So this is not a raw-radio view and does not pretend to be one.

What it is: a GSMTAP listener on UDP 4729. GSMTAP is the format gr-gsm, srsRAN and Open5GS all emit, and it is what Wireshark keys off. The tab binds the port, decodes each message's 16-byte header as it arrives, and shows the type, GSM channel, ARFCN, timeslot, signal, direction, length and payload.

That makes it useful both ways — passively to watch paging, SI and identity exchanges happen, and offensively to confirm an emitter is actually transmitting and see what a UE answers with.

It needs an upstream emitter. If nothing arrives within three seconds it says so and names what to start, rather than showing an empty pane:

grgsm_livemon # GSM, via gr-gsm

or an eNB/gNB started with GSMTAP enabled

Two honest limits. The header's arfcn field is 16 bits, so an NR-ARFCN (which runs into the millions) cannot be represented in it — the field is not a general NR ARFCN carrier. And sub_type is a GSM channel type only under a GSM payload; under LTE/NR it is not a channel, so the column shows — rather than a plausible-looking wrong name.

Dependencies — run the check. Half of all confusing failures later are a missing tool.

SDR / Radio Manager — confirm a device is seen and which bands it covers. A receive-only device is flagged, because most attack verbs need transmit.

Cell Recon — try --status-tsv first. It works with no radio attached, which makes it a good smoke test.

Modules

Sixty-one modules, grouped by the categories the application itself uses, so this list and the Dashboard cannot drift apart. Every verb a module documents has a control on its page, and every page answers in the card that asked: a value list for one record, a list of records with per-row Copy for many.

05_field_kit --guard-check and 01_radio probe for these, and the answers are not impressive:

So the honest summary is: the software half runs, the radio half has never run. "Written" and "works" are different claims and this table is which is which.

Everything that is pure protocol work runs today: --selftest on all 60 modules, all encode/decode, all key derivation, pcap dissection, CVE dispatch, corpus generation and the killchain runner. This is most of the tree and it costs nothing.

A PlutoSDR (or a Pluto+/LibreSDR board running the same ADI firmware) is enumerated as pluto:<context> and captured with iio_readdev:

modules/01_radio.sh --list-tsv # pluto:usb:1.9.5 and pluto:ip:192.168.2.1 are one board, two doors modules/01_radio.sh --select 'pluto:ip:192.168.2.1' modules/01_radio.sh --record 5 # iio_attr tunes, iio_readdev streams ci16

Two contexts, two rows: USB and Ethernet reach the same board differently, and the Ethernet door survives a cable pull without re-enumerating.

The capture is ci16 (the AD9361 is a 12-bit converter, samples are shifted left by four); 01_radio --record reports format ci16 with the file so a reader never guesses.

Gain writes set gain_control_mode manual first, because a hardwaregain write in automatic mode is silently ignored.

Known limit: this tree has no Pluto transmit call. The TX verbs name the driver they were p

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →