蓝牙¶
注解
如果你刚开始使用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非数据控制电路的操作。 (RTS , DTR 等)
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或更高版本。
打开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 .
Eddystone URL信标¶
此示例设置虚拟 `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`_ (安卓):
开始广告¶
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))
资源和参考资料¶
- `16-bit UUIDs for members`__: 出现在
EIR_CompleteList16BitServiceUUIDs
和EIR_ServiceData16BitUUID
.
- `16-bit UUIDs for SDOs`__: 标准开发组织使用的已注册UUID列表。
- `Company Identifiers`__: 公司ID列表,显示在
EIR_Manufacturer_Specific_Data.company_id
.
- `Generic Access Profile`__: 指定的类型ID列表和到规范定义的链接,这些定义显示在
EIR_Header
.