蓝牙

注解

如果你刚开始使用scapy,从 usage documentation 介绍了如何在以太网和IP上使用scapy。

警告

scapy不支持Windows上的蓝牙接口。

什么是蓝牙?

蓝牙是一种短程的,主要是点对点无线通信协议,在2.4GHz上运行。 `ISM band`_ _.

Bluetooth standards are publicly available 来自于 `Bluetooth Special Interest Group.`_ _

从广义上讲,蓝牙 不同的物理层协议:

蓝牙基本速率(BR)和增强数据速率(EDR)

这些是“经典”的蓝牙物理层。

BR 达到最高721kbit/s的有效速度。这被批准为 IEEE 802.15.1-2002 (V1.1)和 -2005 (V1.2)。

EDR 作为蓝牙2.0(2004)的可选功能引入。它可以达到2.1兆位/秒的有效速度,比BR的功耗更低。

在蓝牙4.0及更高版本中,不支持 低能 接口,除非它们标记为 dual-mode .

蓝牙高速(HS)

作为蓝牙3.0(2009)的可选功能引入,它通过提供 IEEE 802.11 (WiFi)作为另一种更高速的数据传输方式。节点协商切换 AMP .

这仅受标记为的蓝牙接口支持 +HS . 并非所有蓝牙3.0及更高版本的接口都支持它。

蓝牙低能量(BLE)

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

这只受标记为的蓝牙接口支持 +LE低能 --并非所有的蓝牙4.0和更高版本的接口都支持它。

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

蓝牙插座 (AF_BLUETOOTH

蓝牙有多种协议可通过 AF_BLUETOOTH 插座:

主机控制器接口(HCI) BTPROTO_HCI

ScPy类: BluetoothHCISocket

这是用于与蓝牙控制器通信的“基本”级接口。一切都是建立在这个之上的,这代表着接近物理层,就像一个人可以得到常规的蓝牙硬件一样。

逻辑链路控制和适配层协议(L2CAP) BTPROTO_L2CAP

ScPy类: BluetoothL2CAPSocket

它位于HCI之上,为更高级别的协议提供连接和无连接的数据传输。它提供协议复用、包分割和重新组装操作。

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

RFCOMM BluetoothRFCommSocket

ScPy类: BluetoothRFCommSocket

rfcomm是一种串行端口仿真协议,在L2CAP上运行。

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

Linux上的蓝牙

Linux的蓝牙栈是由 `the BlueZ project`_ _. `The Linux kernel contains drivers to provide access to Bluetooth`_ _使用HCI的接口,这些接口通过 AF_BLUETOOTH .

Bluez还为这些内核接口提供了一个用户空间伙伴。关键组成部分包括:

bluetoothd

提供通过D总线访问蓝牙设备的守护进程。

bluetoothctl

一个交互式命令行程序,它与 bluetoothd 超过D总线。

hcitool

直接与内核接口接口的命令行程序。

Support for Classic Bluetooth in bluez is quite mature 然而, `BLE is under active development`_ _.

第一步

注解

您必须将这些示例运行为 root . 这些只在Linux上测试过,需要scapy 2.4.3或更高版本。

验证蓝牙设备

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

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

打开HCI插座

scapy的第一步是打开基础蓝牙设备的HCI插座:

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

发送控制包

此数据包不包含任何操作(即:它不执行任何操作),但它将测试您是否可以通过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
>>> ans[0][1]
>>> p.show()
###[ HCI header ]###
  type= Event
###[ HCI Event header ]###
     code= 0xf
     len= 4
###[ Command Status ]###
        status= 1
        number= 2
        opcode= 0x0

接收所有事件

要开始从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 实际上不会在设备上启用任何混乱模式。

但是,这对于稍后将解释的其他一些命令很有用。

导入和导出数据包

Just like with other protocols ,您可以保存数据包以备将来在 libpcap 格式与 wrpcap

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

再装上 rdpcap

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

使用蓝牙低能耗

注解

这需要支持蓝牙4.0或更高版本的接口 BLE, either as a dedicated LE chipset or a dual-mode LE + BR/EDR 芯片组(如 `RTL8723BU`_ ②)

这些指令只在Linux上测试过,需要scapy 2.4.3或更高版本。早期版本中存在错误解码数据包。

这些例子假设你已经 opened a HCI socket (AS) bt

发现附近的设备

启用发现模式

使用以下选项启动活动发现模式:

>>> # 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>)

收集广告报告

有时你可以得到多重的 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}

筛选广告报告

# 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

设置广告

注解

更改广告在第一次更改之前可能不会生效。 stopped .

AltBeacon

AltBeacon _是由radius网络开发的一种近距离信标协议。此示例设置虚拟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())

一次 advertising has been started ,然后可以用 `Beacon Locator`_ _(安卓)。

注解

信标定位器v1.2.2 `incorrectly reports the beacon as being an iBeacon`_ _但这些值在其他方面是正确的。

艾地斯东

Eddystone _是谷歌开发的近程信标协议。这将使用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())

一次 advertising has been started ,然后可以用 `Eddystone Validator`_`Beacon Locator`_ (安卓):

../_images/ble_eddystone_url.png

伊贝肯

iBeacon _是由苹果公司开发的一种近距离信标协议,使用其制造商特定的数据字段。 Apple/iBeacon framing (以下)更详细地描述了这一点。

此示例设置虚拟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())

一次 advertising has been started ,然后可以用 `Beacon Locator`_ (安卓):

../_images/ble_ibeacon.png

开始广告

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

停止广告

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

资源和参考资料

苹果/ibeacon广播帧

注解

这描述了基于(有限的)公开信息的苹果蓝牙低能量广告的有线格式。它并不特定于在苹果操作系统上使用蓝牙。

iBeacon _是苹果的近距离信标协议。scapy包括一个控制模块, ibeacon ,用于与苹果的 BLE 广播:

>>> load_contrib('ibeacon')

Setting up advertising for iBeacon (上面)描述了如何广播一个简单的信标。

当调用此模块时 ibeacon ,苹果还有其他“子信息”,这些信息也在其特定于制造商的数据字段中发布,包括:

为了与这些其他广播兼容,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 .

有时人们可能会在一个广播中看到多个子消息,如切换和附近。这不是强制性的——也只有切换和附近的广播。

从苹果设备检查原始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%'