用 西湖论剑IoT闯关赛 蓝牙赛题 理解 蓝牙协议

虽然之前总结过:关于蓝牙的漏洞研究,但对于蓝牙还是很懵,因为从来没有实践过,西湖论剑IoT比赛时,蓝牙的题目一个也没做出来。每次看到蓝牙都不知道在说哪一层的协议,看到wireshark抓的包也感觉之前看的蓝牙包不长这样啊。这次经过一段时间的研究,才大概的明白:(1)蓝牙的协议栈之所以复杂,是由于历史的变迁,以及兼容性的考虑,导致出现了(老的)经典蓝牙和(新的)低功耗蓝牙并存复杂的协议栈,单独来看这新老两个技术的协议栈,都没有很复杂,并且其结构都是很清晰的。(2)蓝牙的数据包在其从用户程序发送到空中的过程中,封包并非如TCP/IP协议仅仅将上一层的数据进行简单的封装就传递到下一层,相邻层之间的数据变换可能比较复杂,于是就导致了由于抓包的层次不同,看到的同一过程的数据的组织方式是不同的,典型就是在空口抓包以及在HCI层抓包。(3)另外以西湖论剑的三道蓝牙题目为例子,总结了主机控制蓝牙不同层次的收发包工具以及背后原理。

蓝牙协议

协议简介

新老并存是蓝牙协议栈复杂的主要原因,协议分层如图:

image

想了解最全面的蓝牙协议栈设计,可以去 蓝牙官网 找,目前最新的白皮书是:Bluetooth Core Specification v5.3

协议实现

谈协议分层总是很简单,因为上面这种图片随处可见,但其本质的内容是一个抽象的设计方案,而不是具体的实现方案(软件代码,硬件电路)。对于黑客来说,我们不仅仅关注抽象的协议设计上有没有问题,更关注的是协议的实现,因为设计一般都是经过世界上顶尖的大脑们反复推敲出来的,而实现可能就是某个开发者半夜一边吃外卖一边写出来的。协议设计的问题可能在白皮书中隐约看到,但实现的漏洞你是不可能从白皮书中看出来的,比如:

这些漏洞他们的本体在:

所以我们要了解的是,整个蓝牙的通信过程中,其数据处理的每一个过程究竟在哪?换种说法就是:每层的协议到底是软件实现还是硬件实现?如果是软件实现,那是什么层次的软件(应用代码、内核代码、还是芯片固件等等)?也就是具体协议的落地层次,可以参考:

主要就是三种架构方案,后两者的最大区别是:蓝牙app的业务代码与蓝牙协议栈是否运行在同一个处理器上。当然这也就会造成两者蓝牙模组/SoC的开发厂商提供的SDK的本质不同,单芯片的SDK主要完成编译烧录运行,而双芯片主要完成通信过程。

image

PC和手机一般用蓝牙的都是host+controller双芯片标准架构,其通信的HCI协议也是蓝牙官方规定好的。通过分析linux的蓝牙驱动,以及相关芯片的datasheet,都能看出来这些芯片不参与任何上层协议的实现工作:

而嵌入式设备上的使用的蓝牙,可能会采用单芯片整体方案或者自定义双芯片架构,也就是那些蓝牙模组/SoC。模组,模块,SoC其实这些概念用起来比较混淆:

可见网上卖的大部分模组,模块,使用起来都应该属于自定义双芯片架构,因为你看上面的开发,配置一下串口然后就能直接使用GATT协议进行工作了,可见模组中已经实现了比较完整的蓝牙协议栈了。单芯片整体方案最常见的例子就是ESP32,我们的业务代码和蓝牙协议栈代码都运行在一个处理器上:

ESP32拆解图 可见:ESP32中就封装了一个ESP的SoC和flash

image

其蓝牙协议栈的实现在:https://github.com/espressif/esp-idf/tree/master/components/bt,即我们开发的业务代码最终会和这个蓝牙协议栈一起编译,打包,然后烧录进esp32的flash中,由esp32的xtensa处理器来执行。

攻击技能

这里只讨论从空口对另一台蓝牙设备的攻击,不讨论本地对自身的蓝牙驱动或者蓝牙芯片的攻击。

对于协议的抽象设计和实现方法有了清晰的认知之后,就是什么东西实现在哪?怎么实现的? 我们从开发者的视角切换成攻击者。我们不仅会对漏洞的发现,原理更加明晰,而且还能更清楚的知道,我们如何发动一次攻击:即在什么协议层次?怎么发送攻击流量?怎么完成这个层次的流量抓取? 此时我们需要回答一个问题:

  • 问:基本所有的手机或电脑本身都是支持蓝牙的,那为什么还要其他的外置硬件才能进行某些场景下的安全研究呢?
  • 答:研究一个通信的过程,黑客主要有五个动作:收、发、抓、断、改。本机的硬件可能不支持某些动作,比如发畸形链路层报文:CC2541 SweynTooth BLE漏洞实测、抓空中其他设备的通信报文等等。

对于空中信号,完成基于中间人的断、改,一般通过拉长双方距离,然后采用中继设备来实现中间人,比如NFCGate。不过除了在通信的物理链路上做手脚,还可以在通信过程的软件实现处完成中间人,就像可以使用frida来hook掉android侧的app进而完成对蓝牙数据的修改一样,只要在关注的目标层次之前,篡改其未来要处理的数据即可。对于蓝牙的中间人我还没有调研过,这里还是主要说,收、发、抓这三个动作。

层次抓包

其实在通信过程的任何阶段,都可以想办法捕获通信内容,所说的常规方法只不过因为是现成的方案。

蓝牙抓包一般来说有如下几种办法:

方法 抓包位置 所需硬件 特点 方法说明
Ubertooth 空口 Ubertooth BLE/BR, open source 使用Ubertooth监听蓝牙通信
nRF52832 空口 nRF52832 only BLE nRF52832 Sniffer 抓包使用体验
cc2540 空口 cc2540 only BLE CC2540 USB Dongle 蓝牙抓包分析仪使用教程
hollong 空口 hollong only BLE Hollong 蓝牙4.0/4.1/4.2 BLE协议监控分析仪 文档
HCI接口 本机 本机蓝牙 only local 使用Ubuntu虚拟机抓Bluetooth报文
HCIlog 本机 本机蓝牙 only local Android Bluetooth HCI log 详解

抓包位置不同,捕获的数据包层次就不同,看起来的样子也不同,主要是两种,空口和HCI:

但是以上两个都不够直观,我们使用接下来的例题自己抓两个包:

可以清楚的对比两种报文的差异了,其实大差不差:

image

HCI和空口是蓝牙协议栈的不同层次,协议对两个层次的数据组织并不是简单的封装。这个差异最开始很让我困惑,因为我们太熟悉以太网的报文了,以至于理所应当的认为:数据在通信的每一个层次的流动就是简单做一些数据的包裹,即添加或删除一些头之类的操作。但其实数据在他的整个生命周期的过程,除了基本的包裹操作,还可以有非常多的变换,比如加密解密,编码解码等。这里的本质原因是:每个层次所考虑的问题不仅仅是对下层负责,可能还要在本层完成一些事情。

高级收发

攻击行为本质就是恶意数据的收发,任何包含发送数据的攻击都必然要有攻击的信道。

如果只是BLE应用层(ATT流量)的简单读写交互的话,nRF connect 这个手机软件就足够了,但当我们需要:

  • 攻击经典蓝牙
  • 在ATT层有复杂的交互
  • 攻击其他非ATT的底层协议

这时 nRF connect 就有些力不从心了,于是我们需要更高级的收发包方法,让我们能构造更丰富的恶意报文,所以我们需要尽量彻底的控制蓝牙设备,让其为我们工作。刚才我们说过,目前的手机以及PC都采用的是host+controller双芯片标准架构,所以由于硬件的限制,一般来说,我们只能构造链路层以上的报文。对于链路层和物理层的攻击,则需要更加可控的蓝牙设备,比如ESP32,Nordic52840,甚至是自己构建的SDR。这里我们只关注PC和手机平台作为攻击机:

攻击机 蓝牙设备 协议栈 原生API 顶层工具
linux PC PC蓝牙controller bluez D-Bus APIC socket API bluez toolsScapypybluezbluepypygattbluescan
android 手机蓝牙controller Fluoride java API nRF connect
iPhone 手机蓝牙controller 私有 Objective-C API nRF connect

bluez API 说明:Linux Bluetooth API Function Locations

在以上原生API的帮助下,我们在空口收发包的最低层次能到L2CAP。值得注意的是,HCI层协议是主机和控制器的交互界面,其自身的生命周期只存在于二者交互的过程中,而不存在于纯空口过程中。所以对于从空口上完成的HCI层攻击,还是发送其他层协议的报文,从而触发对端的HCI过程,进而发生攻击。

不过原生API的使用不够便捷与轻量,而linux的蓝牙攻击工具是生态最成熟的,基本都是python的库,只有bluez自带的用户态二进制工具除外。所以linux的PC是我们理想的攻击平台,但由于我们大都是使用linux虚拟机,其使用蓝牙设备的方式是和宿主机共享,在这种情况下可能会出现各种各样的问题,所以一般建议linux虚拟机独占一个蓝牙外设。比如我媳妇的惠普windows本中的linux虚拟机就可以使用共享本机的蓝牙设备正常攻击,而我的 MacBook Pro 上,虽然可以使用hciconfig看到蓝牙设备,但之后无法正常进行攻击,这里使用bluepy中的blescan进行测试。

image

所以当你尝试共享蓝牙设备给linux虚拟机不好使的情况下,才可能需要单独购买一个蓝牙USB外设。bluescan的官方文档中建议Ostran 奥视通 USB 蓝牙适配器 OST-105 CSR 8150 v4.0或者UD100 G03,我之前一直很奇怪为啥非得这俩蓝牙外设,他们多啥?这玩意淘宝一搜不一大堆么?后来仔细看看才发现,原来网上卖的蓝牙USB外设大部分没有linux的驱动,都是windows独占。另外这些蓝牙USB外设的信号也没有手机或者PC上自带的蓝牙芯片稳定,经常需要插拔,重新连接到虚拟机等重置操作。外设配置好后,就可以关注怎么控制外设收发包了,即linux上的蓝牙顶层工具,这些工具是各有特色:

工具 形态 底层 接口最低控制层次 特点
bluez tools 命令行 bluez HCI(BR/BLE) 基础:主要用于配置检查,能完成一些基本的正常业务数据包
Scapy python bluez HCI(BR/BLE) 收发:使用复杂,可在python层面直接控制HCI,组织数据包灵活
pybluez python bluez L2CAP(BR/BLE) 收发:成熟的python蓝牙库,对L2CAP、RFCOMM层的接口友好
bluepy python bluez GATT (BLE) 收发:GATT相关处理较多,扫描脚本blescan命令行直接可用
pygatt python gatttool GATT (BLE) 收发:将gatttool(bluez tools)封装成python接口
bluescan python bluepy , pybluez HCI(BR/BLE) 扫描:安恒海特实验室 Sourcell Xu 开发,安全向,主要用于扫描,Python 3.9以上适配

工具使用示例文章:

有了这些工具,学会了怎么使用这些工具配置,发包,扫描,就可以完成下面的题目了。

题目实践

2020西湖论剑IoT闯关赛系列Writeup(蓝牙部分)

题目概述:

image

硬件环境:

image

软件环境(ubuntu21.04虚拟机):

 lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 21.04
Release:	21.04
Codename:	hirsute
 uname -a         
Linux xuanxuan 5.11.0-22-generic #23-Ubuntu SMP Thu Jun 17 00:34:23 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
 python3 --version
Python 3.9.5
 pip list | grep -i blue
bluepy                 1.3.0
bluescan               0.6.4
PyBluez     

adv_sign

本题考查的层次为BLE的链路层,考查点是BLE广播报文的捕获与解析,需要了解的协议为:通用访问配置文件(GAP)

题目将flag信息编码到了BLE广播报文的 General Access Profile 中,所以使用任何可以嗅探到BLE广播报文的手段都可以完成此题,以下使用bluescan解题:

  sudo bluescan -m le
[WARNING] Before doing an active scan, make sure you spoof your BD_ADDR.
[INFO] LE active scanning on hci0 with timeout 10 sec


----------------LE Devices Scan Result----------------
Addr:        A6:50:92:7A:97:14 (Unknown)
Addr type:   public
Connectable: True
RSSI:        -72 dBm
General Access Profile:
    0xFE (Unknown): 74665a6d78415a323868
    0xFD (Unknown): 51475666596a56775147
    0xFC (Unknown): 596d786c
    Complete Local Name: BCM20702A

然后将数据拼起来解码:

 python3
>>> import base64
>>> base64.b64decode(bytes.fromhex('596d786c51475666596a5677514774665a6d78415a323868'))
b'ble@e_b5p@k_fl@go!'

send_l2cap

本题考查的层次为经典蓝牙的L2CAP和SDP层,考查点是SDP服务的发现以及L2CAP的协议格式,需要了解的协议为:逻辑链路控制和适配层协议(L2CAP)

首先使用bluescan扫描:

  sudo bluescan -m br
[INFO] BR scanning on hci0 with timeout 10.24 sec

Addr: A6:50:92:5A:93:14 (Unknown)
Page scan repetition mode: 1 (R1)
Reserved: 0x02
CoD: 0x000000
    Service Class: 0b0
    Major Device Class: 0b0, Miscellaneous
Clock offset: 0x616E
RSSI: -72
Extended inquiry response: None


  sudo bluescan -m sdp A6:50:92:5A:93:14
[INFO] Scanning...
Number of service records: 6 

Service Record
0x0000: ServiceRecordHandle (uint32)
	0x00010005
0x0001: ServiceClassIDList (sequence)
	11111111-1111-1111-1111-111111111111: unknown
0x0003: ServiceID (uuid)
	11111111-2222-3333-4444-555555555555: to be parsed
0x0004: ProtocolDescriptorList (sequence)
	0x0100: L2CAP
		PSM: 0x1031
	0x0100: L2CAP
	0x0100: L2CAP
0x0005: BrowseGroupList (sequence)
	0x1002: PublicBrowseRoot
0x0009: BluetoothProfileDescriptorList (sequence)
	22222222-2222-2222-2222-222222222222: unknown
0x0100: ServiceName (guess) (text)
	L2CAP Matryoshka
0x0101: ServiceDescription (guess) (text)
	What's the innermost part of this L2CAP Matryoshka?
0x0102: ProviderName (guess) (text)
	Sourcell Xu of HatLab, DBAPP Security

完成题目需要与目标建立L2CAP连接,并发送数据,所以可以参考 pybluezl2capclient.py 建立连接,最终的解题脚本如下:

#!/usr/bin/env python3
import sys
import bluetooth

sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
addr = "A6:50:92:5A:93:14"
port = 0x1031

recv = lambda       :  (print("[+] recv: "+str(sock.recv(1024))))
send = lambda data  :  (sock.send(bytes.fromhex(data)), print("[+] send: "+str(data)), recv())

print("[+] Trying to connect to %s on PSM %s..." % (addr,hex(port)))
sock.connect((addr, port))
print("Connected\n")
recv()

send('060001000aff0200ffff')
send('0800010002ff040041104000')
send('0800010004ff040041000F00')

recv()

send('0a004100060001000aff0200ffff')
send('0c0041000800010002ff040051104000')
send('0c0041000800010004ff040042000F00')

recv()

send('0800410004004200666c6167')
sock.close()

ubuntu21.04下我的蓝牙外设不稳定,后续攻击过程不需要bluescan,最终在ubuntu16.04下稳定执行:

  python3 send_l2cap.py
[+] Trying to connect to A6:50:92:5A:93:14 on PSM 0x1031...
Connected

[+] recv: b'Level1:ConnectMe'
[+] send: 060001000aff0200ffff
[+] recv: b'\x16\x00\x01\x00\x0b\xff\x12\x00\xff\xff\x00\x00PSM1041ForConn'
[+] send: 0800010002ff040041104000
[+] recv: b'\x0c\x00\x01\x00\x03\xff\x08\x00A\x00@\x00\x00\x00\x00\x00'
[+] send: 0800010004ff040041000F00
[+] recv: b'\n\x00\x01\x00\x05\xff\x06\x00@\x00\x00\x00\x00\x00'
[+] recv: b'\x1e\x00@\x00Level1:Passed,Level2:ConnectMe'
[+] send: 0a004100060001000aff0200ffff
[+] recv: b'\x1a\x00@\x00\x16\x00\x01\x00\x0b\xff\x12\x00\xff\xff\x00\x00PSM1051ForConn'
[+] send: 0c0041000800010002ff040051104000
[+] recv: b'\x10\x00@\x00\x0c\x00\x01\x00\x03\xff\x08\x00B\x00@\x00\x00\x00\x00\x00'
[+] send: 0c0041000800010004ff040042000F00
[+] recv: b'\x0e\x00@\x00\n\x00\x01\x00\x05\xff\x06\x00@\x00\x00\x00\x00\x00'
[+] recv: b'\'\x00@\x00#\x00@\x00WantGetFlag?SendMeInfoPayload"flag"'
[+] send: 0800410004004200666c6167
[+] recv: b'#\x00@\x00\x1f\x00@\x00flag{br0h1pIt_l@cab_watrx0sHka}'

板子串口数据:

[DEBUG] Peer socket name
        04:7F:0E:05:36:13
        0x1031
[INFO] Accepted connection from 04:7F:0E:05:36:13, PSM 0x1031
[DEBUG] level0data_level1signal, recv
< b'\x06\x00\x01\x00\n\xff\x02\x00\xff\xff'
        info_payload_len: 0x0006
        CID: 0x0001
        code: 0x0a
        identifier: 0xff
        length: 0x0002
        data: b'\xff\xff'
                InfoType: 0xffff
[INFO] Passed level0data_level1signal, L2CAP_INFOMATION
[DEBUG] level0data_level1signal, recv
< b'\x08\x00\x01\x00\x02\xff\x04\x00A\x10@\x00'
        info_payload_len: 0x0008
        CID: 0x0001
        code: 0x02
        identifier: 0xff
        length: 0x0004
        data: b'A\x10@\x00'
                PSM: 0x1041
                SCID: 0x0040
[INFO] Passed level0data_level1signal, L2CAP_CONNECTION
[DEBUG] level0data_level1signal, recv
< b'\x08\x00\x01\x00\x04\xff\x04\x00A\x00\x0f\x00'
        info_payload_len: 0x0008
        CID: 0x0001
        code: 0x04
        identifier: 0xff
        length: 0x0004
        data: b'A\x00\x0f\x00'
                DCID: 0x0041
                flags: 0x000f
                config_opts: b''
[INFO] Passed level0data_level1signal, L2CAP_CONFIGURATION
[DEBUG] level1data_level2signal, recv
< b'\n\x00A\x00\x06\x00\x01\x00\n\xff\x02\x00\xff\xff'
        info_payload_len: 0x0006
        CID: 0x0001
        code: 0x0a
        identifier: 0xff
        length: 0x0002
        data: b'\xff\xff'
                InfoType: 0xffff
[INFO] Passed level1data_level2signal, L2CAP_INFOMATION
[DEBUG] level1data_level2signal, recv
< b'\x0c\x00A\x00\x08\x00\x01\x00\x02\xff\x04\x00Q\x10@\x00'
        info_payload_len: 0x0008
        CID: 0x0001
        code: 0x02
        identifier: 0xff
        length: 0x0004
        data: b'Q\x10@\x00'
                PSM: 0x1051
                SCID: 0x0040
[INFO] Passed level1data_level2signal, L2CAP_CONNECTION
[DEBUG] level1data_level2signal, recv
< b'\x0c\x00A\x00\x08\x00\x01\x00\x04\xff\x04\x00B\x00\x0f\x00'
        info_payload_len: 0x0008
        CID: 0x0001
        code: 0x04
        identifier: 0xff
        length: 0x0004
        data: b'B\x00\x0f\x00'
                DCID: 0x0042
                flags: 0x000f
                config_opts: b''
[INFO] Passed level1data_level2signal, L2CAP_CONFIGURATION
info_payload_len1: 8
CID1: 65
info_payload_len2: 4
CID2: 66
payload2: b'flag'

gatt_safe_box

本题考查的层次为BLE的GATT层,考查点是GATT业务的猜测分析,需要了解的协议为:通用属性配置文件(GATT)

完成题目需要与目标完成GATT通信,可以参考 pygattsubscribe_indicate_thermometer_sample.py ,最终解题脚本如下:

import pygatt,time
from Crypto.Cipher import AES

kl  =  [b'VmYZWYe2xGpy1Ifk',
        b'm55GRyWz7jk6UL9O',
        b'7Dz2UyaPTYaINOhT',
        b'7DU4xpwOaBE9dVnu',
        b'5vquNX1PZuatGD4X',
        b'V6TNSErhXPgdJSZU',
        b'8rrkcBSw9928pxmj',
        b'rYA6xm9mP1gqdItZ',
        b'dxj4iwXPBRPM2uk4',
        b'lry0CrP5HDGL5VqY']

adapter = pygatt.GATTToolBackend()
adapter.start()
device = adapter.connect('82:56:42:A1:06:42')
print("connected successfully")

def log(handle, value):
    value = bytes.fromhex(value.hex())
    print(b"[+] recv: "+ value)

def battery(handle, value):
    value = bytes.fromhex(value.hex())
    key = kl[ int(int(value.hex(),16)/10) - 1  ]
    a = AES.new(key, AES.MODE_ECB)
    cipher =  a.encrypt('DBAPPSecurHatLab'.encode())
    device.char_write("11111111-1111-1111-1111-111111111110",cipher, wait_for_response=False)
    print(b"[+] key:    "+ key)
    print(b"[+] cipher: "+ cipher)

device.subscribe("00002a19-0000-1000-8000-00805f9b34fb",callback=battery, wait_for_response=False)
device.subscribe("11111111-1111-1111-1111-111111111110",callback=log, wait_for_response=False)

time.sleep(1000)

ubuntu21.04下我的蓝牙外设不稳定,最终在ubuntu16.04下稳定执行:

  python3 connet_gatt.py
connected successfully
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    rYA6xm9mP1gqdItZ'
b'[+] cipher: Mw\xed\xbd\xb0R\xc6_\x985J\x91\t\x8d\x8e\x9e'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    8rrkcBSw9928pxmj'
b'[+] cipher: \xc4\xc52\xb7+R\xe8\xb5\xc6\xbe\xa0\xbd\x1eJ\xc4\xdf'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    VmYZWYe2xGpy1Ifk'
b'[+] cipher: Vw-\x0b\xdc\xb6zz\x0f\xe79S\x80\xc0\x17)'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    7DU4xpwOaBE9dVnu'
b'[+] cipher: #\x93B\x0f\xd6kr~\xc6\xe8\xc5_g\xed u'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    dxj4iwXPBRPM2uk4'
b"[+] cipher: \xfe\xe0\t\xd9i\xd0\x9f\xc3`\x8a\xaf'\x8f7\x9db"
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    V6TNSErhXPgdJSZU'
b'[+] cipher: \xb7`\xe071P\xbb\x00w\xd05-\x95\xbb\xad\xcd'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    rYA6xm9mP1gqdItZ'
b'[+] cipher: Mw\xed\xbd\xb0R\xc6_\x985J\x91\t\x8d\x8e\x9e'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    rYA6xm9mP1gqdItZ'
b'[+] cipher: Mw\xed\xbd\xb0R\xc6_\x985J\x91\t\x8d\x8e\x9e'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    dxj4iwXPBRPM2uk4'
b"[+] cipher: \xfe\xe0\t\xd9i\xd0\x9f\xc3`\x8a\xaf'\x8f7\x9db"
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: DBAPPSecurHatLab'
b'[+] key:    V6TNSErhXPgdJSZU'
b'[+] cipher: \xb7`\xe071P\xbb\x00w\xd05-\x95\xbb\xad\xcd'
b'[+] recv: DBAPPSecurHatLab'
b'[+] recv: flag_6onT@ttach_bkdr'

板子串口输出:

hci0:   Type: Primary  Bus: UART
        BD Address: A6:50:92:7A:97:14  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING 
        RX bytes:916 acl:0 sco:0 events:36 errors:0
        TX bytes:428 acl:0 sco:0 commands:36 errors:0

[   80.348495] g_ether gadget: high-speed config #1: CDC Ethernet (ECM)
[INFO] Using /org/bluez/hci0
[INFO] Registering RootObject...
[INFO] mainloop run
[DEBUG] RootObject, GetManagedObjects
[INFO] RootObject registered
[DEBUG] BatteryLevelCharac StartNotify
[DEBUG] BackdoorCharac StartNotify
[INFO] Current battery level:  80
[INFO] Current key: b'rYA6xm9mP1gqdItZ'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 1
[INFO] Current battery level:  70
[INFO] Current key: b'8rrkcBSw9928pxmj'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 2
[INFO] Current battery level:  10
[INFO] Current key: b'VmYZWYe2xGpy1Ifk'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 3
[INFO] Current battery level:  40
[INFO] Current key: b'7DU4xpwOaBE9dVnu'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 4
[INFO] Current battery level:  90
[INFO] Current key: b'dxj4iwXPBRPM2uk4'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 5
[INFO] Current battery level:  60
[INFO] Current key: b'V6TNSErhXPgdJSZU'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 6
[INFO] Current battery level:  80
[INFO] Current key: b'rYA6xm9mP1gqdItZ'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 7
[INFO] Current battery level:  80
[INFO] Current key: b'rYA6xm9mP1gqdItZ'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 8
[INFO] Current battery level:  90
[INFO] Current key: b'dxj4iwXPBRPM2uk4'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 9
[INFO] Current battery level:  60
[INFO] Current key: b'V6TNSErhXPgdJSZU'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 10
[INFO] Current battery level:  100
[INFO] Current key: b'lry0CrP5HDGL5VqY'
[DEBUG] BackdoorCharac, WriteValue
[INFO] plaintext_bin b'DBAPPSecurHatLab'
[INFO] Hit count: 11
[INFO] Current battery level:  30
[INFO] Current key: b'7Dz2UyaPTYaINOhT'
[DEBUG] BatteryLevelCharac StopNotify
[DEBUG] BackdoorCharac StopNotify