Security Ripcord

Cutaway Security Blog and Projects

ZigBee Packet Capture Analysis Using ZBAanalyzer

For the TL;DR crowd, the zbanalyzer.py (ZBAnalyzer) script provides an improved method for conducting analysis of ZigBee networks. It is designed to leverage the ZigBee Scapy functionality implemented within the KillerBee project with augmentation from an updated ZigBee Scapy layer provided by a Scapy-Com fork. The rest of this blog post provides a demonstration of how to use ZBAnalyzer.

Capturing ZigBee Packets with KillerBee

Capturing ZigBee network communications is accomplished using a ZigBee capture device. This is most commonly accomplished using the Atmel RZ RAVEN using firmware initially developed by Joshua Wright as a part of the KillerBee project. Riverloop Security is in the final stages of developing the ApiMote v4 beta which may change that in the near future.

While KillerBee project provides methods for capturing, I have started using the zbdump_display2 tool. The only difference between this and the original zbdump tool is that the updated version prints incoming packets to the screen, originally thought up by Larry Pesce, to help the user confirm ZigBee traffic is being captured and recorded. The following textbox demonstrates a quick capture using this updated tool.

1
2
3
4
5
6
7
8
9
10
11
cutaway:Dot15d4> zbid
           Dev Product String       Serial Number
       001:003 KILLERB001           B7AD17FFFF25
cutaway:Dot15d4> python zbdump_display2 -c 25 -w /tmp/test.pcap -s
zbdump: listening on '001:003', link-type DLT_IEEE802_15_4, capture size 127 bytes

<bound method Dot15d4.mysummary of <Dot15d4  fcf_reserved_1=0 fcf_panidcompress=True fcf_ackreq=False fcf_pending=False fcf_security=False fcf_frametype=Data fcf_srcaddrmode=Short fcf_framever=0 fcf_destaddrmode=Short fcf_reserved_2=0 seqnum=221 |<Dot15d4Data  dest_panid=0x588a dest_addr=0xffff src_addr=0x0 |<ZigbeeNWK  discover_route=0 proto_version=2 frametype=command flags=reserved2+extended_dst destination=0xfffc source=0x00 radius=1 seqnum=76 ext_src=00:0d:6f:00:01:db:9b:36 |<ZigbeeSecurityHeader  reserved1= extended_nonce=1 key_type=network_key nwk_seclevel=None fc=0x16974b source=00:0d:6f:00:01:db:9b:36 key_seqnum=1 data='\x93\xbe6-\x8d\xaf\x0e8\xe7\xd6Z' |>>>>>

<bound method Dot15d4.mysummary of <Dot15d4  fcf_reserved_1=0 fcf_panidcompress=True fcf_ackreq=False fcf_pending=False fcf_security=False fcf_frametype=Data fcf_srcaddrmode=Short fcf_framever=0 fcf_destaddrmode=Short fcf_reserved_2=0 seqnum=221 |<Dot15d4Data  dest_panid=0x588a dest_addr=0xffff src_addr=0xbb9e |<ZigbeeNWK  discover_route=0 proto_version=2 frametype=command flags=reserved2+extended_dst destination=0xfffc source=0xbb9e radius=1 seqnum=162 ext_src=00:0d:6f:00:03:60:77:0a |<ZigbeeSecurityHeader  reserved1= extended_nonce=1 key_type=network_key nwk_seclevel=None fc=0x0274ba source=00:0d:6f:00:03:60:77:0a key_seqnum=1 data='\x89\x828\xcc\xbc1J\xf8~$;' |>>>>>

<bound method Dot15d4.mysummary of <Dot15d4  fcf_reserved_1=0 fcf_panidcompress=True fcf_ackreq=True fcf_pending=False fcf_security=False fcf_frametype=Data fcf_srcaddrmode=Short fcf_framever=0 fcf_destaddrmode=Short fcf_reserved_2=0 seqnum=222 |<Dot15d4Data  dest_panid=0x588a dest_addr=0xbb9e src_addr=0x0 |<ZigbeeNWK  discover_route=1 proto_version=2 frametype=data flags=reserved2+reserved1 destination=0xbb9e source=0x00 radius=15 seqnum=78 relay_count=0 relay_index=0 relays=[] |<ZigbeeSecurityHeader  reserved1= extended_nonce=1 key_type=network_key nwk_seclevel=None fc=0x16974c source=00:0d:6f:00:01:db:9b:36 key_seqnum=1 data='\x7fN\xd4\xa1\xb8\xb5\xc2$\x84\xcb\x8f\x9d \xa0\x893\x0b' |>>>>>

Using ZBAnalyzer

I have tried to document ZBAnalyzer internally as much as possible. Reviewing the code should give users a sense for the steps necessary to process a ZigBee Pcap file and analyze each layer. As with all tools this script has a help menu.

1
2
3
4
5
6
7
8
9
10
11
cutaway:Dot15d4> python zbanalyzer.py -h
zbanalyzer.py Usage
    -h: help
    -f <filename>: capture file with zigbee packets.
    -d <directory>: directory with ZigBee capture files.
    -p <panid>: Pan ID in ASCII format. Will be converted for use.
    -k <network_key>: Network Key in ASCII format. Will be converted for use. Requires -p.
    -R: Turn on reprocessing. This will parse for keys and addresses first then reprocess and print zbscapy parsed packets.
    -s <packet number>: Print a single packet. Numbered from 0.
    -S: Show all information that has been processed and stored.
    -D: Turn on debugging.

Searching For PanID and Network Key

To analyze all layers in a ZigBee capture a key is necessary to decrypt any encrypted layers. The ZBAnalyzer script parses a single capture file, or a directory filled with capture files, and analyzes the packets for these keys. The ‘-S" option of ZBAnalyzer will process the file(s) and list network information. If the script locates a network key the key and and its associated Pan ID will be noted. The following textbox is a demonstration of ZBAnalyzer being used to analyze all the ZigBee Pcap files in the directory “../../Projects/zb_blog”. To make using this data easier for additional analysis, the PanID and Network Key have been output as ZBAnalyzer command line options in the line beginning with “Prepped”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
===================================
cutaway:Dot15d4> python zbanalyzer.py -d ../../Projects/zb_blog -S

[Snipped for Brevity]

###############################
Controller: 00:0d:6f:00:01:db:9b:36
    Pan IDs:
        0x588a
    End Nodes:
        00:00:00:00:00:00:00:00:
            0x1034
        00:0d:6f:00:02:54:84:0a:
            0x32fc
        da:35:58:c2:22:b2:2f:2e:
            0x1034
        00:0d:6f:a0:03:43:77:76:
            0x597f
        58:5d:b8:d3:54:62:53:97:
            0x1034
        00:0d:6f:00:03:60:77:0a:
            0x597f
            0x9c23
            0xadf9
            0x8ef6
            0xa603
            0x1034
            0x02f8
            0x0ec1
            0x8d03
            0x6522
            0x490b
            0xbb9e
    Keys:
        Pan ID 0x588a: 6bddd3a625285bdfd7ae5cd1cb962727
        Prepped: -p 588a -k 6bddd3a625285bdfd7ae5cd1cb962727
###############################

cutaway:Dot15d4>
===================================

Parsing ZigBee Pcaps with ZBAnalyzer

Printing the Network Key for a collection of ZigBee communication captures is actually not necessary to parse all the layers for a single file or a collection of files. ZBAnalyzer actually double parses all of the pcap files, notates keys and their associated network. This is accomplished using the “-R” option as shown in the following image.

ZBAnalyzer Scapy Output

To demonstrate the parsing functionality of ZBAnalyzer I located a specific packet that contained encrypted data. This packet was captured from a ZigBee network made-up of an IRIS gateway and an associated door sensor. The pcap for this capture did not contain a network key. However, repeated captures of this ZigBee network, while removing and adding devices, eventually detected a network key for the same Pan ID. Thus, the door sensor’s communication could be parsed.

The following textbox demonstrates a packet parsed without the Network Key. Notice that the “ZigbeeSecurityHeader” layer is not processed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cutaway:Dot15d4>  python zbanalyzer.py -f ../../Projects/zb_blog/zb_firmware_update_door_sensor1.pcap -R -s 256
##############################################
# Reprocessing pcaps
# NOTE: Directory read may not be in order
##############################################
##############################################
Processing file: ../../Projects/zb_blog/zb_firmware_update_door_sensor1.pcap
##############################################
256: <Dot15d4FCS  fcf_reserved_1=0 fcf_panidcompress=True fcf_ackreq=True fcf_pending=False fcf_security=False fcf_frametype=Data fcf_srcaddrmode=Short fcf_framever=0 fcf_destaddrmode=Short fcf_reserved_2=0 seqnum=242 |<Dot15d4Data  dest_panid=0x588a dest_addr=0x0 src_addr=0x32fc |<ZigbeeNWK  discover_route=1 proto_version=2 frametype=data flags=reserved2 destination=0x00 source=0x32fc radius=30 seqnum=62 |<ZigbeeSecurityHeader  reserved1= extended_nonce=1 key_type=network_key nwk_seclevel=None fc=0x03d06e source=00:0d:6f:00:02:54:84:0a key_seqnum=1 data='-l\xedsdl\xfdJ\xd5\xed\xb0\x01\n\xd1\xf9\x93Qx' |>>>>

##############################################
# Done: Reprocessing pcaps
##############################################
cutaway:Dot15d4>

The next textbox is the same packet parsed using the Network Key detected by parsing other capture files. Notice that the “ZigbeeSecurityHeader” layer has been processed and the encrypted layers exposed for additional analysis.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cutaway:Dot15d4>  python zbanalyzer.py -f ../../Projects/zb_blog/zb_firmware_update_door_sensor1.pcap -p 588a -k 6bddd3a625285bdfd7ae5cd1cb962727 -R -s 256
##############################################
# Reprocessing pcaps
# NOTE: Directory read may not be in order
##############################################
##############################################
Processing file: ../../Projects/zb_blog/zb_firmware_update_door_sensor1.pcap
##############################################
256: <Dot15d4FCS  fcf_reserved_1=0 fcf_panidcompress=True fcf_ackreq=True fcf_pending=False fcf_security=False fcf_frametype=Data fcf_srcaddrmode=Short fcf_framever=0 fcf_destaddrmode=Short fcf_reserved_2=0 seqnum=242 |<Dot15d4Data  dest_panid=0x588a dest_addr=0x0 src_addr=0x32fc |<ZigbeeNWK  discover_route=1 proto_version=2 frametype=data flags=reserved2 destination=0x00 source=0x32fc radius=30 seqnum=62 |<ZigbeeSecurityHeader  reserved1= extended_nonce=1 key_type=network_key nwk_seclevel=None fc=0x03d06e source=00:0d:6f:00:02:54:84:0a key_seqnum=1 data='-l\xedsdl\xfdJ\xd5\xed\xb0\x01\n\xd1\xf9\x93Qx' |>>>>

Decrypt Details:
        Key:            6bddd3a625285bdfd7ae5cd1cb962727
        Nonce:          0a845402006f0d006ed003002d
        Mic:
        Encrypted Data: 2d6ced73646cfd4ad5edb0010ad1f9935178
        Decrypted Data: 4002000516c20245090000040000c47d72f2
256 Enc Data: <ZigbeeAppDataPayload  frame_control=ack_req delivery_mode=unicast aps_frametype=data dst_endpoint=2 cluster_id=0x0500 profile=ALERTME_c216 src_endpoint=2 counter=69 |<ZigbeeClusterLibrary  reserved=0 disable_default_response=0 direction=1 manufacturer_specific=0 zcl_frametype=1 transaction_sequence=0 |<ZCLSpecificClusters  |<ZCLBasic  command=off |<Raw  load='\x04\x00\x00\xc4}r\xf2' |>>>>>

##############################################
# Done: Reprocessing pcaps
##############################################

Decryption of ZigBee layers was actually already a part of the KillerBee framework. This functionality is provided in the kbdecrypt function. New functionality provided by ZBAnalyzer is partly provided by the scapy-like parsing of all packets in multiple files and, more importantly, in the processing of ZigBee profiles and clusters. The decrypted packet identifies the profile of the captured data as “ALERTME_c216” which is consistent with IRIS gateways. The cluster is identified by the value “0x0500” which still needs to be added to the Scapy-Com 802.15.4 Layer.

Confirming ZBAnalyzer Output Using Wireshark

To date, the defacto ZigBee Pcap analysis tool is Wireshark. The ZigBee Specifications (login required) are convoluted and verbose, at best. Getting to this point in the update of Scapy-com and ZBAnalyzer would not have been possible without Wireshark’s functionality, source code, and header files. While writing this blog post I was pleased to find that Wireshark’s ZigBee functionality has continuted to be developed.

Opening the zb_firmware_update_door_sensor1.pcap file in Wireshark will automatically parse the file using the ZigBee dissector. Wireshark can be configured with Network Keys using the “Edit” -> “Preferences” window. The left sidebar has a menu item name “Protocols”. Once selected “Protocols” will expand to a long list of configurable protocols. Scroll to the bottom and find the “ZigBee” protocol (doing this using the IEEE 802.15.4 Protocol will not work). Selecting “ZigBee” show two configurable options “Security Level” and “Pre-configured Keys”. For the zb_firmware_update_door_sensor1.pcap file I set the “Security Level” as “AES-128 Encryption, 32-bit Integrity Protection.” Selecting “Edit…” for “Pre-configured Keys” opened a new window where the Network Key was input and labeled. ZBAnalyzer displays Network Keys in a “Normal” Byte Order. Some other ZigBee tools may output keys in “Reverse” Byte Order, thus Wireshark provides the ability to specify the order. The following image is an example of these settings in Wireshark.

Wireshark Preferences

Once configured Wireshark will attempt to apply the key to any packets that properly decrypt with this key. Wireshark will actually search a ZigBee Pcap file and apply any keys that it finds. Preconfiguring the ZigBee Protocol preferences helps Wireshark when it cannot find a key in the capture.

The following images demonstrate Wireshark parsing the 257th packet (Wireshark starts counting from 1 instead of 0). The first image is the encrypted packet and the second image is the decrypted packet. Notice that the ZigBee Security Layer has not been processed in the first image. In the second this layer has been processed and displays the Profile and Cluster IDs.

Parsed Packet With Network Key Parsed Packet Without Network Key

This information confirms most of the fields parsed by ZBAnalyzer. The Wireshark dissection of this packet also demonstrates that there is still a lot of work that needs to be done in ZBAnalyzer to properly parse all of the Profiles and Cluster IDs. An ongoing battle that will also be hampered by the use of custom clusters by individual manufacturers developing proprietary code. Fortunately, at this point, it is just the time consuming steps of going through each ZigBee spec section by section and adding a new block of code to handle a new layer for Cluster IDs that have not been implemented.

Final Thoughts

ZBAnalyzer is a huge step (in my biased opinion) ahead for the KillerBee and Scapy-Com projects. I hope someday this functionality will be integrated into these projects or, at least, spur new development. ZigBee is actively being deployed in a variety of environments to include building automation and security. There is still a need for up-to-date assessment and penetration testing tools in this field.

Thank You and Recognition

Ryan Speers - for his personal time and team contributions to KillerBee, Scapy-Com, and support for zbscapy development (even if we are doing basically the same thing in separate projects).
Jean-Michel Picod - for his assistance with Scapy usage and development.
Atlas - for his encouragement and “extremely important” contribution to properly map Cluster IDs with Profile IDs.
Larry Pesce - for his encouragement, testing, brain storming, and patience.
John H. Sawyer, Andrew Righter, and KF - for their constant encouragement around this project.
Tom Liston - for putting up with me developing all of this using iPython.
Joshua Wright - for peering into the unknown parts of things everybody takes for granted.
InGuardians - for giving me opportunities to assess wireless networks and follow up on the shortcomings in assessment tools I noticed during those assessments.

Go forth and do good things,
Don C. Weber (cutaway)