Bluetooth

Note

如果您不熟悉Scapy,请从用法文档开始,该文档介绍了如何将Scapy与以太网和IP一起使用.

Warning

Scapy在Windows上不支持蓝牙接口.

What is Bluetooth?

Bluetooth is a short range, mostly point-to-point wireless communication protocol that operates on the 2.4GHz ISM band.

蓝牙标准可蓝牙特别兴趣小组 公开获得 .

广义地说,蓝牙具有三种不同的物理层协议:

Bluetooth Basic Rate (BR) and Enhanced Data Rate (EDR)

这些是"经典"蓝牙物理层.

BR的有效速度高达721kbit / s. 它被批准为IEEE 802.15.1-2002 (v1.1)和-2005 (v1.2).

EDR是蓝牙2.0(2004)的一项可选功能. 它可以达到2.1Mbit / s的有效速度,并且功耗比BR低.

在Bluetooth 4.0及更高版本中, 低功耗接口不支持此功能,除非将它们标记为double-mode .

Bluetooth High Speed (HS)

作为蓝牙3.0(2009)的一项可选功能而引入的,它通过提供IEEE 802.11 (WiFi)作为替代的高速数据传输来扩展蓝牙. 节点与AMP协商交换.

仅标记为+ HS的蓝牙接口支持此功能. 并非所有的蓝牙3.0和更高版本的接口都支持它.

Bluetooth Low Energy (BLE)

在蓝牙4.0(2010)中引入,这是专为低功耗嵌入式系统设计的备用物理层. 它具有更短的设置时间,更低的数据速率和更小的MTU尺寸. 除了点对点链接之外,它还添加了广播和网状网络拓扑.

仅标记为+ LE低能耗的蓝牙接口支持此功能-并非所有的蓝牙4.0及更高版本的接口都支持它.

PC上的大多数蓝牙接口都使用USB连接(即使在笔记本电脑上也是如此),这由主机控制器接口(HCI)控制. 这通常不支持混杂模式(嗅探),但是还有许多其他专用的非HCI设备支持它.

Bluetooth sockets (AF_BLUETOOTH)

There are multiple protocols available for Bluetooth through AF_BLUETOOTH sockets:

Host-controller interface (HCI) BTPROTO_HCI

Scapy类: BluetoothHCISocket

这是用于与蓝牙控制器通信的"基础"级别接口. 一切都建立在此之上,并且这代表着与常规蓝牙硬件所能达到的物理层几乎一样的物理层.

Logical Link Control and Adaptation Layer Protocol (L2CAP) BTPROTO_L2CAP

Scapy类: BluetoothL2CAPSocket

它位于HCI之上,它提供了到更高级别协议的连接和无连接数据传输. 它提供协议多路复用,数据包分段和重组操作.

与单个设备通信时,可以使用L2CAP通道.

RFCOMM BluetoothRFCommSocket

Scapy类: BluetoothRFCommSocket

RFCOMM是在L2CAP上运行的串行端口仿真协议.

除了常规的数据传输外,它还支持操纵RS-232的所有非数据控制电路( RTSDTR等).

Bluetooth on Linux

Linux的蓝牙堆栈由BlueZ项目开发. Linux内核包含使用HCI 提供对蓝牙接口的访问的驱动程序 ,该接口通过带有AF_BLUETOOTH套接字AF_BLUETOOTH .

BlueZ还为这些内核接口提供了用户空间伴侣. 关键组件是:

bluetoothd

一个守护程序,可通过D-Bus访问蓝牙设备.

bluetoothctl

一个交互式的命令行程序,可通过D-Bus与bluetoothd接口.

hcitool

一个直接与内核接口交互的命令行程序.

bluez中对Classic Bluetooth的支持已经相当成熟 ,但是BLE正在积极开发中 .

First steps

Note

您必须以root身份运行这些示例. 这些仅在Linux上经过测试,并且需要Scapy v2.4.3或更高版本.

Verify Bluetooth device

在执行其他任何操作之前,您需要检查操作系统是否已实际检测到您的蓝牙设备:

$ hcitool dev
Devices:
        hci0 xx:xx:xx:xx:xx:xx

Opening a HCI socket

Scapy的第一步是打开基础蓝牙设备的HCI套接字:

>>> # Open a HCI socket to device hci0
>>> bt = BluetoothHCISocket(0)

Send a control packet

该数据包不包含任何操作(即:不执行任何操作),但是它将测试您是否可以通过HCI设备进行通信:

>>> ans, unans = bt.sr(HCI_Hdr()/HCI_Command_Hdr())
Received 1 packets, got 1 answers, remaining 0 packets

然后,您可以检查响应:

>>> # ans[0] = Answered packet #0
>>> # ans[0][1] = The response packet
>>> p = ans[0][1]
>>> p.show()
###[ HCI header ]###
  type= Event
###[ HCI Event header ]###
     code= 0xf
     len= 4
###[ Command Status ]###
        status= 1
        number= 2
        opcode= 0x0

Receiving all events

要开始从HCI设备捕获所有事件,请使用sniff

>>> pkts = bt.sniff()
(press ^C after a few seconds to stop...)
>>> pkts
<Sniffed: TCP:0 UDP:0 ICMP:0 Other:0>

除非您的计算机通过蓝牙进行其他操作,否则此时您可能会收到0个数据包. 这是因为sniff实际上并没有在设备上启用任何混杂模式.

但是,这对于稍后将介绍的其他一些命令很有用.

Importing and exporting packets

就像其他协议一样 ,您可以使用wrpcaplibpcap格式保存数据包以备将来使用:

>>> wrpcap("/tmp/bluetooth.pcap", pkts)

并再次使用rdpcap加载它们:

>>> pkts = rdpcap("/tmp/bluetooth.pcap")

Working with Bluetooth Low Energy

Note

这需要一个支持BLE的Bluetooth 4.0或更高版本的接口,以专用的LE芯片组或双模式 LE + BR / EDR芯片组(例如RTL8723BU为准 .

这些说明仅在Linux上经过测试,并且需要Scapy v2.4.3或更高版本. 早期版本中存在一些错误,无法正确解码数据包.

这些示例假定您已经打开了HCI套接字 (如bt ).

Discovering nearby devices

Enabling discovery mode

通过以下方式启动活动发现模式:

>>> # type=1: Active scanning mode
>>> bt.sr(
...   HCI_Hdr()/
...   HCI_Command_Hdr()/
...   HCI_Cmd_LE_Set_Scan_Parameters(type=1))
Received 1 packets, got 1 answers, remaining 0 packets

>>> # filter_dups=False: Show duplicate advertising reports, because these
>>> # sometimes contain different data!
>>> bt.sr(
...   HCI_Hdr()/
...   HCI_Command_Hdr()/
...   HCI_Cmd_LE_Set_Scan_Enable(
...     enable=True,
...     filter_dups=False))
Received 1 packets, got 1 answers, remaining 0 packets

在后台,套接字上已经有HCI事件等待. 您可以使用sniff捕获这些事件:

>>> # The lfilter will drop anything that's not an advertising report.
>>> adverts = bt.sniff(lfilter=lambda p: HCI_LE_Meta_Advertising_Reports in p)
(press ^C after a few seconds to stop...)
>>> adverts
<Sniffed: TCP:0 UDP:0 ICMP:0 Other:101>

收到数据包后,请通过以下方式禁用发现模式:

>>> bt.sr(
...   HCI_Hdr()/
...   HCI_Command_Hdr()/
...   HCI_Cmd_LE_Set_Scan_Enable(
...     enable=False))
Begin emission:
Finished sending 1 packets.
...*
Received 4 packets, got 1 answers, remaining 0 packets
(<Results: TCP:0 UDP:0 ICMP:0 Other:1>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

Collecting advertising reports

有时你可以得到多个HCI_LE_Meta_Advertising_Report单一HCI_LE_Meta_Advertising_Reports ,而这些也可以是不同的设备!

# Rearrange into a generator that returns reports sequentially
from itertools import chain
reports = chain.from_iterable(
  p[HCI_LE_Meta_Advertising_Reports].reports
  for p in adverts)

# Group reports by MAC address (consumes the reports generator)
devices = {}
for report in reports:
  device = devices.setdefault(report.addr, [])
  device.append(report)

# Packet counters
devices_pkts = dict((k, len(v)) for k, v in devices.items())
print(devices_pkts)
# {'xx:xx:xx:xx:xx:xx': 408, 'xx:xx:xx:xx:xx:xx': 2}

Filtering advertising reports

# Get one packet for each device that broadcasted short UUID 0xfe50 (Google).
# Android devices broadcast this pretty much constantly.
google = {}
for mac, reports in devices.items():
  for report in reports:
    if (EIR_CompleteList16BitServiceUUIDs in report and
        0xfe50 in report[EIR_CompleteList16BitServiceUUIDs].svc_uuids):
      google[mac] = report
      break

# List MAC addresses that sent such a broadcast
print(google.keys())
# dict_keys(['xx:xx:xx:xx:xx:xx', 'xx:xx:xx:xx:xx:xx'])

查看收到的第一个广播:

>>> for mac, report in google.items():
...   report.show()
...   break
...
###[ Advertising Report ]###
  type= conn_und
  atype= random
  addr= xx:xx:xx:xx:xx:xx
  len= 13
  \data\
   |###[ EIR Header ]###
   |  len= 2
   |  type= flags
   |###[ Flags ]###
   |     flags= general_disc_mode
   |###[ EIR Header ]###
   |  len= 3
   |  type= complete_list_16_bit_svc_uuids
   |###[ Complete list of 16-bit service UUIDs ]###
   |     svc_uuids= [0xfe50]
   |###[ EIR Header ]###
   |  len= 5
   |  type= svc_data_16_bit_uuid
   |###[ EIR Service Data - 16-bit UUID ]###
   |     svc_uuid= 0xfe50
   |     data= 'AB'
  rssi= -96

Setting up advertising

Note

更改广告可能要等到广告第一次停止后才能生效.

AltBeacon

AltBeacon是Radius Networks开发的邻近信标协议. 此示例设置了一个虚拟AltBeacon:

# Load the contrib module for AltBeacon
load_contrib('altbeacon')

ab = AltBeacon(
    id1='2f234454-cf6d-4a0f-adf2-f4911ba9ffa6',
    id2=1,
    id3=2,
    tx_power=-59,
)

bt.sr(ab.build_set_advertising_data())

广告开始后 ,即可使用Beacon Locator (Android)检测信标 .

Note

Beacon Locator v1.2.2 错误地将 Beacon 报告为iBeacon ,但该值在其他方面是正确的.

Eddystone

Eddystone是Google开发的一种接近信标协议. 这使用特定于Eddystone的服务数据字段.

此示例设置了一个虚拟Eddystone URL信标:

# Load the contrib module for Eddystone
load_contrib('eddystone')

# Eddystone_URL.from_url() builds an Eddystone_URL frame for a given URL.
#
# build_set_advertising_data() wraps an Eddystone_Frame into a
# HCI_Cmd_LE_Set_Advertising_Data payload, that can be sent to the BLE
# controller.
bt.sr(Eddystone_URL.from_url(
  'https://scapy.net').build_set_advertising_data())

广告开始后 ,便可以使用Eddystone ValidatorBeacon Locator (Android)检测信标

../_images/ble_eddystone_url.png

iBeacon

iBeacon是Apple开发的一种接近信标协议,它使用其特定于制造商的数据字段. Apple / iBeacon框架 (如下)对此进行了详细说明.

此示例设置了一个虚拟iBeacon:

# Load the contrib module for iBeacon
load_contrib('ibeacon')

# Beacon data consists of a UUID, and two 16-bit integers: "major" and
# "minor".
#
# iBeacon sits ontop of Apple's BLE protocol.
p = Apple_BLE_Submessage()/IBeacon_Data(
   uuid='fb0b57a2-8228-44cd-913a-94a122ba1206',
   major=1, minor=2)

# build_set_advertising_data() wraps an Apple_BLE_Submessage or
# Apple_BLE_Frame into a HCI_Cmd_LE_Set_Advertising_Data payload, that can
# be sent to the BLE controller.
bt.sr(p.build_set_advertising_data())

广告开始后 ,即可使用Beacon Locator (Android)检测到信标

../_images/ble_ibeacon.png

Starting advertising

bt.sr(HCI_Hdr()/
      HCI_Command_Hdr()/
      HCI_Cmd_LE_Set_Advertise_Enable(enable=True))

Stopping advertising

bt.sr(HCI_Hdr()/
      HCI_Command_Hdr()/
      HCI_Cmd_LE_Set_Advertise_Enable(enable=False))

Resources and references

  • 成员的16位UUID :在EIR_CompleteList16BitServiceUUIDsEIR_ServiceData16BitUUID显示的已注册UUID列表.

  • 公司标识符 :公司ID列表,显示在EIR_Manufacturer_Specific_Data.company_id .

  • 通用访问配置文件 :分配的类型ID列表以及指向规范定义的链接,这些列表显示在EIR_Header .

Apple/iBeacon broadcast frames

Note

这基于(有限的)公开可用信息,描述了Apple的Bluetooth Low Energy广告的有线格式. 它并不特定于在Apple操作系统上使用蓝牙.

iBeacon是Apple的邻近信标协议. Scapy包含一个contrib模块ibeacon ,用于处理Apple的BLE广播:

>>> load_contrib('ibeacon')

为iBeacon设置广告 (如上所述)介绍了如何广播简单的信标.

虽然此模块称为ibeacon ,但Apple还具有其他"子消息",这些消息也在其制造商特定的数据字段中进行广告宣传,包括:

为了与这些其他广播兼容,Scapy中的Apple BLE框架位于Apple_BLE_SubmessageApple_BLE_Frame

  • HCI_Cmd_LE_Set_Advertising_DataHCI_LE_Meta_Advertising_ReportBTLE_ADV_INDBTLE_ADV_NONCONN_INDBTLE_ADV_SCAN_IND包含一个或多个…

  • EIR_Hdr ,可能具有一个有效载荷…

  • EIR_Manufacturer_Specific_Data ,可能具有一个有效载荷…

  • Apple_BLE_Frame ,其中包含一个或多个…

  • Apple_BLE_Submessage ,其中包含一个有效载荷…

  • Raw (如果不支持)或IBeacon_Data .

该模块目前仅支持IBeacon_Data消息. 其他子消息则解码为Raw .

有时,您可能会在一次广播中看到多个子消息,例如"切换"和"附近". 这不是强制性的-也有仅切换和仅附近广播.

从Apple设备检查原始的BTLE广告框架:

p = BTLE(hex_bytes('d6be898e4024320cfb574d5a02011a1aff4c000c0e009c6b8f40440f1583ec895148b410050318c0b525b8f7d4'))
p.show()

输出结果:

###[ BT4LE ]###
  access_addr= 0x8e89bed6
  crc= 0xb8f7d4
###[ BTLE advertising header ]###
     RxAdd= public
     TxAdd= random
     RFU= 0
     PDU_type= ADV_IND
     unused= 0
     Length= 0x24
###[ BTLE ADV_IND ]###
        AdvA= 5a:4d:57:fb:0c:32
        \data\
         |###[ EIR Header ]###
         |  len= 2
         |  type= flags
         |###[ Flags ]###
         |     flags= general_disc_mode+simul_le_br_edr_ctrl+simul_le_br_edr_host
         |###[ EIR Header ]###
         |  len= 26
         |  type= mfg_specific_data
         |###[ EIR Manufacturer Specific Data ]###
         |     company_id= 0x4c
         |###[ Apple BLE broadcast frame ]###
         |        \plist\
         |         |###[ Apple BLE submessage ]###
         |         |  subtype= handoff
         |         |  len= 14
         |         |###[ Raw ]###
         |         |     load= '\x00\x9ck\x8f@D\x0f\x15\x83\xec\x89QH\xb4'
         |         |###[ Apple BLE submessage ]###
         |         |  subtype= nearby
         |         |  len= 5
         |         |###[ Raw ]###
         |         |     load= '\x03\x18\xc0\xb5%'