BLE CTF Walkthrough

So a pentest friend came over that I hadn't seen in a while, and as always we had an evening of nerding out, one of the many takeaways from this was he gave me a small device and a link to a CTF he had flashed onto it, I spent the weekend hacking it and here is my writeup.

I would like to note that I have never investigated Bluetooth or any of this before so I might have gone about things the wrong way. However I did manage to solve it in a weekend and feel most people with an interest could pick this up fairly easily.

Where is this CTF I hear you ask... here: https://github.com/hackgnar/ble_ctf
As stated on that page:
The purpose of BLE CTF is to teach the core concepts of Bluetooth Low Energy client and server interactions. While it has also been built to be fun, it was built with the intent to teach and reinforce core concepts that are needed to plunge into the world of Bluetooth hacking. After completing this CTF, you should have everything you need to start fiddling with any BLE GATT device you can find.
Awesome! To the left is a pic of the device I was given.

I was told I would need a "bluetootth sniffer" so I got one. (What did we do before amazon prime?). Turns out you don't need one, I didn't even work out how to get it working, perhaps that'll be my next project.

I managed to solve all of the challenges using the inbuilt Intel bluetooth on my laptop (Razer blade stealth 2017) However on my desktop I used a cheap USB Bluetooth adapter, which is preferred as it uses "cambridge silicon" firmware which is apparently better supported and also has 90% of the market share.

Setup

OK so I know this is boring, so lets just get it over with.

First in windows has to make the service "Bluetooth Support Service" set to "automatic" - access it's settings by running "services.msc"

on Debian VM:
apt-get install bluetooth bluez bluez-tools rfkill
apt-get install firmware-iwlwifi bluez-firmware

Followed install guide here: https://github.com/evilsocket/bleah

And you should be ready to go
There are 2 commands that will be used frequently and these are:

Show Score:

$> gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x002a|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n' 

Submit Flag:

$> gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x002c -n $(echo -n "some flag value"|xxd -ps) 

Bleah

So initially I thought I would use bleah, it seemed like the latest tool and had the easiest to read output. However as you will see I decided against this as I felt I wouldn't learn as much just plowing through the challenges this way, however here is a quick demonstration:

First lets get a list of devices (output below only shows the CTF device)

$> bleah
@ Scanning for 5s [-128 dBm of sensitivity] ...
 
┌ 24:0a:c4:9a:7b:8e (-46 dBm) ──────────────────────────────────────────┐
│ Vendor                │ Espressif                                     │
│ Allows Connections    │ ✓                                             │
│ Address Type          │ public                                        │
│ Tx Power              │ u'eb'                                         │
│ Complete 16b Services │ '000000ff-0000-1000-8000-00805f9b34fb'        │
│ Complete Local Name   │ BLECTF                                        │
│ Flags                 │ LE General Discoverable, BR/EDR Not Supported │
└───────────────────────┴───────────────────────────────────────────────┘

Then enumerate that device:

$> bleah -b "24:0a:c4:9a:7b:8e" -e
-snip same as above-
@ Enumerating all the things ...
 
@ Enumerating all the things ...
 
┌──────────────┬────────────────────────────────────────────────────────────┬─────────────┬─────────────────────────────────────┐
│ Handles      │ Service > Characteristics                                  │ Properties  │ Data                                │
├──────────────┼────────────────────────────────────────────────────────────┼─────────────┼─────────────────────────────────────┤
│ 0001 -> 0005 │ Generic Attribute ( 00001801-0000-1000-8000-00805f9b34fb ) │             │                                     │
│ 0003         │   Service Changed ( 00002a05-0000-1000-8000-00805f9b34fb ) │ INDICATE    │                                     │
│              │                                                            │             │                                     │
│ 0014 -> 001c │ Generic Access ( 00001800-0000-1000-8000-00805f9b34fb )    │             │                                     │
│ 0016         │   Device Name ( 00002a00-0000-1000-8000-00805f9b34fb )     │ READ        │ u'2b00042f7-snip-056c4b410d28f33cf' │
│ 0018         │   Appearance ( 00002a01-0000-1000-8000-00805f9b34fb )      │ READ        │ Unknown                             │
│ 001a         │   Central Address Resolution ( -snip )                     │ READ        │ '\x00'                              │
│              │                                                            │             │                                     │
│ 0028 -> ffff │ 00ff ( 000000ff-0000-1000-8000-00805f9b34fb )              │             │                                     │
│ 002a         │   ff01 ( 0000ff01-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Score: 0/20'                      │
│ 002c         │   ff02 ( 0000ff02-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'Write Flags Here'                 │
│ 002e         │   ff03 ( 0000ff03-0000-1000-8000-00805f9b34fb )            │ READ        │ u'd2053-snip-ff44835'              │
│ 0030         │   ff04 ( 0000ff04-0000-1000-8000-00805f9b34fb )            │ READ        │ u'MD5 of Device Name'               │
│ 0032         │   ff05 ( 0000ff05-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'Write anything here'              │
│ 0034         │   ff06 ( 0000ff06-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'Write the ascii value "yo" here'  │
│ 0036         │   ff07 ( 0000ff07-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'Write the hex value 0x07 here'    │
│ 0038         │   ff08 ( 0000ff08-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Write 0xC9 to handle 58'          │
│ 003a         │   ff09 ( 0000ff09-0000-1000-8000-00805f9b34fb )            │ WRITE       │                                     │
│ 003c         │   ff0a ( 0000ff0a-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'Brute force my value 00 to ff'    │
│ 003e         │   ff0b ( 0000ff0b-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Read me 1000 times'               │
│ 0040         │   ff0c ( 0000ff0c-0000-1000-8000-00805f9b34fb )            │ NOT RD WRI  │ u'Listen to me for a notification'  │
│ 0042         │   ff0d ( 0000ff0d-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Listen to 0x0044 for a indication'│
│ 0044         │   ff0e ( 0000ff0e-0000-1000-8000-00805f9b34fb )            │ READ IND WRI│                                     │
│ 0046         │   ff0f ( 0000ff0f-0000-1000-8000-00805f9b34fb )            │ NOT READ WRI│ u'Listen to me for multi notific    │
│ 0048         │   ff10 ( 0000ff10-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Lsn 0x004a for multi indications' │
│ 004a         │   ff11 ( 0000ff11-0000-1000-8000-00805f9b34fb )            │ READ IND WRI│                                     │
│ 004c         │   ff12 ( 0000ff12-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Cnt with BT MAC 11:22:33:44:55:66'│
│ 004e         │   ff13 ( 0000ff13-0000-1000-8000-00805f9b34fb )            │ READ        │ u'Set your connection MTU to 444'   │
│ 0050         │   ff14 ( 0000ff14-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u"Write+resp 'hello'  "             │
│ 0052         │   ff15 ( 0000ff15-0000-1000-8000-00805f9b34fb )            │ READ WRITE  │ u'No notifications here! really?'   │
│ 0054         │   ff16 ( 0000ff16-0000-1000-8000-00805f9b34fb )            │ -snip       │ u'So many properties!'              │
│ 0056         │   ff17 ( 0000ff17-0000-1000-8000-00805f9b34fb )            │ READ        │ u"md5 of author's twitter handle"   │
│              │                                                            │             │                                     │
└──────────────┴────────────────────────────────────────────────────────────┴─────────────┴─────────────────────────────────────┘

As you can see bleah is a very powerful tool to quickly identify and enumerate BLE devices. I'll use it's output as a reference at times, but for the most part try to rely on other tools.

Challenge 01 - Flag 1

This one was very simple, simply read the hint that gives you the flag.

Challenge 02 - Flag 0x002e

Again a simple one, simply read the value of the handle Flag 0x002e
I suppose now is a good a time as any to explain what a handle is.
I by no means am an expert here and have learnt this from various blog posts and guesswork. But basically BLE is a load of handles wrapped in a service. you can think of the service as a class and each handle a different method.
For some reason unbeknown to me the term "handle" and "characteristic" are used interchangeably.

Referring to the bleah output above we can see that all of the challenge handles are in the "000000ff-0000-1000-8000-00805f9b34fb" service, which can be shortened to 0xFF for most tools.

Each handle has a flag which describes what it is capable of (read, write, notify etc... we'll gett to these latter)

I hope that helps.. now back to the challenge, lets read that handle (0x002e):

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x002e|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 03 - Flag 0x0030

For this challenge simply submit the MD5 of the device's local name.
as we can see from the bleah output the device is called "BLECTF" however lets try this without bleah:

╰» hcitool -i hci0 lescan
LE Scan ...
24:0A:C4:9A:7B:8E BLECTF
╰» echo -n BLECTF | md5sum
5cd-snip-40f442ece036c6f4f06 -

It's also worth remembering that all flags are first 20 chars of md5, so simply truncate and send.

Challenge 04 - Flag 0x0016

This challenge is reading the name of the device - as you can see in the bleah output it's given away pretty easily, lets see how it would be done without bleah:

╰» gatttool -b 24:0a:c4:9a:7b:8e -I
[24:0a:c4:9a:7b:8e][LE]> connect
Attempting to connect to 24:0a:c4:9a:7b:8e
Connection successful
[24:0a:c4:9a:7b:8e][LE]> primary
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb <-- 14 to 1c
attr handle: 0x0028, end grp handle: 0xffff uuid: 000000ff-0000-1000-8000-00805f9b34fb
[24:0a:c4:9a:7b:8e][LE]> char-desc 01 05
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
[24:0a:c4:9a:7b:8e][LE]> char-desc 14 1c
handle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb <-- 2a00 == device name!
handle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
[24:0a:c4:9a:7b:8e][LE]> char-read-hnd 0016
Characteristic value/descriptor: 32 62 30 30 30 34 32 66 37 34 38 31 63 37 62 30 -snip- 31 30 64 32 38 66 33 33 63 66
╰» echo "32 62 30 30 30 34 32 66 37 34 38 31 63 37 62 30 -snip- 31 30 64 32 38 66 33 33 63 66"|xxd -r -p;printf '\n'

Again, truncate and send the result

Challenge 05 - Flag 0x0032

A fairly simple one, read and write to a handle:

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0032|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
Write anything here
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0032 -n $(echo -n "anything"|xxd -ps)
Characteristic value was written successfully
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0032|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 06 - Flag 0x0034

Pretty much the same as above, specifies sending ascii text

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0034|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
Write the ascii value "yo" here
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0034 -n $(echo -n "yo"|xxd -ps)
Characteristic value was written successfully
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0034|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 07 - Flag 0x0036

Same as above, this time hex

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0036|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
Write the hex value 0x07 here
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0036 -n 07
Characteristic value was written successfully
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0036|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 08 - Flag 0x0038

this time write to the handles int value rather than hex:

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0038|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
Write 0xC9 to handle 58
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 58 -n c9
Characteristic value was written successfully
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0038|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 09 - Flag 0x003c

OK so this one stumped me for ages!... it asks for "Brute force my value 00 to ff". I wrote some hideous python to brute-force it which I won't burden you with, however in the end I simply added gatttool in the python loop like so:

for x in range(255): # 255 == FF
    xhex = '0x{:02x}'.format(x)
    os.system('gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x3c -n '+xhex)

I'm not proud of this, but it worked. I did go back to solve it using just python as you will see later in the post!

Challenge 10 - Flag 0x003e

Half way through! not bad going so far...
This challenge wanted you to read the handle 1000 times.
I'm not sure why, possibly because of the hideous python I previously wrote but was already unlocked...
I didn't bother to reset the device to re-try this one, it's pretty simple!

Challenge 11 - Flag 0x0040

Time to learn about notifications and indications... they are pretty much the same (infact I see no difference whatsoever) with gatttool use the --listen flag to guess what... listen!

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0040 -n 0100 --listen
Characteristic value was written successfully
Notification handle = 0x0040 value: 35 65 63 -snip- 63 64 30 30 63 66 30 36 64 38 65 62
╰» echo "35 65 63 -snip- 63 64 30 30 63 66 30 36 64 38 65 62" | xxd -r -p
-solution-

Challenge 12 - Flag 0x0042

This is same as above but listening for an indication instead. You may have notices the -n flag in the previous command, well this specifies what to listen for: 0100 - notifications, 0200 - indications, 0300 - both. So yea, not sure why you would use the first two!

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0044 -n 0300 --listen
Characteristic value was written successfully
Indication handle = 0x0044 value: 63 37 62 -snip- 32 31 38 34 38 63 37 37 63 31 31 33 ^C
╰» echo "63 37 62 -snip- 32 31 38 34 38 63 37 37 63 31 31 33" | xxd -r -p
-solution-

Challenge 13 - Flag 0x0046

The device can send "multi notifications", I didn't realize this but that is what the --listen is for, with just the -n flag it will only wait for 1

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0046 -n 0300 --listen
Characteristic value was written successfully
Notification handle = 0x0046 value: 55 20 6e 6f 20 77 61 6e 74 20 74 68 69 73 20 6d 73 67 00 00
Notification handle = 0x0046 value: 63 -snip- 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64
Notification handle = 0x0046 value: 63 -snip- 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64
Notification handle = 0x0046 value: 63 -snip- 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64
Notification handle = 0x0046 value: 63 -snip- 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64
-snip-
╰» echo "55 20 6e 6f 20 77 61 6e 74 20 74 68 69 73 20 6d 73 67 00 00 63 -snip- 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64 " | xxd -r -p
U no want this msg-solution-

Challenge 14 - Flag 0x0048

Getting a bit repetitive now, could probably have done without this one... same as above but for indications. (also the hint was wrong)

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x004a -n 0300 --listen
Characteristic value was written successfully
Indication handle = 0x004a value: 55 20 6e 6f 20 77 61 6e 74 20 74 68 69 73 20 6d 73 67 00 00
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
Indication handle = 0x004a value: 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61
-snip-
╰» echo "55 20 6e 6f 20 77 61 6e 74 20 74 68 69 73 20 6d 73 67 00 00 62 -snip- 61 34 37 66 32 30 37 64 33 38 65 31 36 66 66 61 " | xxd -r -p
U no want this msg-solution-

Challenge 15 - Flag 0x004c

This one you need to spoof the client mac address, this is where the device you are using comes into play. I got lucky and both of my devices supported it, however from reading around your best bet would be a cambridge silione device.

╰» spooftooph -i hci0 -a 11:22:33:44:55:66 -n test
Manufacturer: Cambridge Silicon Radio (10)
Device address: 00:15:83:EE:17:41
New BD address: 11:22:33:44:55:66
Address changed
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x004c|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 16 - Flag 0x004e

This challenge wants you to change the message MTU to 444, gatttool has a --mtu flag, however it didn't work, I figured python would.. and it did, first time!

#! /usr/bin/python
 
import binascii
import struct
import sys
import bluepy.btle as btle
 
chall_uuid = 0x4e
 
p = btle.Peripheral("24:0a:c4:9a:7b:8e")
print ("Attached to peripheral")
services=p.getServices()
service=p.getServiceByUUID("000000ff-0000-1000-8000-00805f9b34fb")
 
p.setMTU(444)
 
hex = binascii.b2a_hex(p.readCharacteristic(chall_uuid))
hexstr = str(hex, 'utf-8')
print ("Response: " + hexstr) 
hexlif = binascii.unhexlify(hexstr).decode('utf8') # second step in tutorial
print ("Unhexlified: " + hexlif)
 
p.disconnect()

Challenge 17 - Flag 0x0050

So this one wants you to listen for a write response. I couldn't work out how I solved it as had been using the flag the whole time. but turns out if you use --char-write gattool doesn't listen for a response, unlike --char-write-req which does.

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0050|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
Write+resp 'hello'
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0050 -n $(echo -n "hello"|xxd -ps)
Characteristic value was written successfully
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0050|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
-solution-

Challenge 18 - Flag 0x0052

As you an see in the bleah output this handle doesn't show that it has notify enabled... but it does

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0052|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
No notifications here! really?
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0052 -n $(echo -n "hello"|xxd -ps) --listen
Characteristic value was written successfully
Notification handle = 0x0052 value: 66 63 -snip- 63 36 38 62 36 30 30 36 31 36 39 34 37 37 62
^C
╰» echo "66 63 -snip- 63 36 38 62 36 30 30 36 31 36 39 34 37 37 62" | xxd -r -p
-solution-

Challenge 19 - Flag 0x0054

When you look at this one in bleah you see "NOTIFY BROADCAST READ WRITE EXTENDED PROPERTIES" wow! not sure where to start I figured lets do the usual read and write

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0054|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
So many properties!
╰» gatttool -b 24:0a:c4:9a:7b:8e --char-write-req -a 0x0054 -n $(echo -n "test"|xxd -ps) --listen
Characteristic value was written successfully
Notification handle = 0x0054 value: 30 37 -snip- 63 63 34 38 ^C
╰» echo "30 37 -snip- 63 34 38" | xxd -r -p
07-snip-c48

OK so got half of the solution. So I tried many things here, literally spending hours throwing packets at it.. I decide to read the initial message again and the other half soluion was there?!

╰» gatttool -b 24:0a:c4:9a:7b:8e --char-read -a 0x0054|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
fb-snip-58f

So put them together and send to complete this challenge. After resetting the board a few times I realise I can just write anything and it would have changed the text! doh!

Challenge 20 - Flag 0x0056

"Send the first 20 chars of the authors twitter handle"

  1. https://github.com/hackgnar/ble_ctf
  2. find profile page: https://github.com/hackgnar/
  3. leads to: http://www.hackgnar.com/
  4. links to: @hackgnar
  5. md5 that shizz - d953bfb9846acc2e15eecd5b467a79aa
  6. First 20 chars and send to BLE

And that is all the challenges done. Challenge complete. But wait! I wasn't satisfied with my solution to Challenge 9 (the brute force one) and wanted to complete it in python.
So first I had to figure out how to send data to the handle in python, for this I re-did Challenge 06 (ascii) and 07 (hex):

06.py

#! /usr/bin/python
import binascii
import struct
import sys, os, time
import bluepy.btle as btle
 
chall_uuid = 0x34
 
p = btle.Peripheral("24:0a:c4:9a:7b:8e")
print ("Attached to peripheral")
services=p.getServices()
for service in services:
   print (service)
svc=p.getServiceByUUID(0x00FF)
print(svc)
 
hex = binascii.b2a_hex(p.readCharacteristic(chall_uuid))
hexstr = str(hex, 'utf-8')
print ("Response: " + hexstr) 
hexlif = binascii.unhexlify(hexstr) # second step in tutorial
hexlif = str(hexlif, 'utf-8')
print ("Unhexlified: " + hexlif)
 
response = p.writeCharacteristic(chall_uuid, bytes("yo", "utf-8"), True)
print (response) 
 
hex2 = binascii.b2a_hex(p.readCharacteristic(chall_uuid)) 
hexlif2 = binascii.unhexlify(hex2)
print(hexlif2)
 
p.disconnect()

07.py

#! /usr/bin/python
import binascii
import struct
import sys, os, time
import bluepy.btle as btle
 
chall_uuid = 0x36
#chall_char = UUID(0xFF0A)
 
p = btle.Peripheral("24:0a:c4:9a:7b:8e")
print ("Attached to peripheral")
services=p.getServices()
svc=p.getServiceByUUID(0x00FF)
print(svc)
 
hex = binascii.b2a_hex(p.readCharacteristic(chall_uuid))
hexstr = str(hex, 'utf-8')
print ("Response: " + hexstr) 
hexlif = binascii.unhexlify(hexstr)
hexlif = str(hexlif, 'utf-8')
print ("Unhexlified: " + hexlif)
 
x = 7
sendhex = bytes([x])
print (sendhex)
 
response = p.writeCharacteristic(chall_uuid, sendhex, True)
print (response) 

hex2 = binascii.b2a_hex(p.readCharacteristic(chall_uuid)) 
hexlif2 = binascii.unhexlify(hex2)
print(hexlif2)
 
p.disconnect()

I was then ready to solve Challenge 09 in python:

09.py

#! /usr/bin/python
import binascii
import struct
import sys, os, time
import bluepy.btle as btle
 
chall_uuid = 0x36
 
p = btle.Peripheral("24:0a:c4:9a:7b:8e")
print ("Attached to peripheral")
services=p.getServices()
for service in services:
   print (service)
svc=p.getServiceByUUID(0x00FF)
print(svc)
 
hex = binascii.b2a_hex(p.readCharacteristic(chall_uuid))
hexstr = str(hex, 'utf-8')
print ("Response: " + hexstr) 
hexlif = binascii.unhexlify(hexstr)
hexlif = str(hexlif, 'utf-8')
print ("Unhexlified: " + hexlif)
 
for x in range(255): # 255 == FF
	sendhex = bytes([x])
	print (sendhex)
	response = p.writeCharacteristic(chall_uuid, sendhex, True)
	print (response) 
 
	hex2 = binascii.b2a_hex(p.readCharacteristic(chall_uuid)) 
	hexlif2 = binascii.unhexlify(hex2)
	hexlif2 = str(hexlif2, 'utf-8')
	print(hexlif2)
 
	if hexlif2 != hexlif:
		break
 
p.disconnect()

And that is how I solved the BLE CTF!
Massive thank you to Ryan Holeman AKA hackgnar for making this awesome challenge, and bit thanks to Mantis for giving me the device to play with.

It's been a lot of fun and I feel like I've learnt at least the fundamentals of BLE testing.

As always, feel free to leave questions in the comments (I'm not sure I'll be able to answer any, but will try) And if I've made any mistakes please let me know also.

Sharing is caring!

One thought on “BLE CTF Walkthrough

  1. Pingback: BLE Hacking – Yekki's Blog

Leave a Reply