BLE-CTF低功耗蓝牙CTF挑战

学习自BLE_CTF低功耗蓝牙CTF挑战

环境搭建

项目地址:
ble_ctf · github

首先你需要淘宝购买一块ESP32的板子,随便买一块就行了

然后在kali虚拟机里输入如下命令(注意wsl不行,因为串口无法连接到wsl里面,还是虚拟机好一些)

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install esptool
首先得安装 esptool 用来烧录 esp32

git clone https://github.com/hackgnar/ble_ctf
cd ble_ctf
esptool.py -p /dev/ttyUSB0 -b 460800 --before default_reset --after hard_reset --chip esp32  write_flash --flash_mode dio --flash_size 2MB --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/ble_ctf.bin

查看蓝牙设备:hciconfig

激活:hciconfig hci0 up

查看蓝牙信息:sudo hciconfig hci0 lestates

给BLECTF上电,然后输入hcitool lescan,就可以扫描周围蓝牙设备了

由此可以得知蓝牙设备的MAC地址了

bug解决

Can’t init device hci0: Function not implemented (38)

这种情况是kali没有蓝牙适配器,淘宝买一个即可,我买的是CSR8510,对linux的支持比较好

connect to xx:xx:xx:xx:xx:xx: Connection refused (111)

装上蓝牙适配器之后,如果出现Connect refused,那么重启一下蓝牙服务即可

service bluetooth start

再不行,点击kali右上角的蓝牙图标,手动关闭打开一下

做题

gattool命令简介

GATT commands
  --primary                                 发现GATT服务
  --characteristics                         发现设备上所有的characteristics
  --char-read                               读某个characteristics,需要指定一个handle(句柄)
  --char-write                              写某个characteristics,需要指定一个handle,使用Write Without Response的方式
  --char-write-req                          写某个characteristics,需要指定一个handle,使用Write Request的方式
  --char-desc                               发现所有的Characteristics Descriptor
  --listen                                  监听Characteristics的notification或者indication

Primary Services/Characteristics arguments
  -s, --start=0x0001                        起始handle
  -e, --end=0xffff                          结束handle
  -u, --uuid=0x1801                         16比特或者128比特的UUID

Characteristics Value/Descriptor Read/Write arguments
  -a, --handle=0x0001                       通过handle来读写characteristic,后面接handle值
  -n, --value=0x0001                        写characteristic时候的参数,后面接具体的值

Application Options:
  -i, --adapter=hciX                        后面接设备描述, 如hci0等
  -b, --device=MAC                          远端设备的蓝牙地址
  -t, --addr-type=[public | random]         远端设备蓝牙地址的类型,默认为public
  -m, --mtu=MTU                             att协议的MTU大小
  -p, --psm=PSM                             制定gatt的PSM,默认值为0
  -l, --sec-level=[low | medium | high]     安全等级,默认为low
  -I, --interactive                         交互式模式

使用gatttool -b F4:65:0B:E7:6E:6A –char-read -a 0x002a|awk -F’:’ ‘{print $2}’|tr -d ‘ ‘|xxd -r -p;printf ‘\n’查看当前分数

关卡1

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "12345678901234567890"|xxd -ps)

熟悉一下怎么交flag

关卡2

请读取句柄(handle)0x002e 的 ASCII 值,并将其提交到用于 flag 提交的句柄 0x002c

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "6432303533303365303939636566663434383335")

关卡3

读取 BLE 设备上 GATT 句柄(handle)0x0030 的 ASCII 值,按照其中的指示操作,并将最终得到的 flag 提交到句柄 0x002c

这里的提示是获得设备名的md5值

那么自然就是BLECTF进行md5了

然后github主页说了md5只取前20字符

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "5cd56d74049ae40f442e"|xxd -ps)

关卡4

蓝牙 GATT 服务提供了一些额外的设备属性。尝试找出 “Generic Access” 服务中的 “Device Name” 值。

使用primary参数发现设备的服务

Generic Access(UUID:1800)和Generic Attribute(UUID:1801)

所以我们接下来要查一下,有关Generic Access服务的相关信息(UUID=1800)

gatttool -b F4:65:0B:E7:6E:6A --characteristics  --start=0x0014 --end=0x001c

可以看到handle16对应的是Device Name(UUID=2a00)

这里区分一下handle和value handle,value handle才是我们真正想要的那个

名称全称作用是否包含实际数据?
HandleAttribute Handle每个 GATT 属性(Attribute) 的唯一编号❌ 不一定
Value HandleCharacteristic Value Handle特征值(Characteristic Value) 的 handle✅ 是!
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "2b00042f7481c7b056c4"|xxd -ps)

关卡5

读取句柄 0032 并按照其指示操作。注意,它并没有让你像之前那样写入到 flag 句柄。当你找到 flag 后,请将其写入你过去用于提交 flag 的那个句柄中。

让我们在这里随便写点东西

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x0032 -n $(echo 123)

再次read就是flag了

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "3873c0270763568cf7aa"|xxd -ps)

关卡6

按照从读取句柄 0x0034 中获取的指令进行操作。请注意,某些工具仅支持写入十六进制(hex)值,而其他工具则同时提供写入十六进制或 ASCII 文本的方法。

提示写ascii码的“yo”

gatttool -b F4:65:0B:E7:6E:6A --char-read -a 0x0034|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf '\n'
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "c55c6314b3db0a6128af"|xxd -ps)

关卡7

请遵循从读取句柄 0x0036 中获取的指令。请注意,某些工具仅支持写入十六进制值,而其他工具则同时提供写入十六进制或 ASCII 文本的方法。

要我们把0x7写在这里

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x0036 -n 07     
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "1179080b29f8da16ad66"|xxd -ps)

关卡8

请遵循从读取句柄 0x0038 中获取的指令。注意此处的句柄。请记住,句柄可以用整数或十六进制表示,大多数工具(如 gatttool 和 bleah)都支持这两种方式指定句柄。

提示我们把C9写到句柄58里面

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 58 -n C9   
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "f8b136d937fad6a2be9f"|xxd -ps)   

关卡9

查看句柄 0x003c 并按照其指示操作。你应该为此编写一个脚本来实现自动化。同时请注意,某些工具的写入速度比其他工具更快。

让我们爆破它的值

#!/bin/bash

# 配置参数
DEVICE="F4:65:0B:E7:6E:6A"
HANDLE="0x003c"
DELAY=0.1  # 写入后等待时间(秒),可调

echo "开始爆破句柄 $HANDLE 的值 (00 -> ff)"

for i in $(seq 0 255); do
    # 格式化为两位十六进制
    hex_val=$(printf "%02x" $i)

    echo "尝试写入: $hex_val"

    # 写入值
    gatttool -b $DEVICE --char-write-req -a $HANDLE -n $hex_val > /dev/null 2>&1

    # 等待片刻,避免过快请求
    sleep $DELAY

    # 读取当前值
    read_value=$(gatttool -b $DEVICE --char-read -a $HANDLE | awk -F'[: ]' '{print $2}' | tr -d ' ')

    # 输出结果
    echo "写入 $hex_val -> 读回: $read_value"

    # 可选:检测是否匹配,例如如果读回等于写入,则标记
    if [ "$read_value" == "$hex_val" ]; then
        echo "✅ 匹配: $hex_val"
    fi

    # 可选:如果发现特殊行为,暂停或保存
    # 例如:如果返回值异常,可以 break 或 log
done

echo "爆破完成。"
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "933c1fcfa8ed52d2ec05"|xxd -ps)

关卡10

查看句柄 0x003e 并按照其指示操作。请注意,某些工具在执行读写操作时的连接速度优于其他工具,这取决于该工具提供的功能,或其如何利用主机操作系统上的蓝牙连接缓存。建议尝试使用不同的工具来获取此 flag。一旦找到速度最快的工具,就编写一个脚本或单行 Bash 命令来完成任务。提示:如果操作正确,该任务在运行后大约需要 90 秒完成。

提示要读取该句柄1000次,每次都用gatttool建立连接很明显太慢了,这里我们用gatttool的交互模式

gatttool -b F4:65:0B:E7:6E:6A -I << EOF
connect
$(for i in {1..10000}; do echo "char-read-hnd 0x003e"; done)
quit
EOF

之所以是10000不是1000是因为这里没有设置时延,所以干脆多读几次得了

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "6ffcd214ffebdc0d069e"|xxd -ps) 

关卡11

查看句柄 0x0040,并在 Google 上搜索 “gatt notify”。一些工具(例如 gatttool)具备订阅 GATT 通知的功能。

随便发个值,开启监听模式即可

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "3565633337373262636430306366303664386562")

关卡12

查看句柄 0x0042,并在 Google 上搜索 “gatt indicate”。对于像本次挑战这样的单次响应指示(indicate)消息,gatttool 等工具完全可以胜任。

这里其实就想告诉我们indicate和notify不一样,前者需要回应,后者不需要回应,但是在这里实用的命令是一样的

 gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "6337623836646431323138343863373763313133")

关卡13

查看句柄 0x0046,并按照它的提示操作。请注意,本次通知(notification)挑战要求你接收多条响应才能完成。

这次要接受多次notification

可以看到第一次是假的,第二次之后就是真的了

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "c9457de5fd8cafe349fd"|xxd -ps)

关卡14

查看句柄 0x0048,并在 Google 上搜索 “gatt indicate”。请注意,本次挑战要求你解析多条指示(indicate)响应才能完成。

和刚才一样的指令

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "b6f3a47f207d38e16ffa"|xxd -ps)

关卡15

查看句柄 0x004c,并按照它的提示操作。和以太网或 Wi-Fi 设备类似,你也可以更改蓝牙设备的 MAC 地址。

提示让我们修改我们的MAC地址为11:22:33:44:55:66

BT MAC:Bluetooth MAC Address 的缩写,即 蓝牙设备的 MAC 地址。


bdaddr 去修改 MAC 地址,出现如下错误

sudo apt-get install libbluetooth-dev

装一下依赖库即可

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "aca16920583e42bdcf5f"|xxd -ps)

关卡16

阅读句柄 0x004e 并照其指示操作。设置 MTU 可能是一件棘手的事情。虽然有些工具可能提供 MTU 标志,但它们似乎无法真正触发服务器上的 MTU 协商。建议使用 gatttool 的交互模式来完成此任务。默认情况下,BLECTF 服务器设置为强制 MTU 大小为 20。服务器会监听 MTU 协商并进行查看,但实际上我们在代码中并未更改 MTU。我们只是在你使用句柄 0x004e 中指定的值触发 MTU 事件时,触发相应的标志代码。祝你好运!

最大传输单元MTU(Maximum Transmission Unit,MTU),是指网络能够传输的最大数据包大小,以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。如果MTU超过了接收端所能够承受的最大值,或者是超过了发送路径上途经的某台设备所能够承受的最大值,就会造成报文分片甚至丢弃,加重网络传输的负担。如果太小,那实际传送的数据量就会过小,影响传输效率。

题目让我们把MTU设置成444

这里我们需要用交互模式,因为-m选项不会主动发起 MTU 协商请求

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "b1e409e5a4eaf9fe5158"|xxd -ps)

关卡17

请查看句柄(handle)0x0050,并按照它的指示操作。
本题与其他“写入类”挑战不同:你所使用的写入工具必须正确实现“写入响应”(Write Response ACK)机制。
此外,该 flag 的获取方式也比较 tricky(巧妙/棘手)——flag 会以“通知”(notification)的形式返回数据,尽管该特征(characteristic)并没有设置 “NOTIFY” 属性。

让我们使用–char-write-req方式写入hello

 gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x0050 -n $(echo -n "hello"|xxd -ps)   
gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "d41d8cd98f00b204e980"|xxd -ps)  

关卡18

查看句柄 0x0052。请注意它并没有“通知”(notify)属性。但你仍然要在这里执行写入操作,并且无论如何都要监听通知!事情往往并不像表面看起来那样!

虽然这么说,但还是可以监听的

随便写点东西采用监听模式就可以了

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "fc920c68b6006169477b"|xxd -ps) 

关卡19

仔细检查句柄 0x0054 的所有属性!对它们进行各种尝试(读、写、通知等),找出构成 flag 的碎片

这里的句柄属性是9b,对应权限如下

10011011  0x9b

10000000  0x80 Extended Properties
00010000  0x10 Notify
00001000  0x08 write
00000010  0x02 read
00000001  0x01 Broadcast

随便写点东西,得到一段flag

通过监听,还可以获得一段flag

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "fbb966958f07e4a0cc48"|xxd -ps) 

关卡20

gatttool -b F4:65:0B:E7:6E:6A --char-write-req -a 0x002c -n $(echo -n "d953bfb9846acc2e15ee"|xxd -ps)

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇