courses

Z-Wave

Why this matters

Z-Wave is the quiet one. It has none of Zigbee’s name recognition and none of Matter’s marketing, and it is in a very large number of door locks, garage controllers and alarm panels — the device classes where a failure is not an inconvenience.

Two things make it distinctive for this course. First, it is sub-GHz, which means it is easy to capture with hardware you already own for LoRa work, and it goes through walls that stop Zigbee. Second, its security history is an unusually clean case study: a first attempt with a fatal bootstrapping flaw, a well-designed replacement, and a downgrade attack that let an attacker choose the first one.

The radio layer

Z-Wave is narrowband FSK in the sub-GHz ISM bands, standardised as ITU-T G.9959. The frequency is region-specific and legally mandated, so a European controller will not talk to a North American device at all:

Region Frequency
North America 908.42 MHz (plus 916.0 MHz for the higher rate)
Europe 868.42 MHz
Australia / NZ 921.42 MHz
Z-Wave Long Range (US) 912 MHz / 920 MHz

Three data rates coexist, and devices negotiate down for range:

Rate Speed Modulation
R1 9.6 kb/s FSK
R2 40 kb/s FSK
R3 100 kb/s GFSK

The channels are narrow — a few hundred kHz. That is the single most useful fact for capture: unlike WiFi’s 20 MHz OFDM channels, a Z-Wave channel fits comfortably inside the bandwidth of a $25 RTL-SDR. There is no hopping to follow and no spreading to undo. Point a cheap dongle at 908.42 MHz and you have the traffic.

Sub-GHz propagation also means range: roughly 100 m line of sight per hop, substantially better than 2.4 GHz through building materials. Classic Z-Wave meshes route up to four hops and cap at 232 nodes, addressed by a 32-bit HomeID (unique to the controller) plus an 8-bit NodeID.

Z-Wave Long Range changes the topology rather than the band: a star, not a mesh, reaching about a mile with dynamic transmit power control, supporting thousands of nodes with 12-bit node IDs. It mandates S2, which matters below.

Capturing it

Tool Notes
RTL-SDR + a decoder Cheapest; narrowband FSK is easy to demodulate
HackRF / other SDR Same job, transmit capability if authorised
Silicon Labs Zniffer Official; a UZB stick reflashed with Zniffer firmware
EZ-Wave / Z-Force Research tools built on GNU Radio and Scapy; EZ-Wave’s repository is no longer published

The Zniffer is the pragmatic choice when you can get one, because it decodes the full frame structure including security encapsulation and shows you exactly what the stack sees. The SDR route is the instructive one, because you build the understanding yourself.

⚠️ Transmitting is a different legal question from receiving. 908.42 MHz is inside the US 902–928 MHz ISM band and unlicensed transmission there is permitted under FCC Part 15 within power and duty-cycle limits — but injecting frames into a neighbour’s door lock is not a Part 15 question, it is a computer crime question. Receive freely, transmit only against course hardware in lab. See Radio Protocols for the full discussion.

Frames and topology leak without any key

Even on a fully encrypted network, the frame header is plaintext. It has to be — routing happens before decryption.

+----------+--------+-------+---------+--------+---------+-----------+
| HomeID   | SrcID  | Frame | Length  | DstID  | Payload | Checksum  |
| (32-bit) | (8)    | Ctrl  |         | (8)    |         |           |
+----------+--------+-------+---------+--------+---------+-----------+
                                                 ^
                                    encrypted under S0/S2 if secured

A passive listener therefore learns, with no key at all:

Traffic analysis is a finding in its own right, and one students routinely overlook because they are focused on decrypting payloads. Write it up.

The security model

Before S0: nothing

A great many deployed Z-Wave devices use no encryption whatsoever. Security was optional, it cost battery life and code space, and non-critical device classes skipped it. A light switch, a motion sensor, a temperature probe — all frequently plaintext, all trivially replayable with a recorded frame.

This is not a historical footnote. These devices last fifteen years.

S0: the right primitive, the wrong bootstrap

S0 (2013) encrypts with AES-128 CCM and adds a nonce exchange for freshness. The cryptography is fine. The inclusion process is not.

When a node joins, the controller must give it the network key. To protect that transfer, S0 encrypts the network key with a temporary key of all zeros — a constant, specified, publicly known value.

temp_key = 0x00000000000000000000000000000000

So an attacker present during inclusion decrypts the key transport and holds the network key for the life of the network. This is exactly Zigbee’s default link key problem in a different protocol: the bootstrap secret is in the specification.

S0 is also expensive — every secured message costs a nonce request and nonce report round trip, roughly tripling the traffic, which is itself a reason vendors avoided applying it broadly.

S2: an actual key exchange

S2 (mandatory for certification since 2017) replaces the bootstrap with Elliptic-Curve Diffie–Hellman on Curve25519. The joining node and the controller derive a shared secret over the air, so there is no constant to know.

ECDH alone is anonymous and therefore MITM-able, so S2 authenticates it out of band with the DSK (Device Specific Key) — the first 16 bytes of the node’s 32-byte public key, rendered as five groups of five decimal digits and printed on the device, usually as a QR code:

DSK: 12345-31782-90144-56273-88109
     ^^^^^
     first group blanked in the UI; the installer types it from the label

The controller blanks the first group and requires the human to enter it, which binds the exchange to the physical device in your hand. An attacker without the label cannot complete an authenticated inclusion.

S2 defines three classes with separate network keys, so a compromised sensor does not yield the lock’s key:

Class Used by
S2 Unauthenticated Low-risk devices; ECDH without DSK entry
S2 Authenticated Most secured devices; DSK entry required
S2 Access Control Locks, garage doors, barriers

That key separation is a genuine architectural improvement over Zigbee’s single shared network key, and worth calling out when comparing the two.

SmartStart extends this: scanning the device’s QR code into the controller before powering it on pre-authorises the DSK, so inclusion completes automatically and authenticated, with no window in which a user might click through a warning.

Z-Shave: choosing S0 for them

Pen Test Partners demonstrated in 2018 that the improvement could be bypassed entirely, because the negotiation of which security version to use is itself unauthenticated.

During inclusion the joining node advertises its capabilities in a Node Information Frame. An attacker who spoofs a NIF with COMMAND_CLASS_SECURITY_2 removed convinces the controller that the device is S0-only. The controller obliges, falls back, and the all-zeros key is in play again.

The structural lesson is now familiar:

A system that supports both a strong and a weak mode, and negotiates between them without authentication, has the security of the weak mode.

Compare WPA3 transition mode, Bluetooth’s BIAS downgrade, and Zigbee’s backward-compatible joining. Four protocols, four independent design teams, the same mistake. It is worth students noticing that this is a pattern, not a series of accidents.

The mitigation is not cryptographic — it is telling the user. Certified controllers must now warn when an inclusion downgrades, on the theory that a human who scanned a QR code and then sees “this device will be added with lower security” has enough information to stop. Whether they read it is another matter.

Worked example: finding and capturing a Z-Wave network

Confirm there is activity before you commit to a capture. rtl_power sweeps a range and writes a CSV you can plot or grep:

$ rtl_power -f 907M:910M:10k -i 30 -e 5m -g 30 survey.csv
Number of frequency hops: 2
Dongle bandwidth: 1500000Hz
Total FFT bins: 512
FFT bin size: 5859.38Hz
Reporting every 30 seconds

Z-Wave is bursty, so look for the peak rather than a continuous carrier:

$ awk -F', ' 'NR>1 {for(i=7;i<=NF;i++) if($i>-30)
    printf "%s  %.3f MHz  %s dB\n", $2, ($3+(i-7)*$5)/1e6, $i}' survey.csv | head
14:22:31  908.420 MHz  -18.94 dB
14:23:01  908.421 MHz  -21.03 dB

That is the North American Z-Wave channel, and something is using it. Capture raw IQ centred on it:

$ rtl_sdr -f 908420000 -s 2048000 -g 30 -n 20480000 zwave.iq
Found Rafael Micro R820T tuner
Sampling at 2048000 S/s.
Tuned to 908420000 Hz.

Ten seconds of samples at 2.048 MS/s. From here you demodulate the FSK and parse the frame — Universal Radio Hacker will do the first part interactively, and a dedicated decoder such as waving-z does both. (EZ-Wave, which older write-ups recommend alongside it, was published by AFIT’s WiSec group and is no longer available anywhere — the repository and the organisation that held it are both gone.)

⚠️ Check the decoder’s flags against its own README. These are research tools with small maintainer counts and their command-line interfaces shift without notice. Do not trust a transcript — including this one — over --help.

What you are looking for in the output is the header described above: a constant HomeID across every frame, a small set of NodeIDs, and whether the payload is a readable command class or a Security / Security 2 encapsulated blob. That single distinction — encapsulated or not — is the finding.

Key takeaways

References


Related course pages: Radio Protocols · Zigbee · Thread and Matter · Other IoT radios · Attacks · Tools of the Trade

🛠️ Maintenance note: the SDR decoders on this page are lightly maintained research code and are the most likely thing to break between offerings — test the whole pipeline before lab and be prepared to fall back to a Zniffer. Z-Wave Long Range adoption and the Z-Wave Alliance’s multi-vendor silicon situation have both moved quickly since the specification opened in 2020; re-check whether classic mesh is still the default assumption for new devices. The regional frequency table is legally load-bearing — verify it against the current ITU/FCC allocations rather than copying it forward.