This tutorial assumes you have a modern Linux system or VM running BlueZ. The commands below should work in BlueZ 4.101 and BlueZ 5.x.
Finding Bluetooth DevicesThe most basic way to find local discoverable Bluetooth devices is to use
hcitool scan. In the following example, there are two discoverable devices near my laptop: a Nexus 4 and a wireless speaker:
$ hcitool scan Scanning ... 98:D6:XX:XX:XX:XX Nexus 4 00:0D:XX:XX:XX:XX Bluetooth Speaker
The left column is the device's BD ADDR (Bluetooth Device ADDRess). This address is unique to the device and is very similar to a WiFi or ethernet MAC address. The right column is the device's human-readable name, which the device sent us in response to our scan requests.
To get a little more information about a device, we can use
hcitool inq, another subcommand of
$ hcitool inq Inquiring ... 98:D6:XX:XX:XX:XX clock offset: 0x0000 class: 0x5a020c 00:0D:XX:XX:XX:XX clock offset: 0x5a75 class: 0x240404
This output again includes the BD ADDR, but this time it also includes the clock offset and class of device. Clock offset is a low-level value that can be ignored. Class of Device (CoD) tells us what type of device we're talking to.
You can decode CoD using a tool I wrote called btclassify. Running it with the above classes tells us these devices identify as a phone and a wearable headset:
$ ./btclassify.py 0x5a020c 0x240404 0x5a020c: Phone (Smartphone): Telephony, Object Transfer, Capturing, Networking 0x240404: Audio/Video (Wearable Headset Device): Audio, Rendering
Diving Deeper: ServicesNow that we know we have a phone and a headset (which is actually a speaker), we'd like to find out what services they run.
In Bluetooth service information is available via the Service Discovery Protocol, or SDP. BlueZ ships with
sdptoolfor querying SDP. The
browsesubcommand is typically the best tool for listing services. It has fairly verbose output, so it's useful to filter it using grep:
$ sdptool browse 98:D6:XX:XX:XX:XX | grep Service\ Name Service Name: Headset Gateway Service Name: Handsfree Gateway Service Name: AV Remote Control Target Service Name: Advanced Audio Service Name: Android Network Access Point Service Name: Android Network User Service Name: OBEX Phonebook Access Server Service Name: OBEX Object Push
Given the presence of "Android Network" services, we can conclude that this device is likely an Android smart phone. The other services are relatively typical for a phone. For instance, Headset and Handsfree are used with headsets and car audio systems, and the OBEX services are used for transferring contacts and sharing files.
Unfortunately when we try to run
sdptool browseagainst the speaker, we do not receive any records. Instead we can use the
recordssubcommand to receive these records. This command runs for 20 seconds before terminating, so don't worry if it appears to have hung:
$ sdptool records 00:0D:XX:XX:XX:XX Service RecHandle: 0x10001 Service Class ID List: "Audio Sink" (0x110b) Protocol Descriptor List: "L2CAP" (0x0100) PSM: 25 "AVDTP" (0x0019) uint16: 0x102 Profile Descriptor List: "Advanced Audio" (0x110d) Version: 0x0102 Service RecHandle: 0x10002 Service Class ID List: "AV Remote Target" (0x110c) Protocol Descriptor List: "L2CAP" (0x0100) PSM: 23 "AVCTP" (0x0017) uint16: 0x103 Profile Descriptor List: "AV Remote" (0x110e) Version: 0x0103 Service Name: Hands-Free unit Service RecHandle: 0x10004 Service Class ID List: "Handsfree" (0x111e) "Generic Audio" (0x1203) Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 1 Language Base Attr List: code_ISO639: 0x656e encoding: 0x6a base_offset: 0x100 Profile Descriptor List: "Handsfree" (0x111e) Version: 0x0105
Pay attention to the values after "Service Class ID List". This tells us the device has "Audio Sink", "AV Remote Target", "Handsfree", and "Generic Audio" services. These services make sense given that we know this is a speaker.
Both of these commands give a complete breakdown of all lower-level protocols used to implement the services. This information is not typically useful during general reconnaissance, but it can be useful when developing fuzzers.
One final thing to note is that
sdptoolworks even if a device is not discoverable. If you know a device's BD ADDR you can try to connect to it using
recordsto find out if it's nearby but undiscoverable.
Information Hidden by BlueZCertain devices return a bit more information that BlueZ does not display in
hcitooloutput. You can get at this information using
hcidumpor BlueZ 5's
hcidumpworks on all recent versions of BlueZ, I will demonstrate its use.
In one terminal run
hcidumpand tell it to log to a file:
$ sudo hcidump -w inquriy.cap
In another terminal run
$ hcitool inq Inquiring ... 00:26:XX:XX:XX:XX Richard Gill's MacBook Pro
Yowza, we can already see the name of the owner of a nearby laptop. Could be useful for social engineering. This naming convention is fairly common among Mac laptops. Worse, on at least some versions of Mac OS X when you put Bluetooth into discoverable mode it will remain in that mode indefinitely.
hcidumpand load the file it created in Wireshark. Filter the output to just inquiry responses using
bthci.evt_code == 0x2f. If the device is friendly, you will see information similar to the following screenshot:
Under "Extended Inquiry Response Data" you can see a list of service UUIDs, which will be fairly similar to the output of
sdptool. On the right I've highlighted a "manufacturer specific" field. This field helpfully tells us the specific model number of the laptop! This information is also highly useful for social engineering.
BLE ReconAll the of the above applies to classic Bluetooth devices, such as phones, headsets, speakers, and so forth. BLE devices are becoming increasingly common, and they require their own set of tools. Some examples of BLE devices are fitness wristbands, heart rate monitors, smart watches, proximity sensors, and so on.
Listing BLE DevicesThe most basic tool to list local BLE devices is
$ hcitool lescan LE Scan ... DC:A0:F2:B9:4F:9E (unknown) DC:A0:F2:B9:4F:9E Flex 00:22:XX:00:XX:XX (unknown) 00:22:XX:00:XX:XX Polar H7 00XXXX
I haven't censored the first device because it is using a random address that can vary over time, a BLE security feature that makes tracking devices more difficult.
Given a bit of a-priori knowledge, we can assume the first device is a FitBit Flex. The second device is a Polar H7 heart rate monitor.
Listing BLE ServicesRecent versions of BlueZ ship with
gatttoolfor querying BLE services over GATT. The
--primarycommand line switch connects to the device and asks it for a list of services:
$ gatttool --primary -b 00:22:XX:00:XX:XX attr handle = 0x0001, end grp handle = 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle = 0x000c, end grp handle = 0x000e uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle = 0x000f, end grp handle = 0x0014 uuid: 0000180d-0000-1000-8000-00805f9b34fb attr handle = 0x0015, end grp handle = 0x0023 uuid: 0000180a-0000-1000-8000-00805f9b34fb attr handle = 0x0024, end grp handle = 0x0026 uuid: 0000180f-0000-1000-8000-00805f9b34fb attr handle = 0x0027, end grp handle = 0xffff uuid: 6217ff49-ac7b-547e-eecf-016a06970ba9
The service UUID defines the service. UUIDs of the form
000018xx-0000-1000-8000-00805f9b34fbare generally 16-bit services that are assigned by the Bluetooth SIG. Information about these can be found on the GATT assigned numbers page.
Based on the UUIDs, we can see this device has "Generic Access", "Generic Attribute", "Heart Rate", "Device Information", and "Battery" services. The last UUID is a manufacturer-specific UUID. If you see another device with this service, it's likely a Polar H7.
Given the presence of the "Heart Rate" service we can assume this device is probably a heart rate monitor. The "Device Information Service" is more interesting, and I'll describe some fun tricks with that in the next section.
One thing to note: if you're trying to connect to a device using a random address, such as the FitBit Flex, you need to add the
-t randomcommand line flag. Let's list the services for that device:
$ gatttool -t random --primary -b DC:A0:F2:B9:4F:9E attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle = 0x0008, end grp handle = 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle = 0x0009, end grp handle = 0x000e uuid: adabfb00-6e7d-4601-bda2-bffaa68956ba attr handle = 0x000f, end grp handle = 0x0012 uuid: 558dfa00-4fa8-4105-9f02-4eaa93e62980 attr handle = 0x0013, end grp handle = 0x0018 uuid: 0000180a-0000-1000-8000-00805f9b34fb attr handle = 0x0019, end grp handle = 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb
This device has many services in common with the heart rate monitor, but there are two additional manufacturer-specific services. Seeing these services on another device indicates you're probably looking at a FitBit Flex.
Finally, to see a list of all characteristics you can use the
characteristicscommand in interactive mode. I will omit its output, since it's generally very long. Once you've found a characteristic you're interested in, you can try reading it using
Sensitive Information in Device Information ServiceThe "Device Information Service" is very interesting. From the SIG's page about it, we can see there is an optional field called "serial number". Clicking on the link brings us to the serial number string characteristic, which is assigned number 0x2a25. Let's use
gatttool's interactive mode to try to read it:
$ gatttool -I -b 00:22:XX:00:XX:XX [ ][00:22:XX:00:XX:XX][LE]> connect [CON][00:22:XX:00:XX:XX][LE]> char-read-uuid 2a25 [CON][00:22:XX:00:XX:XX][LE]> handle: 0x001b value: 30 30 30 33 3X 3X 3X 3X 3X 3X 00
This value is an ASCII representation of the serial number, which in this case is 0003XXXXXX. This value is likely unique and trackable.
Let's try that on the FitBit:
$ gatttool -t random -I -b DC:A0:F2:B9:4F:9E [ ][DC:A0:F2:B9:4F:9E][LE]> connect [CON][DC:A0:F2:B9:4F:9E][LE]> char-read-uuid 2a25 [CON][DC:A0:F2:B9:4F:9E][LE]> Read characteristics by UUID failed: No attribute found within the given range
Too bad, it doesn't have it. One other interesting UUID to query is the manufacturer name:
[CON][DC:A0:F2:B9:4F:9E][LE]> char-read-uuid 2a29 handle: 0x0015 value: 46 69 74 62 69 74 00 00 00 00 00 00 00 00 00 00 00 00 00
Converting this to ASCII gives us "FitBit", as expected.
One Last ThingUsing
gatttoolis nowhere near as reliable as the above makes it out to be. Connections will fail and drop all the time, even under controlled conditions. Just be patient and things generally work eventually.
Have fun doing Bluetooth recon!