Tuesday, April 26, 2011

pCTF 2011 #32 That's no bluetooth

The only networking problem at pCTF 2011 was unusual because it involved ZigBee, based on IEEE 802.15.4.


We captured this network traffic from outside of an AED employee's home.

Decrypt it and find the key.

Update: Our operatives were able to decrypt packet #18 in the capture file.

The decrypted data is 18060a0700421a63343a636f6e74726f6c345f73723235303a43342
or (printable text only) Bc4:control4_sr250:C4-SR250B03.01.54 !<

If you aren't getting the correct values, make sure your keys are correct,
and that they are entered correctly. Keep in mind bits sometimes flip when
transmitting signals wirelessly. 
download file


First thing to do with a pcap, open it with Wireshark:

Wireshark recognizes IEEE 802.15.4 and ZigBee. At packet #13 you see "pCTF_ZigBee_LOL" (15 bytes) while the following data packets are recognized as encrypted. After a few reads on ZigBee you find that the communication is encrypted using AES-CTR with a network key of 16 bytes that has been sent in clear, at packet 13.

Frame Check Sequence (FCS)

Still in Wireshark, you see that the Frame Check Sequence (FCS) of packet #13 is incorrect. As explained in the context, some bytes have flipped, much likely the last byte of the key (\x00). Let's recover this missing byte by trying all possibilities and calculating the FCS of the new frame to get the expected one (0xd3a1). According to the documentation, FCS is CRC-16-CCITT (reversed polynom 0x8408).
def crc16(buff, crc = 0, poly = 0x8408):
    l = len(buff)
    i = 0
    while i < l:
        ch = ord(buff[i])
        uc = 0
        while uc < 8:
            if (crc & 1) ^ (ch & 1):
                crc = (crc >> 1) ^ poly
                crc >>= 1
            ch >>= 1
            uc += 1
        i += 1
    return crc

p1 = 'a\x88nY3U6\x00\x00\x08\x00U6\x00\x00\x1ez\x01=\x05\x01'
key = 'pCTF_ZigBee_LOL'
p2 = '\x00\x1a[A\x00\x00\xff\x0f\x00\xff\xff\xff\xff\xff\xff\xff\xff'

for i in range(256):
  if crc16(p1 + key + chr(i) + p2)==0xd3a1:
    print "Found byte %r (%02x)" % (chr(i),i)
    print "Key is %r (%s)" % (key+chr(i), (key+chr(i)).encode("hex"))
Found byte '\xea' (ea)
Key is 'pCTF_ZigBee_LOL\xea' (704354465f5a69674265655f4c4f4cea)

Decrypt ZigBee with Perytons

I first tried to decrypt ZigBee packets implementing their AES-CTR encryption (see this good presentation), but it was painful. Let's just find if a ZigBee analysis tool already exists. And there is one! I found Perytons and they even provide a free evaluation (direct .exe link).

First, you have to convert the .pcap into their .anl format. Apparently they did not put this into their software (why?) but give a form where you uploaed your .pcap and it returns you the corresponding .anl file...

Then, run Perytons and import your .anl by using "File/New" menu. Perytons is clever enough to automatically read the network key from the capture, however it has the wrong last byte. Fix it by using "Tools/Security/Network keys" menu. You can then confirm with packet #17 (numbering starts from 0 unlike Wireshark which starts from 1) that the decryption was successful:

Finally, just browse the data packets and you find the key at packet #394:

You read: "Key : z1gb33_r0ck5"

Thanks tylerni7 for this unusual challenge!


  1. Very good write-up! Another easy way to decrypt the packets in Wireshark is to put the key bytes (in reverse) in the dissector options:

    Edit -> Preferences... -> Protocols -> ZigBee NWK -> Network Key = ea:4c:4f...

    You will see a new tab at the bottom showing the decrypted data.


  2. Oh I didn't know/see that Wireshark had it. Silly me :)

  3. Great!

    One quick question, how could you know that this particular string "pCTF_ZigBee_LOL" in the data payload (of 804.15.4) is the network key of the network layer? does zigbee specify that?


  4. ZigBee surely specifies that, as Perytons is able to automatically read the ZigBee Network Key and decrypt the next packets with it.

    Anyway, before reading on ZigBee I was pretty sure it was the key because:
    1) there was encryption: it required either a predefined key, or a key to be transmitted
    2) it looked like a good place: it's the only data packet marked as "not encrypted" while the next ones are marked as "encrypted"
    3) it looks like a key :) ascii printable + "pCTF" + "ZigBee"