通过blectf简单认识与ble的交互
基础知识
通用属性配置文件(GATT) 是 BLE(蓝牙低功耗)设备在建立连接后用于数据交换的协议框架。它定义了设备间如何通过一系列层次化的属性进行通信。GATT 结构中有三个核心概念:
- Profile(配置文件)
- Service(服务)
- Characteristic(特征)
它们的关系可以类比为嵌套结构:
一个 Profile 包含多个 Service
每个 Service 又包含一个或多个 Characteristic
在 BLE 的通信中,设备分为两类:
- 主机(Central/Master):发起连接的一方
- 从机(Peripheral/Slave):被连接的一方,通常持有具体的数据和功能
从机通常通过 Profile 来定义其提供的服务和功能。
在 GATT 层中,通信角色被进一步细化为:
- Server(服务端):保存数据(如 Characteristic),响应客户端请求
- Client(客户端):发起读取或写入请求,与服务端交互数据
Characteristic(特征)的组成:
- UUID:唯一标识
- Properties:定义行为(如读、写、通知)
- Value:当前值
- Descriptors:附加说明,如格式、权限等
通信方式:
- Client 向 Server 发送请求:读取(Read)或写入(Write)数据
- Server 主动推送数据给 Client:通过通知(Notify)
此外,还有一个更通用的术语 Attribute(属性),用于描述 BLE 中的一切数据单元。它可以包含 UUID、属性、值、描述符等,是构成 Characteristic 的基础元素,也是 GATT 传输的核心单位。
环境搭建
道具准备
- esp32开发板一片
- USB蓝牙适配器一个, 我用的是绿联CM390(如果电脑自带的蓝牙适配器可以兼容linux可以不需要)
环境安装
首先安装esptool用于烧录开发板
1 | sudo apt-get install esptool |
接着克隆ble_ctf仓库并烧录
1 | git clone https://github.com/hackgnar/ble_ctf |
flash_size可以根据自己的板子修改, 但不改问题也不大
等待烧录完成, 此时打开蓝牙可以扫描到一个BLECTF
常用工具
gatttool
命令行模式
1 | Usage: |
交互模式
1 | help Show this help |
bluetoothctl
虽然都说这个工具更好 但感觉使用体验上不如gatttool
1 | enu main: |
BLE_CTF
阅读Readme
查看分数
1 | gatttool -b de:ad:be:ef:be:f1 --char-read -a 0x002a|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n' |
提交flag
1 | gatttool -b de:ad:be:ef:be:f1 --char-write-req -a 0x002c -n $(echo -n "some flag value"|xxd -ps) |
作者还给出了共20个关卡的知识点所在
Flag | Description |
---|---|
Flag 1 | This flag is a gift and can only be obtained from reading the hint! |
Flag 0x002e | Learn how to read handles |
Flag 0x0030 | Read handle puzzle fun |
Flag 0x0016 | Learn about discoverable device attributes |
Flag 0x0032 | Learn about reading and writing to handles |
Flag 0x0034 | Learn about reading and writing ascii to handles |
Flag 0x0036 | Learn about reading and writing hex to handles |
Flag 0x0038 | Learn about reading and writing to handles differently |
Flag 0x003c | Learn about write fuzzing |
Flag 0x003e | Learn about read and write speeds |
Flag 0x0040 | Learn about single response notifications |
Flag 0x0042 | Learn about single response indicate |
Flag 0x0046 | Learn about multi response notifications |
Flag 0x0048 | Learn about multi response indicate |
Flag 0x004c | Learn about BT client device attributes |
Flag 0x004e | Learn about message sizes MTU |
Flag 0x0050 | Learn about write responses |
Flag 0x0052 | Hidden notify property |
Flag 0x0054 | Use multiple handle properties |
Flag 0x0056 | OSINT the author! |
0x1
flag1直接在readme中给我们了, 送分, 用于了解如何提交flag
1 | $gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x002c -n $(echo -n "12345678901234567890"|xxd -ps) |
0x2
Learn how to read handles
Check out the ascii value of handle 0x002e and submit it to the flag submision handle 0x002c. If you are using gatttool, make sure you convert it to hex with xxd. If you are using bleah, you can send it as a string value.
1 | $gatttool -b 14:2B:2F:C5:8A:56 --char-read -a 0x002e |
转为ascii也就是d205303e099ceff44835
提交
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x002c -n $(echo -n "d205303e099ceff44835"|xxd -ps) |
0x3
Read handle puzzle fun
Check out the ascii value of handle 0x0030. Do what it tells you and submit the flag you find to 0x002c.
还是先读
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-read -a 0x0030 |
得到结果转字符串MD5 of Device Name
Device Name也就是BLECTF了
提交
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x002c -n $(echo -n "5cd56d74049ae40f442e"|xxd -ps) |
0x4
Learn about discoverable device attributes
Bluetooth GATT services provide some extra device attributes. Try finding the value of the Generic Access -> Device Name.
查看Generic Access 的Device Name
首先查看主要服务
1 | $gatttool -b 14:2B:2F:C5:8A:56 --primary |
蓝牙标准规定的某些特殊服务或者特性存在着固定的UUID
00001800-0000-1000-8000-00805f9b34fb
就是Generic Access的固定UUID, 这个服务包含的特性是0x14 到 0x1c 范围
那么对该范围进行扫描
1 | $gatttool -b 14:2B:2F:C5:8A:56 --characteristics --start=0x0014 --end=0x001c |
其中短uuid 2A00就是Device Name(这也是固定的)
也就是handle 0x0015, 但0x0015只是特征值声明, 我们需要读取其特征值数据handle也就是0x0016
读取到后取结果20位即可
0x5
Learn about reading and writing to handles
Read handle 0032 and do what it says. Notice that its not telling you to write to the flag handle as you have been. When you find the flag, go ahead and write it to the flag handle you have used in the past flags.
让我们先读0032得到结果是Write anything here
那我们随便写一点东西
1 | $gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0032 -n $(echo -n "2b00042f7481c7b056c4"|xxd -ps) |
写完以后再次读取就变成了flag
0x6
Learn about reading and writing ascii to handles
Follow the instructions found from reading handle 0x0034. Keep in mind that some tools only write hex values while other provide methods for writing either hex or ascii
先读0x0034得到字符串Write the ascii value "yo" here
直接写就可以了
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0034 -n $(echo -n "yo"|xxd -ps) |
写完后再读变为flag
0x7
Learn about reading and writing hex to handles
Follow the instructions found from reading handle 0x0036. Keep in mind that some tools only write hex values while other provide methods for writing either hex or ascii
读取0x0036得到Write the hex value 0x07 here
直接写
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0036 -n 07 |
0x8
Learn about reading and writing to handles differently
Follow the instructions found from reading handle 0x0038. Pay attention to handles here. Keep in mind handles can be refrenced by integer or hex. Most tools such as gatttool and bleah allow you to specify handles both ways.
读取0x0038得到Write 0xC9 to handle 58
还是直接写
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 58 -n c9 |
0x9
Learn about write fuzzing
Take a look at handle 0x003c and do what it says. You should script up a solution for this one. Also keep in mind that some tools write faster than others.
读取0x003c得到Brute force my value 00 to ff
即暴力破解一个8比特位的数到0x003c
1 |
|
执行后再次读取即可
0xa
Learn about read and write speeds
Talke a look at handle 0x003e and do what it says. Keep in mind that some tools have better connection speeds than other for doing reads and writes. This has to do with the functionality the tool provides or how it uses cached BT connections on the host OS. Try testing different tools for this flag. Once you find the fastest one, whip up a script or bash 1 liner to complete the task. FYI, once running, this task takes roughly 90 seconds to complete if done right.
读取0x003e得到Read me 1000 times
读取1000次即可
1 |
|
最后就可以读出flag
0xb
Learn about single response notifications
Check out handle 0x0040 and google search gatt notify. Some tools like gatttool have the ability to subscribe to gatt notifications
读取得到Listen to me for a single notification
客户端可以向服务端请求通知一项特征值,当该特征可用时服务端会通知客户端,通知(notification)不需要客户端回应 ACK
使用命令发起请求监听
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0040 -n 00 --listen |
00可以是任意值没什么要求
0xc
Learn about single response indicate
Check out handle 0x0042 and google search gatt indicate. For single response indicate messages, like this challenge, tools such as gatttool will work just fine.
读取得到Listen to handle 0x0044 for a single indication
指示与通知差不多但区别在于指示需要我们回应
单指令其实和上一题没有区别
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0044 -n 11 --listen |
0xd
Learn about multi response notifications
Check out handle 0x0046 and do what it says. Keep in mind that this notification clallange requires you to recieve multiple responses in order to complete.
读取得到Listen to me for multi notifications
还是和上一题一样的的指令, 不过要多等一下
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0046 -n 11 --listen |
0xe
Learn about multi response indicate
Check out handle 0x0048 and google search gatt indicate. Keep in mind that this chalange will require you to parse multiple indicate responses in order to complete the chalange.
读取得到Listen to handle 0x004a for multi indications
还是一样的命令
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x004a -n 11 --listen |
0xf
Learn about BT client device attributes
Check out handle 0x004c and do what it says. Much like ethernet or wifi devices, you can also change your bluetooth devices mac address.
读取得到Connect with BT MAC address 11:22:33:44:55:66
也就是要修改设备的MAC地址
可以使用工具thxomas/bdaddr: Updated version of the bluez bdaddr tool
0x10
Learn about message sizes MTU
Read handle 0x004e and do what it says. Setting MTU can be a tricky thing. Some tools may provide mtu flags, but they dont seem to really trigger MTU negotiations on servers. Try using gatttool’s interactive mode for this task. By default, the BLECTF server is set to force an MTU size of 20. The server will listen for MTU negotiations, and look at them, but we dont really change the MTU in the code. We just trigger the flag code if you trigger an MTU event with the value specified in handle 0x004e. GLHF!
读取得到Set your connection MTU to 444
MTU是蓝牙单次数据传输能承载的最大字节数
可以直接通过命令行参数设置, 不过存在一些问题, 得使用交互模式
0x11
Learn about write responses
Check out handle 0x0050 and do what it says. This chalange differs from other write chalanges as your tool that does the write needs to have write response ack messages implemente correctly. This flag is also tricky as the flag will come back as notification response data even though there is no “NOTIFY” property.
读取得到Write+resp 'hello'
对于--char-write
和--char-write-req
差别就在于后者必须接受到目标的回复, 有更高的可靠性
所以这里直接写就可以了
1 | gatttool -b 14:2B:2F:C5:8A:56 --char-write-req -a 0x0050 -n $(echo -n "hello"|xxd -ps) |
0x12
Hidden notify property
Take a look at handle 0x0052. Notice it does not have a notify property. Do a write here and listen for notifications anyways! Things are not always what they seem!
读取得到No notifications here! really?
根据特征属性标志位
- 0x01:允许广播
- 0x02:允许读取
- 0x04:允许写入(无响应)
- 0x08:允许写入(带响应)
- 0x10:允许通知(无确认)
- 0x20:允许通知(带确认)
- 0x40:允许经过身份签名的写入
- 0x80:运行扩展属性
1 | handle = 0x0051, char properties = 0x0a, char value handle = 0x0052, uuid = 0000ff15-0000-1000-8000-00805f9b34fb |
0x0a属性本不应该有通知权限, 但因为源码虽然仍然使用了esp_ble_gatts_send_indicate发送通知, 所以依然可以接收到通知
0x13
Use multiple handle properties
Check out all of the handle properties on 0x0054! Poke around with all of them and find pieces to your flag.
读取得到So many properties!
我们可以看到该句柄具有很多权限
1 | handle = 0x0053, char properties = 0x9b, char value handle = 0x0054, uuid = 0000ff16-0000-1000-8000-00805f9b34fb |
可以写入也可以监听, 所以只需要写入一次读取再监听一次
即可得到完整的flag
0x14
md5 of author’s twitter handle