蓝牙

备注

如果你刚开始使用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

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

Scapy class: BluetoothMonitorSocket

Allows to capture all HCI transactions that are taking place over all HCI interfaces (including in BlueZ core). It is intended to perform monitoring of transactions, device attachment and removal, BlueZ logging...

Scapy class: BluetoothUserSocket

This socket interacts with a Bluetooth controller with complete and exclusive control of de device. This means that BlueZ will not try to take control of the interface and will not help you manage connections via this interface.

ScPy类: BluetoothHCISocket

Using HCI protocol, this socket interacts with a Bluetooth controller but does not have exclusive control over it, allowing BlueZ and other applications to still use the adapter to communicate with devices.

逻辑链路控制和适配层协议(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
>>> 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

接收所有事件

要开始从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 on top 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%'

Using Nordic Semiconductor's nRF Sniffer

Since Scapy >2.5.0, Scapy supports Wireshark's extcap interfaces. You can therefore use your USB nordic bluetooth dongle, provided that you have installed the Wireshark module properly.

>>> load_contrib("nrf_sniffer")
>>> load_extcap()
>>> conf.ifaces
Source           Index  Name                          Address
nrf_sniffer_ble  100    nRF Sniffer for Bluetooth LE  /dev/ttyUSB0-None
[...]
>>> sniff(iface="/dev/ttyUSB0-None", prn=lambda x: x.summary())
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_IND
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_IND
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_IND
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_NONCONN_IND
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_NONCONN_IND
NRFS2_PCAP / NRFS2_Packet / NRF2_Packet_Event / BTLE / BTLE_ADV / BTLE_ADV_IND