Bluetooth reconnaissance on a Raspberry Pi
I wanted a cheap box I could leave in an office to answer two questions: what Bluetooth Low Energy devices are advertising here, and what do our own devices expose to anyone who connects without pairing. Fitness bands, smart locks, label printers, conference room kit and dev boards all advertise constantly, and plenty of them will let a stranger read or write GATT characteristics without any authentication at all.
A Raspberry Pi 3 or 4 has a Bluetooth 4.x/5 radio built in, which is enough for this. This was Raspbian Buster in October 2019, where Python 2 was still the default python.
Only point this at kit you own or have permission to test. Listening to advertisements is passive, but connecting to someone else's device and poking its characteristics is not.
Base install
Start from a fresh Raspbian image and bring it up to date:
sudo apt-get update && sudo apt-get dist-upgrade
sudo apt-get install bluez tshark python-pip python3-pip git \
libxml2 libxml2-dev libxslt1-dev
sudo usermod -aG wireshark pi
Say yes when the tshark installer asks whether non-root users can capture. Log out and back in for the group change.
For scripting captures from Python I used pyshark-legacy (the Python 2 branch of pyshark) and pexpect to drive bluetoothctl:
pip install pyshark-legacy pexpect
Look before you touch
BlueZ's bluetoothctl is enough to see what's around:
bluetoothctl
[bluetooth]# power on
[bluetooth]# scan on
[bluetooth]# devices
[bluetooth]# info AA:BB:CC:DD:EE:FF
info shows the advertised name, the address type (public or random), the service UUIDs in the advertisement and any manufacturer data. The address type tells you a lot. A device that uses a random resolvable address and changes it every few minutes is doing the privacy feature properly. One that advertises a fixed public address and a name like "Meeting Room 3" can be tracked and identified by anyone walking past.
To keep a record, capture the raw HCI traffic. btmon writes a btsnoop file Wireshark can open:
sudo btmon -w survey.btsnoop
or capture the Bluetooth interface with tshark directly (check the interface name with tshark -D, it's usually bluetooth0):
tshark -i bluetooth0 -w survey.pcapng
In Wireshark, the display filter bthci_evt.code == 0x3e (LE meta events) narrows an HCI capture down to the advertising reports and connection events.
Connect to your own device
For a device you own, see what it exposes without pairing:
bluetoothctl
[bluetooth]# connect AA:BB:CC:DD:EE:FF
[AA:BB:CC:DD:EE:FF]# menu gatt
[AA:BB:CC:DD:EE:FF]# list-attributes
[AA:BB:CC:DD:EE:FF]# select-attribute /org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/service000c/char000d
[AA:BB:CC:DD:EE:FF]# read
The questions I ask of each device:
- Which characteristics can be read without pairing? Device name and battery level are fine. Serial numbers, owner names, configuration or sensor history are not.
- Which can be written without pairing? A writable characteristic that unlocks, configures or resets something is the finding.
- Does it use LE Secure Connections, or legacy pairing with Just Works? Legacy pairing can be cracked from a captured pairing exchange.
- Does it stay connectable all the time, or only after a button press?
BLESuite
NCC Group's BLESuite wraps a lot of this in Python: scanning, GATT enumeration, reading and writing attributes, and replaying captured GATT traffic with ble-replay. It's built and tested on Debian, so it installs cleanly on Raspbian:
sudo apt-get install libbluetooth-dev libpython-dev python-sphinx \
libzbar-dev libzbar0
pip install gevent pycrypto prettytable sphinx-rtd-theme
git clone https://github.com/nccgroup/BLESuite.git
cd BLESuite
pip install -r requirements.txt
cd docs && make html && cd ..
sudo python setup.py install
The README says to use the copy of Scapy bundled in the repository rather than the one from PyPI, so don't add pip install scapy on top. The built documentation ends up in docs/_build/html and is the best reference for the API.
The optional bdaddr module, which changes the adapter's own address, only works on some chipsets. If the build fails on it, comment out the ext_modules = [c_ext], line in setup.py and install again.
Android logs as a bonus
If the device has a phone app, the phone's own Bluetooth log shows exactly what the app sends. On Android, turn on "Enable Bluetooth HCI snoop log" in Developer options, use the app, then pull a bug report:
sudo apt-get install android-tools-adb
adb bugreport bugreport.zip
The btsnoop log is inside the zip (on recent Android versions under FS/data/misc/bluetooth/logs/) and opens in Wireshark. It's the quickest way to find which characteristic the app writes to unlock or configure the device.
Today: BLESuite is Python 2 only and hasn't been updated in years. On a current Raspberry Pi OS I'd stick with bluetoothctl and btmon for this, and use the bleak Python library for scripting.