I’ve been interested in Bluetooth Low Energy for some time now, but never took the time to really dive into it or test my own devices. Then I came upon this article which describes a Bluetooth Low Energy CTF which runs on a ESP32. I decided to take my shot at it, and here is the write-up.

Getting the CTF to run

I hav accumulated a few electronic boards over the year, and I happen to have bought a FiPy from Pycom this year, which is a development board supporting 5 different networks : LoRa, Bluetooth, WiFi, Sigfox and LTE-M (NB-IoT and Cat M1). It runs on the ESP32, so I could re-flash it to run the CTF.

First, it is necessary to install the Espressif toolchain for compiling and installing the firmware. Original instructions are here. On Arch, it is possible to install the packages required and the compiler with AUR:

Now, the firmware for the CTF can be built and flashed. In order to flash it on the FiPy, it must be put in firmware update mode.

Unplug the board

Connect a cable from G23 to GND

Plug the board

Now it is ready to receive a brand new firmware ! But let’s build it first.

git clone https://github.com/hackgnar/ble_ctf.git
cd ble_ctf
make menuconfig # Make sure the serial device entered is the ESP32 etc
make
# The user must be allowed to write on the serial console.
# On some distros, it means being part of the group uucp or dialout
make flash

Now, unplug and replug the board, the CTF should be running.

Tooling

Now, we need to talk BLE, several tools are available to do that. I’m far from having an extensive knowledge in BLE, so I learned gatttool during this CTF. While reading, I also saw the hci* suite of tools (hciattach, hcidump, hcitool, …), bluetoothctl and bleah. I installed the Android app nrfConnect, which can be used to easily scan around and talk to devices (provided you know what to tell them). Part of the CTF can be done using it, but some challenges require brute-forcing a few hundreds of values.

Finally, some libraries are able to communicate in BLE. Golang has gatt, Python has bluepy, Node.js has noble/bleno, …

On the hardware side, I used the bluetooth interface embedded in my laptop, but cheap dongles exist aswell.

In order to scan for BLE devices around, you have to start the bluetooth daemon, activate the device and start the scan.

Bluetooth Low Energy devices send beacons, which enables anyone around to see that they are present and to know some information about them. This is the information seen with hcitool lescan As seen, the BLE CTF is running on the device which has mac address 30:AE:A4:2A:54:8A, which confirms that is has been properly flashed.

First steps with GATT

The author of the CTF provides the command to submit the first flag and to see the score. Before that, a short introduction to GATT.

GATT is the protocol used to communicate with BLE devices. The device exposes a server, and the computer or phone that connects to it is the client. The server exposes services, which contain characteristics, which have a value and possibly some descriptors. This is organised as such :

It seems a bit daunting at first to see all those hexadecimal strings, without understanding anything, but really it is possible to see them as pieces of data which you can read or write, with the server and the client agreeing on the role of each one.

As mentioned in the documentation, the score is available by reading the characteristic with handle 42 (0x2a).

To submit a flag, it must be written to the characteristic with handle 44 (0x2c). The first flag is given in the documentation, it is 3132333435363738393031323334353637383930 (two times “1234567890” in hexa).

Flag 3

Flag 4

# This challenge requires to read the name of the device
# It is exposed under service 0x1800, characteristic uuid 0x2a00-*
# It also has handle 0x0016 on this device
$ ./read_txt.sh 0x0016
2b00042f7481c7b056c4b410d28f33cf
$ ./submit.sh 2b00042f7481c7b056c4b410d28f33cf && ./score.sh
Score:4 / 20