Bluetooth學習之esp32
在尋找IOT設備的攻擊面之路的時候,發現藍牙這塊的知識很薄弱,這次借著esp32+BLE_CTF這個組合來認識一下藍牙的協議棧以及藍牙之類的知識
藍牙簡介
在藍牙誕生之前是通過一些復雜的電纜線或者是紅外線,來實現設備與設備之間的通信的,藍牙的前生今世看下面的鏈接就差不多了,這里簡單介紹一下目前藍牙的現狀,目前的藍牙是由三部分所組成的,分別是BLE(低功耗藍牙),BT(經典藍牙),高速藍牙,他們三者都有各自的應用場景,同時還有Mesh網狀網絡技術支持成千個設備進行互聯互通,這不就是正好趕上IOT的大時代趨勢了嗎?
- 「硬核無線技術」系列視頻 藍牙篇(上)
- 「硬核無線技術」系列視頻 藍牙篇(下)
- 一文讀懂藍牙技術從 1.0 到 5.0 的前世今生
- 經典藍牙介紹

服務發現協議 (SDP/GAP)
SDP/GAP 是在所有藍牙設備上發現服務的基礎,這對于所有藍牙模型都是必不可少的,因為可以通過 SDP/GAP 設備信息、服務和服務的特性來查詢,然后可以在兩個或多個藍牙設備之間建立連接
射頻通信(RFCOMM/GATT&&ATT)
RFCOMM 協議用于藍牙中的電纜更換選項。它是一種簡單的傳輸協議,具有額外的規定,用于通過藍牙協議棧的 L2CAP 部分模擬 RS232 串行端口的九個電路。它支持使用串行通信的應用程序的大型基礎。它提供可靠的數據流、多重連接、流量控制和串行電纜線路設置
邏輯鏈路控制和適配 – 層 (L2CAP)
藍牙邏輯鏈路控制和適配層支持更高級別的多路復用、分段和數據包重組以及服務質量通信和組。該層不負責可靠性并使用 ARQ 來確保它
主機制器接口 (HCI)
HCI 為基帶控制器、鏈路管理器以及對硬件狀態和控制寄存器的訪問提供命令接口。該接口提供了訪問藍牙基帶功能的統一方法。主機控制傳輸層去除了傳輸依賴并提供了一個通用的驅動程序接口。核心規范中定義了三個接口:USB、RS-232 和 UART。
再往下就是硬件相關的信息處理,在此就不做過多介紹了,下面的BLE_CTF研究的是BLE中的GATT層,attribute是此層中最重要的信息,它包括包括service, characteristic,descriptor,每一個attribute都有handle、UUID、data、properties,在后面的bleah探測當中可以發現這幾個屬性,例如對于某個characteristic來說,他有個獨一無二的handle代表server里面的attribute table里面序號,有attribute properties代表這個characteristic的類型,之后是attribute value,后面是可以通過某些方法修改這些屬性的,這樣屬性映射到真實的設備上面就是一個個功能模塊!
ESP32環境搭建
配置的環境按照芯片文檔上面的就成功把環境拉起來,一定要看到下面的輸出才算配置完成
- 配置步驟
.Hello world!Restarting in 10 seconds...This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, silicon revision 1, 2MB external flashMinimum free heap size: 298968 bytesRestarting in 9 seconds...Restarting in 8 seconds...Restarting in 7 seconds...Restarting in 6 seconds...Restarting in 5 seconds...
搭建踩坑
- 設備管理器無法找到此設備:
- 可能一:USB線沒有數據傳輸功能
- 原因:有些比較便宜的USB線只能進行供電,不能進行數據傳輸,剪開看可以發現它只有地線和±5V
- 解決辦法:換條可以傳輸數據的線即可
- 可能二:供電不正常
- 原因:可能排線有點問題,供電不上
- 檢查辦法:用萬用表測試一下VCC和GND是否正常
- 可能三:芯片供電不正常
- 原因:可能排線有點問題,供電不上
- 檢查方法:用USB轉TTL的設備通過杜邦線連接ESP32,需要連接VCC,GUN,TX(轉換設備連接RX),再用串口連接工具看看有無輸出,下面為輸出樣例:
ets Jun 8 2016 00:22:57 rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)ets Jun 8 2016 00:22:57 rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)configsip: 0, SPIWP:0x00clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00mode:DIO, clock div:2load:0x3fff0008,len:8load:0x3fff0010,len:3464load:0x40078000,len:7828load:0x40080000,len:252entry 0x40080034I (44) boot: ESP-IDF v2.0-rc1-401-gf9fba35 2nd stage bootloaderI (45) boot: compile time 18:48:10 ...
- 識別不到COM口:
- CP210X驅動安裝鏈接
- 可能一:未安裝驅動
- 解決辦法:安裝CP210X驅動
我踩的坑就是上面這些....
BLE_CTF環境搭建
刷入固件
在識別到COM之后,ESP-IDF 4.3 Powershell輸入下面的命令,記得替換port,就可以直接將BLE_CTF的固件刷入ESP32里面
esptool.py --chip esp32 --port (yours port) \--baud 115200 --before default_reset --after hard_reset write_flash \-z --flash_mode dio --flash_freq 40m --flash_size detect \0x1000 build/bootloader/bootloader.bin \0x10000 build/gatt_server_service_table_demo.bin \0x8000 build/partitions_singleapp.bin
刷入之后,就能在藍牙識別中看見BLECTF這個設備,此時已經成功刷入固件了!
尋找MAC地址
在拉起來BLE_CTF之后,還需要知道它的MAC地址才能與它進行通信,筆者是用樹莓派來尋找它的MAC地址的,在kali和ubuntu都不太行,允許搜索附近的BLE設備的時候,報一個I/O設備的錯誤,解決不了,然后想到了樹莓派,最后成功得到ESP32的MAC地址
鏈接:
- Linux下藍牙工具:hcitool使用教程
- 樹莓派通過藍牙進行串口通訊
- 低功耗藍牙(BLE)的簡要學習分析
- 樹莓派進階之路 (022) - 串口篇 - 通過串口連接控制樹莓派
- 使用串口線連接樹莓派
- 樹莓派三種連接電腦的方式
下面是找到BLECTF的MAC地址:
? ~ sudo hcitool lescan LE Scan...44:17:93:5e:46:06 BLECTF...
開啟BLE_CTF之路
要想實現藍牙的收發包,有幾種方法來實現,下圖展示了具體是哪幾種方法:

gatttool介紹
鏈接:
- gatttool命令詳解
- BlueZ gatttool操作
bleah介紹
Traceback (most recent call last): File "/usr/local/bin/bleah", line 4, in <module> __import__('pkg_resources').run_script('bleah==1.0.0', 'bleah') File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 666, in run_script self.require(requires)[0].run_script(script_name, ns) File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 1446, in run_script exec(code, namespace, namespace) File "/usr/local/lib/python2.7/dist-packages/bleah-1.0.0-py2.7.egg/EGG-INFO/scripts/bleah", line 119, in <module> main() File "/usr/local/lib/python2.7/dist-packages/bleah-1.0.0-py2.7.egg/EGG-INFO/scripts/bleah", line 113, in main bleah = Bleah(args) File "/usr/local/lib/python2.7/dist-packages/bleah-1.0.0-py2.7.egg/bleah/scan.py", line 277, in __init__ self.start_scan() File "/usr/local/lib/python2.7/dist-packages/bleah-1.0.0-py2.7.egg/bleah/scan.py", line 344, in start_scan self.devices += self.scanner.scan(self.args.timeout) File "/usr/local/lib/python2.7/dist-packages/bluepy-1.3.0-py2.7.egg/bluepy/btle.py", line 881, in scan self.start(passive=passive) File "/usr/local/lib/python2.7/dist-packages/bluepy-1.3.0-py2.7.egg/bluepy/btle.py", line 818, in start self._startHelper(iface=self.iface) File "/usr/local/lib/python2.7/dist-packages/bluepy-1.3.0-py2.7.egg/bluepy/btle.py", line 281, in _startHelper self._lineq = Queue()TypeError: 'module' object is not callable
flag1
第一個flag目的在說明如何提交flag,執行下面的命令即可得到一個flag:
gatttool -b 44:17:93:5e:46:06 --char-write-req -a 0x002c -n $(echo -n "12345678901234567890"|xxd -ps)
參數介紹:
-b #指明設備的mac地址--char-write-req #寫入句柄并接受ack-a #指明設備的句柄
執行下面的命令可以得知目前的socre為多少:
gatttool -b 44:17:93:5e:46:06 --char-read -a 0x002a|awk -F':' '{print $2}'|tr -d ' '|xxd -r -p;printf ''
flag2
開始我們的奪旗之旅,hint告訴我們要去查看句柄0x002e的ascii值,有兩種方法可以查看:
第一種是bleah,它可以將此設備的所有屬性給列出來,所以相對來說它的速度要慢一些:
sudo bleah -b "44:17:93:5e:46:06" -e

第二種就是gatttool,它可以選擇輸出指定句柄的data:
? ~ gatttool -b 44:17:93:5e:46:06 --char-read -a 0x002e Characteristic value/descriptor: 64 32 30 35 33 30 33 65 30 39 39 63 65 66 66 34 34 38 33 35
將輸出的ascii轉換成字符串就可以了:
import binascii
str = "64 32 30 35 33 30 33 65 30 39 39 63 65 66 66 34 34 38 33 35"
list_str = list(str)while ' ' in list_str: list_str.remove(' ') print(binascii.unhexlify(''.join(list_str)))
也可以用命令行來轉換:
? ~ echo "64 32 30 35 33 30 33 65 30 39 39 63 65 66 66 34 34 38 33 35"|tr -d ' '|xxd -r -p;printf ''
其實就是linux命令,參考下面的鏈接
- Linux tr命令
- xxd命令功能
最后交上獲得的flag就能得分!!
sudo bleah -b "A4:C1:38:21:2C:E2" -e
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "d205303e099ceff44835"
flag3
此題要md5設備的名稱,這個名稱有點坑,一直以為是下圖的值的md5,導致直接卡死....

最后才知道是要將BLECTF進行md5...,md5的方法有很多就不介紹了:
? ~ echo -n "BLECTF"|md5sum 5cd56d74049ae40f442ece036c6f4f06 -
最后取20位作為flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "5cd56d74049ae40f442e"
flag4
此題才是上面找錯的值,Generic Access -> Device Name的data為2b00042f7481c7b056c4b410d28f33cf,同樣取20位提交:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "2b00042f7481c7b056c4"
flag5
此處提示"Write anything here",嘗試寫入"zyen"在這個句柄里面:
gatttool -b 44:17:93:5e:46:06 --char-write-req -a 0x0032 -n $(echo -n "zyen"|xxd -ps)
或者
sudo bleah -b "44:17:93:5e:46:06" -n 0x0032 -d "hello"

提交flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "3873c0270763568cf7aa"
flag6
和上題大差不差:
sudo bleah -b "44:17:93:5e:46:06" -n 0x0034 -d "yo"
最后查看答案:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "c55c6314b3db0a6128af"
flag7
還是一模一樣,只是將寫入的字符串改成了十六進制的數字:
sudo bleah -b "44:17:93:5e:46:06" -n 0x0036 -d "0x07"
提交得分:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "1179080b29f8da16ad66"
flag8
這題雖然沒有看到有58這個句柄,但是還是可以往這個句柄里面寫值的,猜測應該是隱藏了:
sudo bleah -b "44:17:93:5e:46:06" -n 0x003a -d '0xc9'
提交得分:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "f8b136d937fad6a2be9f"
flag9
這題就有點不一樣了,hint說要寫入一個值,但是沒有告訴你這個值具體的值是多少,只說這是一個00到ff的值,所以我們爆破這個值就好啦
import os
for i in range(0,256): bash = 'sudo bleah -b "44:17:93:5e:46:06" -n 0x003c -d \"' + '0x{0:02x}'.format(i) + '\"' print(bash) os.system(bash)
爆破完回去看就發現,那里已經出現flag了
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "933c1fcfa8ed52d2ec05"
flag10
這題hint說要讀此句柄1000次:
import os for i in range(0,1000): bash = 'gatttool -b 44:17:93:5e:46:06 --char-read -a 0x003e' os.system(bash)
腳本讀完目標句柄1000之后就會出現flag,提交
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "6ffcd214ffebdc0d069e"
flag11
題目提示:Listen to me for a single notification
- 通知和指示有什么不同?
- 低功耗藍牙:在 linux 中監聽通知/指示
- GATT 服務器和客戶端角色
notification只是通知,在某一個句柄是不斷發送一個value
indicate和notification一樣,只不過多了一個ACK的模式
gatttool -b 44:17:93:5e:46:06 --char-write-req --handle=0x0040 --value=0100 --listen
接收到:35 65 63 33 37 37 32 62 63 64 30 30 63 66 30 36 64 38 65 62
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "5ec3772bcd00cf06d8eb"
小tips:
0100 是獲取 notifications
0200 是獲取 indications
0300 兩個都獲取
0000 全部關閉
flag12
題目提示:Listen to handle 0x0044 for a single indication
剛剛講到indication是需要多發一個ACK的:
gatttool -b 44:17:93:5e:46:06 --char-write-req --handle=0x0040 --value=0200 --listen
出現flag,提交即可:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "c7b86dd121848c77c113"
flag13
監聽之后出現兩個兩個flag:
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 39 34 35 37 64 65 35 66 64 38 63 61 66 65 33 34 39 66 64
第一個拿去解碼之后為:"U no want this msg\x00\x00",很明顯不是flag,第二個解碼就為flag:c9457de5fd8cafe349fd,提交得分:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "c9457de5fd8cafe349fd"
flag14
同12題:
gatttool -b 44:17:93:5e:46:06 --char-write-req --handle=0x004a --value=0200 --listen
提交flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "b6f3a47f207d38e16ffa"
flag15
此題是需要修改MAC,但是修改的有點問題,暫時還沒解決
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "aca16920583e42bdcf5f"
flag16
用交互模式修改MTU為444就行:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "b1e409e5a4eaf9fe5158"
flag17
用--char-write-req參數指定數據即可:
gatttool -b 44:17:93:5e:46:06 --char-write-req -a 0x0050 -n $(echo -n "hello"|xxd -ps)
提交flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "d41d8cd98f00b204e980"
flag18
No notifications here! really?一樣去監聽notifications就行:
gatttool -b 44:17:93:5e:46:06 --char-write-req --handle=0x0052 --value=0200 --listen
提交flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "fc920c68b6006169477b"
flag19
此GATT屬性有NOTIFY BROADCAST READ WRITE EXTENDED PROPERTIES,前半段是寫句柄,后半段是監聽
gatttool -b 44:17:93:5e:46:06 --char-write-req --handle=0x0054 --value=0200 --listen
提交flag:
sudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "fbb966958f07e4a0cc48"
flag20
最后以md5作者的推特賬號提交,
echo -n "@hackgnar" | md5sumsudo bleah -b "44:17:93:5e:46:06" -n 0x002c -d "d953bfb9846acc2e15ee"
至此,已經完成所有BLECTF的內容!!!不過后面的題目耦合性有點大了...
總結
完成此CTF挑戰是為了更好地了解藍牙這個協議,為后面的研究打下一定的基礎,從GATT層面來看,某些藍牙設備也是存在一些問題的,可以通過這個來進行切入。
參考鏈接
BLECTF Capture_flag
BLUETOOTH LOW ENERGY CTF - WRITE UP
Bluetooth Protocol (Part 2): Types, Data Exchange, Security
BLUETOOTH FRAMEWORK AND RFCOMM PROTOCOL
Bluetooth: ATT and GATT
Bluetooth Protocol Stack
GATT Server and Client Roles