Skip to content

蓝牙重放攻击记录

买了一台蓝牙设备,想要电脑写一些不同的逻辑控制它,于是有了这篇文章。

步骤一:手机抓包

参考:https://www.cnblogs.com/eezhijun/p/17629196.html

用的小米手机:

  • 开发者选项中打开【蓝牙数据包日志】
  • 在开发者选项中打开【蓝牙调试日志】(没有的请忽略此步骤)
  • 拨号键输入##5959## 开启抓取
  • 拨号键再次输入##5959## 结束抓取

步骤二:Wireshark 分析

参考:https://zhuanlan.zhihu.com/p/45717775

用 wireshark 打开后发现有各种各样的包,但我们要找 Sent Write,可以在 info 列中排序以此来快速找到。

上图中有两种 write,0x25和0x29,由于下面全是 0x29,所以 0x29 才是我们发送的命令,而数据包中的 value 就是我们需要重放的数据。

步骤三:GattTool 复现

参考:https://zhuanlan.zhihu.com/p/45717775

第三步,使用 gattTool 工具尝试重放工具,这个只有 Linux 才有。没有 Linux 的话,最简单的就是用 U盘制作一个 Ubuntu 启动盘,启动的时候选择【尝试 Ubuntu】,这样也是可以使用终端的。

1. 寻找设备的地址,这个其实在 Wireshark 里面就可以找到,参考文章使用的另一种方法。

2. 输入命令 gatttool -b 94:a9:a8:2a:89:fc -I 使用interactive方式连接设备,先 connect,然后 char-write-req 发送我们要重放的数据即可。没错很神奇,不需要配对密钥。下图是参考文章里的图,一目了然。

3. 寻找对应的 UUID,这一步对于后续第四大步骤很重要,如参考文章的图所示,根据 handle 去找到对应的 UUID,并且记录下来。

步骤四:Python+Bleak复现

经过前三个步骤,我们现在有:第二步中找到的命令的 handle、命令的 value;第三步中找到的 UUID。

但这种命令行发送肯定不是最终想要的效果。第四步就是使用 python 的 bleak 包来完成,很棒的包,比其他蓝牙包要好很多。还有一个好处是在 windows 下也能重放攻击了。使用 bleak 的 write_gatt_char 可以达到步骤三中的效果,直接给一个样例代码。

import asyncio
from bleak import BleakScanner, BleakClient
import keyboard

# 先看看能不能寻找到设备
# while True:
#     devices = bluetooth.discover_devices(duration=20, lookup_names=True)
#     for addr, name in devices:
#         print(f'Devices: {addr}, {name}')
#     time.sleep(5)


target_addr = '94:a9:a8:2a:89:fc'

# move和reset就是要重放的value
move = "010201881300000000000000000000000000"
move = bytearray([int(move[i:i + 2], 16) for i in range(0, len(move), 2)])

reset = "060000840300000000000000000000000000"
reset = bytearray([int(reset[i:i + 2], 16) for i in range(0, len(reset), 2)])

uuid = "0000ff82-0000-1000-8000-00805F9B34FB"
print('uuid', uuid)

async def main():
    # device = await BleakScanner.find_device_by_address(target_addr, timeout=30)

    async with BleakClient(target_addr) as client:
        print('connect~')

        while True:
            # 根据键盘响应来进行不同的处理
            now_key = keyboard.read_key()
            if now_key == 'right':
                move[1] = 0x01 # 向右移动,修改对应位置的值
                # response==False 不等待返回数据
                await client.write_gatt_char(uuid, data=move, response=False)

            if now_key == 'r':
                await client.write_gatt_char(uuid, data=reset, response=False)


asyncio.run(main())

Comments