Matheus-Garbelini / sweyntooth_bluetooth_low_energy_attacks

Proof of Concept of Sweyntooth Bluetooth Low Energy (BLE) vulnerabilities.
267 stars 69 forks source link

Script can't find device unless a second app is scanning #9

Closed jandyman closed 4 years ago

jandyman commented 4 years ago

OK, this is a weird one. It's been happening for a while, but I thought I was imagining things. Using the link_layer_length_overflow script (probably others as well), the script gets stuck with the following line being repeated endlessly

TX ---> BTLE_ADV / BTLE_SCAN_REQ

That is, until I open a second app that is also looking for advertisements. This could be our specific BLE Host Application, but it also works to simply open LightBlue on my phone. It clearly shows that our device is advertising, but the mere act of opening LightBlue unwedges the python script and it proceeds normally. I hope I've stated this clearly.

I glossed over this while doing the testing, but now that I'm writing up a report I need to be more formal, because anyone else running this test will get stuck without knowing this trick, and it isn't acceptable to have this mystery hanging about.

How would I go about figuring out what is going on here? I do have an Ellisys Bluetooth Tracker, but must admit that I'm not an expert on using it. If it is necessary to gain that knowledge to get to the bottom of it, then I'll have to do that.

Thanks for all your help so far. You've been really responsive.

Matheus-Garbelini commented 4 years ago

Hi @jandyman thank you very much for the detailed description. What I believe is happening is that your device is advertising "random" addresses. By default, the link_layer_length_overflow script sends a scan request directed to devices with public address and wait for a scan request. When you open your app, the smartphone correctly identifies that the address of your device is random and send a correct scan request, which the device replies and sweyntooth script is able to detect and proceed (albeit sending a correct connection request)

I'll update the script to automatically work with random addresses and let you know. You can also do a tiny modification and it will work: In this lines: https://github.com/Matheus-Garbelini/sweyntooth_bluetooth_low_energy_attacks/blob/master/link_layer_length_overflow.py#L59-L71

Include a new parameter inside the BTLE_SCAN_REQ structure RxAdd=1 This parameter is used here for your reference: https://github.com/Matheus-Garbelini/sweyntooth_bluetooth_low_energy_attacks/blob/master/link_layer_length_overflow.py#L104

Let me know if it works with this tiny patch.

EDIT: BTLE_ADV instead of BTLE_SCAN_REQ

jandyman commented 4 years ago

You mean to the call to BTLE_SCAN_REQ?

Matheus-Garbelini commented 4 years ago

By default the script initializes this field as 0, which correspond to public address.If the peripheral uses random address, it ignores every request from sweyntooth (silly mistake, I'll update asap)

jandyman commented 4 years ago

Like this?:

scan_req = BTLE() / BTLE_ADV() / BTLE_SCAN_REQ( RxAdd=1, ScanA=master_address, AdvA=advertiser_address)

If so, then that gives this error:

Traceback (most recent call last): File "link_layer_length_overflow.py", line 72, in AdvA=advertiser_address) File "/Users/andy/SetPoint Medical Dropbox/Andy Voelkel/sweyntooth_bluetooth_low_energy_attacks-master/libs/scapy/base_classes.py", line 266, in call i.init(*args, **kargs) File "/Users/andy/SetPoint Medical Dropbox/Andy Voelkel/sweyntooth_bluetooth_low_energy_attacks-master/libs/scapy/packet.py", line 173, in init raise AttributeError(fname) AttributeError: RxAdd

EDIT: I think I misunderstood what you mentioned. Stand by while I figure out how to add the member to the structure.

jandyman commented 4 years ago

Still confused. To add the member, I would modify Bluetooth4LE.py?:

class BTLE_SCAN_REQ(Packet): name = "BTLE scan request" fields_desc = [ --- add RxAdd somehow to fields_desc?--- BDAddrField("ScanA", None), BDAddrField("AdvA", None) ]

def answers(self, other):
    return BTLE_SCAN_RSP in other and self.AdvA == other.AdvA
Matheus-Garbelini commented 4 years ago

@jandyman sorry, it's not on the BTLE_SCAN_REQ, it's on the BTLE_ADV. No need to change Bluetooth4LE.py

Update the following in link_layer_length_overflow.py.

def scan_timeout():
    scan_req = BTLE() / BTLE_ADV(RxAdd=1) / BTLE_SCAN_REQ(
        ScanA=master_address,
        AdvA=advertiser_address)
    driver.send(scan_req)
    start_timeout('scan_timeout', 2, scan_timeout)

# Send scan request
scan_req = BTLE() / BTLE_ADV(RxAdd=1) / BTLE_SCAN_REQ(
    ScanA=master_address,
    AdvA=advertiser_address)
driver.send(scan_req)
jandyman commented 4 years ago

OK, that helps. On the initial scan, the device is found. However, after the malformed packet is sent, subsequent attempts to see advertisements fail, until I once again fire up Lightblue, at which point the script recovers and continues. So we halfway there but not all the way. But from this initial result, your theory about random address seems valid.

jandyman commented 4 years ago

Good news! I found another instance of a call to the BTLE_ADV constructor in scan_timeout. I patched that, and now I'm passing with flying colors, no delays in advertising.

Should I just continue to patch all the scripts this way, or do you anticipate making a more global change to the code?

Matheus-Garbelini commented 4 years ago

Hi @jandyman thanks for your update. We will update the scripts this weekend to automatically detect random addresses. Writing just 1 to the RxAddr field works for your case but not for public address devices. I'll update you once the changes are made, but for your case, that solves the issue.

Thanks a lot for your tests and feedback Regards.

Matheus-Garbelini commented 4 years ago

@jandyman the repo is updated to work with random addresses such as your case. However, you don't need to re-run the tests as you had fixed this already. Regards.