Mechanism
Thread is an IPv6 mesh over the IEEE 802.15.4 2.4 GHz O-QPSK PHY (16 channels, 11–26), the same radio layer as Zigbee; a single network sits on one channel. The MAC payload is protected with AES-128-CCM* keyed by the Thread network key, so this is not a decryption control — it is an exposure inventory. The link layer still leaks identity: during an active scan, Routers and Router-Eligible End Devices answer a Beacon Request with a beacon that contains the network’s PAN ID, Extended PAN ID (XPAN ID) and human-readable Network Name in the clear [ot-network-discovery]. Not all MLE information is protected at the MAC layer, so an unauthenticated sniffer can both read these identifiers and analyse MLE traffic patterns to fingerprint the deployment and infer mesh structure [akestoridis2022thread].
The real attack surface is commissioning, not the cipher. Thread admits new devices
via the Mesh Commissioning Protocol (MeshCoP): a Commissioner authenticates to a Border
Agent over DTLS using the Pre-Shared Key for the Commissioner (PSKc), and a Joiner is
admitted with its Joiner credential (PSKd), also over DTLS [akestoridis2022thread].
The Border Agent is discoverable by DNS-SD — a co-located _meshcop._udp /
_meshcop-e._udp service is the on-network signature of a reachable commissioning entry
point. A symbolic (ProVerif) analysis of MeshCoP models its DTLS-based authentication and
its security goals [upadhyay2023meshcop]. The practical link-layer weakness is posture,
not protocol breakage: if the commissioner accepts new devices without pinning the
joiner’s 64-bit IEEE address, an attacker can issue repeated online password guesses
during the join window — shown to be impractical for recovering a joiner credential but
usable as a denial-of-service / energy-depletion attack, optionally amplified by
preventing the legitimate device from joining so the user restarts commissioning
[akestoridis2022thread]. Open tooling for this analysis (Wireshark Thread dissectors plus
the Zigator security-analysis tool) repurposes Zigbee-era 802.15.4 tradecraft for Thread
[zigator].
Where the mesh carries Matter-over-Thread, two further leaks sit just above the link: co-fabric device footprinting in the connectedhomeip SDK (CVE-2024-3454, low) and a CASE Sigma1-replay denial of service in pre-1.1 Matter (CVE-2024-3297) [cve-2024-3454] [cve-2024-3297]. The honest headline: AES-128-CCM* holds, so the finding here is what identity, topology and commissioning state the mesh discloses to a passive observer.
Procedure
Authorised testing only: capture passively on networks you own or are explicitly permitted to assess. Any transmit step (active scan, join attempt) is an active control — use your own equipment, test devices, and explicit written permission, ideally inside RF shielding.
-
Find the channel. If unknown, sweep the 2.4 GHz band to spot the active 802.15.4 channel, then park a real radio on it. With a CatSniffer’s channel monitor:
# CatSniffer / catnip — show live 802.15.4 channel activity (11–26) catnip cativityRead off the channel with sustained traffic; that is the mesh’s channel.
-
Capture link-layer frames into Wireshark. Stream raw 802.15.4/Thread frames with the nRF Sniffer extcap, or via an OpenThread RCP and pyspinel:
# OpenThread RCP on an nRF52840 -> Wireshark, channel 15 python sniffer.py -c 15 -u /dev/ttyACM0 --crc -b 460800 | wireshark -k -i -Wireshark’s 802.15.4 / 6LoWPAN / MLE dissectors decode frame headers without any key.
-
Read the network identifiers (no key needed). In the capture, filter for beacons and MLE discovery responses and record what is in the clear:
wpan.frame_type == 0x0 || mleExpected: beacon / discovery-response frames exposing the PAN ID (
wpan.src_pan), the Extended PAN ID and the Network Name [ot-network-discovery]. These three identify and fingerprint the deployment. -
Profile the mesh structure. Tabulate source/destination short and extended addresses and MLE message types over the capture window to infer roles (Leader/Router/REED/End Device) and parent-child links from traffic patterns [akestoridis2022thread]. A representative report:
zigator parsing capture.pcap # parse 802.15.4/Thread frames to a database zigator analysis capture.pcap # derive per-device / topology statistics -
Check commissioning posture (on-network DNS-SD). From a host on the same LAN as a Border Router, look for a reachable Border Agent / commissioning entry point:
avahi-browse -rt _meshcop._udpA returned service indicates a Border Agent advertising the commissioning path; note whether an onboarding/commissioning window is open (a finding about posture, not a break).
-
Record the posture, do not brute-force. Document whether the network key is distributed out-of-band, whether the commissioner pins joiner EUI-64s, and whether the PSKc/PSKd is default/weak/printed. Online guessing against an open window is bounded and is properly treated as a DoS/energy-depletion finding, not credential recovery [akestoridis2022thread].
Field case
Illustrative walkthrough — substitute the values your own capture records. On a lab bench
(your own devices, shielded), a wideband sweep shows activity around channel 15; an
nRF52840 RCP driven by python sniffer.py -c 15 -u /dev/ttyACM0 --crc -b 460800 streams
frames into Wireshark, and the filter wpan.frame_type == 0x0 || mle isolates the beacon
and MLE discovery responses that disclose the network identifiers in the clear, with no key
supplied. The identifiers below are not a live bench capture: they are taken from
OpenThread’s own published example Active Operational Dataset — the kTlvBytes test vector
in tests/unit/test_dataset.cpp of openthread/openthread — which makes a concrete,
verifiable illustration of exactly the fields a beacon / discovery response leaks
[ot-dataset-tlv-vector]. On your own bench, substitute the values your sniffer records:
- PAN ID:
0xface(the dataset’s PAN ID, asserted aspanId == 0xfacein the same test) [ot-dataset-tlv-vector] - Extended PAN ID:
1d:e5:bf:ec:d5:16:5b:8f[ot-dataset-tlv-vector] - Network Name:
"OpenThread-aac3"[ot-dataset-tlv-vector] - Channel: 15 [ot-dataset-tlv-vector]
avahi-browse -rt _meshcop._udp on the same LAN returns a Border Agent entry when a
commissioning path is reachable. MAC payloads remain AES-128-CCM* encrypted and are left
undecrypted (no network key in scope), so the finding is strictly the
identifier and commissioning-posture exposure — exactly the link-layer leak this
control inventories — not message content.
Remediation
Developer (stack / firmware). Treat link-layer identifiers as inherently public: do not encode secrets in the Network Name or PAN/XPAN ID, and avoid stable identifiers that aid long-term tracking. Keep the MeshCoP/DTLS commissioning implementation current and rate-limit failed joiner authentications so an open window cannot be turned into a cheap energy-depletion or DoS vector [akestoridis2022thread]. For Matter-over-Thread, ship on a connectedhomeip revision that fixes co-fabric footprinting (CVE-2024-3454) and the CASE Sigma1-replay DoS (CVE-2024-3297) [cve-2024-3454][cve-2024-3297].
Integrator (product / commissioning workflow). When commissioning, pin the joiner’s 64-bit IEEE address rather than accepting any device, which removes the multiple-guess / restart-trick amplification [akestoridis2022thread]. Use a strong, per-device PSKc/PSKd — never a shared default — and distribute the network key out of band. Keep the commissioning window as short as the workflow allows and close it promptly.
Operator (deployment). Assume an attacker in RF range already knows the network name, PAN ID and channel; these are not secrets and should not gate trust. Open the commissioning window only when adding a device and confirm it closes afterwards. Periodically re-run this passive inventory to detect unexpected beaconing, a left-open Border Agent, or an unexpected onboarding window — and treat any of those as posture findings to fix, since the strong link crypto means the exposure, not the cipher, is the way in.