Rating:

# Odin Part 1 (part 2 below), re, 334p, 16 solves

> Problem
> Statement
> I’ve installed a smart lock device to the entrance door of my home a while ago.
> The smart lock can be controlled using a smartphone app over Bluetooth Low Energy.
> I noticed, a few times since the installation, that there're some traces left in my home like someone trespassed.
> I really suspect that there’s a hidden backdoor in the smart lock.
> Could you find out the backdoor command for unlocking the door?
>
> The genuine smartphone app unlocks the door with 1 byte length command "91" (in hex) after authorization.
> Your task is to build another command bytes to unlock the door.
>
> I’ve got a firmware dump from BLE SoC on the smart lock board (nRF52832) using SWD and captured BLE packets on genuine app’s unlocking operation.
> I also analyzed the smartphone app for smart lock and wrote a document of BLE communication protocol between the app and the smart lock.
> Here is it.
>
> Files
> Firmware dump (Memory dump of 0x00000000-0x00080000):
> memdump_00000000_00080000.bin
>
> Captured BLE packets of genuine app’s unlocking operation:
> genuine_app_unlock_operation.pcap
>
> Communication protocol
> Structure
> Every request from the app to the smart lock is written to Characteristic 38451401-282b-58d1-d5fe-9e95bb5abded as a byte array.
> Every response from the smart lock to the app is sent as a byte array using Notification.
> The smart lock does not have any other Services/Characteristics.
>
> Request format is (1 byte length command number) + (variable length payload).
> Response format is (1 byte length error number) + (variable length payload).
>
> Known commands
> CMD_GET_CHALLENGE
> Number: 0x00
> Request/Response payload length: 0/16
> Description
> Retrieve a ramdom challenge bytes for CMD_AUTHORIZE.
>
> CMD_AUTHORIZE
> Number: 0x01
> Request/Response payload length: 16/0
> Description:
> Authorize the sender for operating the smart lock.
>
> Payload is aes_ecb_encrypt(key = (Secret bytes set with CMD_INITIALIZE), cleartext = (Challenge bytes retrieved with CMD_GET_CHALLENGE)).
>
> CMD_GET_INFO
> Number: 0x10
> Request/Response payload length: 1/variable
> Description:
> Retrieve information from the smart lock.
>
> Request payload format is (1 byte information type).
> Response payload format is (variable length information).
>
> Known information types are 0x00 for INFO_AUTH_STATE and 0x01 for INFO_TIME.
> INFO_AUTH_STATE is 1 byte length and can be 0x00 (not authorized) or 0x01 (authorized).
> INFO_TIME is 7 byte length.
> A sample code for the time encoding is at https://github.com/SWITCHSCIENCE/samplecodes/blob/bd1b04fc657d58787cbad00297146812ac8d95d2/PCF2129AT_breakout/mbed/Test_PCF2129AT/main.cpp .
>
> CMD_INITIALIZE
> Number: 0x80
> Request/Response payload length: 16/0
> Description:
> Set secret bytes for the authorization with CMD_AUTHORIZE.
>
> This command is only sent in device installation time.
>
> CMD_SET_TIME
> Number: 0x81
> Request/Response payload length: 7/0
> Description:
> Set current time.
>
> Time encoding is the same with CMD_GET_INFO + INFO_TIME.
>
> CMD_LOCK
> Number: 0x90
> Request/Response payload length: 0/0
> Description:
> Lock the door.
>
> CMD_UNLOCK
> Number: 0x91
> Request/Response payload length: 0/0
> Description:
> Unlock the door.
>
> Known error numbers
> Error number will be 0x00 on success, and other numbers on failure.
> Known numbers are the followings.
>
> ERR_SUCCESS = 0x00
> ERR_INVALID_LENGTH = 0x01
> ERR_INVALID_DATA = 0x02
> ERR_INVALID_CMD = 0x03
> ERR_NOT_AUTHORIZED = 0x10
>
> Flag Format
> The backdoor command for unlocking the door is the flag.
> If the command is “12 34 ab cd” in hex, the flag will be “CBCTF{1234abcd}”.

In this problem we got two files, ARM firmware memory dump, and Bluetooth packet dump. From task description we knew the
apparent protocol, as well as that there is a backdoor hidden in firmware allowing to open doors without authentication.
Searching the firmware for protocol constants, such as 0x91, we found function responsible for packet dispatch.
It was fairly straightforward and in line with the description, with one exception: there was additional undocumented
command 0x20. It checked 8 following bytes, four of which had to be equal to part of device's MAC address, and
the other four random-looking constant. If they matched, tenth byte was checked and depending on its value, door
was locked or unlocked. The only thing we didn't get from the firmware was the MAC address - thankfully it
was transmitted and captured in packet dump. With all the information gathered, we could craft backdoor packet.

# Odin Part 2, re, 335p, 13 solves
> Problem
> Statement
> This smart lock has a logging function that records every operation.
> The log is readable only by some special management device.
> Though I don’t have the device, I’ve got a EEPROM dump on the smart lock board which looks like holding the log.
> Could you analyze it and find out when the backdoor was exploited for the first time?

> File
> eeprom.bin

> Flag format
> Flag format is CBCTF{YYYYMMDDhhmmss}.
> If the date is 2018/07/01 12:34:56, the flag will be “CBCTF{20180701123456}”.

The firmware indeed wrote some data to EEPROM just before dispatching Bluetooth packets. It logged each
packet in 16-byte chunks, first 7 of which were packed timestamp, and the remainder - packet payload. The whole
block was AES encrypted with constant key. After decrypting EEPROM blocks, decoding timestamps, we looked
for packets starting with 0x20 byte, i.e. backdoor command. There were only two of these, and the first one
corresponded to time of compromise. Code:

```python
from Crypto.Cipher import AES

key = "88AD3D8347B8CE82082064B4618D7637".decode("hex")
a = AES.new(key, AES.MODE_ECB)

data = open("eeprom", "rb").read()

for i in range(len(data) / 16):
line = data[i*16:i*16+16]
if line == "\xff" * 16:
break
line = a.decrypt(line)

date = line[:7]
payload = line[7:]

if payload[0] == ' ':
print date.encode("hex"),
print payload.encode("hex")

cmd = [ord(x) for x in date]
dts = ((cmd[0] >> 4) * 10) + (cmd[0] & 0x0F);
dtm = ((cmd[1] >> 4) * 10) + (cmd[1] & 0x0F);
dth = ((cmd[2] >> 4) * 10) + (cmd[2] & 0x0F);
dtd = ((cmd[3] >> 4) * 10) + (cmd[3] & 0x0F);
dtwd = ((cmd[4] >> 4) * 10) + (cmd[4] & 0x0F);
dtmm = ((cmd[5] >> 4) * 10) + (cmd[5] & 0x0F);
dty = ((cmd[6] >> 4) * 10) + (cmd[6] & 0x0F);

print dty, dtmm, dtd
print dth, dtm, dts

```

Original writeup (https://github.com/p4-team/ctf/tree/master/2018-07-28-code-blue-quals/odin#odin-part-2-re-335p-13-solves).