|
| 1 | +# BLE-Fuzzer |
| 2 | + |
| 3 | +This is a test setup to apply protocol state fuzzing to Bluetooth Low Energy (BLE) devices. |
| 4 | +It is built upon the [ProtocolState-Fuzzer](https://github.com/protocol-fuzzing/protocol-state-fuzzer) framework and can be used to either test hardware devices over-the-air or to test the NimBLE stack in a Linux process. |
| 5 | + |
| 6 | + |
| 7 | + |
| 8 | +**src/** contains code that configures ProtocolState-Fuzzer (PSF) and acts as a bridge between PSF and the mapper. This is done using [jep](https://github.com/ninia/jep), which allows embedding a CPython interpreter in a Java process. |
| 9 | + |
| 10 | +**py/** contains the mapper. Different "flavors" exist, subclassing a generic mapper to deal with device specific behavior. The mapper uses [Scapy](https://github.com/secdev/scapy) to construct and parse BLE packets. |
| 11 | + |
| 12 | +**experiments/alphabets/** contains different alphabets (subsets of BLE packet types) that can be used for testing. |
| 13 | + |
| 14 | +**experiments/args/** contains test configurations (list of PSF arguments) for devices that have already been tested. |
| 15 | + |
| 16 | +**experiments/results/** contains results after tests have been run. |
| 17 | + |
| 18 | +**experiments/results_saved/** contains results of previous test runs. Mostly for comparison in the CI. |
| 19 | + |
| 20 | +**experiments/targets/** contains test-apps/firmware for devices that have been tested. |
| 21 | + |
| 22 | +**experiments/tests/** contains test sequences of interest. For example, specific test sequences can be run to reproduce bugs. |
| 23 | + |
| 24 | +**scripts/** contains miscellaneous scripts for resetting targets and for CI runs. |
| 25 | + |
| 26 | + |
| 27 | +## Getting Started |
| 28 | + |
| 29 | +1. Install ProtocolState-Fuzzer according to its [installation instructions](https://github.com/protocol-fuzzing/protocol-state-fuzzer?tab=readme-ov-file#installation) |
| 30 | +2. Set up and activate a python environment for ble-fuzzer: `source scripts/setup_venv.sh` |
| 31 | +3. Build ble-fuzzer: `mvn package` |
| 32 | +4. Build (and flash) one of the targets following the instructions in `experiments/targets/xxx` |
| 33 | +5. Flash the SweynTooth firmware to the test dongle following the [instructions below](#flashing-the-sweyntooth-firmware) |
| 34 | +6. Find out the MAC address of the device that is being tested (e.g. by using the "nRF Connect" app on a phone) |
| 35 | +7. Start learning: `java -jar target/ble-fuzzer-1.0-SNAPSHOT.jar @experiments/args/nRF52840_pairing -adapter /dev/device_4B8150861D56F596 -connect EB:D8:6B:33:90:0B` |
| 36 | + |
| 37 | + |
| 38 | +### Flashing the SweynTooth Firmware |
| 39 | + |
| 40 | +To test hardware devices, the nRF52840 dongle is used with the firmware developed in the [SweynTooth](https://github.com/Matheus-Garbelini/sweyntooth_bluetooth_low_energy_attacks) project to send BLE packets over-the-air. The firmware can be flashed to the dongle with the following steps: |
| 41 | + |
| 42 | +1. Download the [firmware](https://github.com/apferscher/ble-learning/blob/main/firmware/nRF52840_dongle_firmware.hex) and [softdevice](https://github.com/apferscher/ble-learning/blob/main/firmware/s140_nrf52_6.1.1_softdevice.hex) file |
| 43 | +2. Load both into the [nRF Connect for Desktop](https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-Desktop) app (under the "Programmer" app) |
| 44 | +3. Insert the the nRF52840 dongle and put it into bootloader mode |
| 45 | + - To get into bootloader mode, the small reset button needs to be pressed |
| 46 | + - Attention: The reset button is not the white button that's clearly visible. There's another button right next to it that goes sideways. |
| 47 | +4. Select the dongle in the programmer and flash the firmware |
| 48 | + |
| 49 | +Once the dongle is flashed, it should register a serial interface (e.g. `/dev/ttyACM0`). Since the number of the interface can vary if multiple devices are plugged in, I recommend creating a udev rule that allows identifying the device based on its serial number. To do that, create a file `/etc/udev/rules.d/85-serial.rules` with the contents: |
| 50 | + |
| 51 | +``` |
| 52 | +SUBSYSTEM=="tty",SUBSYSTEMS=="usb",DRIVERS=="usb",SYMLINK+="device_%s{serial}",MODE="0666" |
| 53 | +``` |
| 54 | + |
| 55 | +The dongle can then be referred to as `/dev/device_xxxxxxxxxxxxxxxx`. |
| 56 | + |
| 57 | + |
| 58 | +### Arguments |
| 59 | + |
| 60 | +For convenience, most required arguments for ProtocolState-Fuzzer have been collected in files under `experiments/args` and can be used on the command line by prefixing the file with an "@" (see [Getting Started](#getting-started) for an example). A full command to start learning a device would look like this: |
| 61 | + |
| 62 | +```sh |
| 63 | +java -jar target/ble-fuzzer-1.0-SNAPSHOT.jar state-fuzzer-server -output experiments/results/nRF52840_pairing -alphabet experiments/alphabets/pairing.xml -equivalenceQueryBound 5000 -logQueries -mapper nRF52840 -adapter /dev/device_4B8150861D56F596 -connect EB:D8:6B:33:90:0B |
| 64 | +``` |
| 65 | + |
| 66 | +**state-fuzzer-server** means that a server implementation (a peripheral) is being fuzzed. This is the only supported mode in this setup. |
| 67 | + |
| 68 | +**-output** allows specifying a path to a directory where the learned models and statistics will be written to. |
| 69 | + |
| 70 | +**-alphabet** allows specifying a file with the alphabet (input symbols) used for testing. If unspecified, the default (`src/main/resources/default_alphabet.xml`) will be used. |
| 71 | + |
| 72 | +**-equivalenceQueryBound** allows specifying how many test sequences should be used to check if a generated hypothesis corresponds to the actual behavior of the SUT. 5000 was found to be a good value when learning the paring procedure (and key re-negotiation) of BLE devices. |
| 73 | + |
| 74 | +**-logQueries** makes sure that the generated queries are logged for debugging. |
| 75 | + |
| 76 | +**-mapper** allows choosing a mapper for testing. If omitted, the generic mapper `py/BLESUL.py` will be used. If specified, the mapper `py/BLESUL_<mapper>.py` is used. |
| 77 | + |
| 78 | +**-adapter** must specify a serial interface via which the mapper sends/receives packets. This can be an interface to the BLE dongle used for testing or to the driver of the NimBLE stack when tested on Linux. |
| 79 | + |
| 80 | +**-connect** must specify the BLE MAC address of the device that is being tested. |
| 81 | + |
| 82 | + |
| 83 | +### Testing Specific Input-Sequences |
| 84 | + |
| 85 | +To test specific input sequences, for example to reproduce a bug, the `-test` flag can be used: |
| 86 | + |
| 87 | +```sh |
| 88 | +java -jar target/ble-fuzzer-1.0-SNAPSHOT.jar @experiments/args/NimBLE_pairing -adapter /dev/pts/5 -connect 11:22:33:44:55:66 -test experiments/tests/pair_att_read.txt |
| 89 | +``` |
| 90 | + |
| 91 | +Specify optionally `-times <n>` to run the input sequence multiple times. |
| 92 | + |
| 93 | + |
| 94 | +## Credits |
| 95 | +- `py/**` is based on work done in [apferscher/ble-learning](https://github.com/apferscher/ble-learning) and [Matheus-Garbelini/sweyntooth_bluetooth_low_energy_attacks](https://github.com/Matheus-Garbelini/sweyntooth_bluetooth_low_energy_attacks) |
| 96 | +- `experiments/targets/nRF52840` is based on an example in [NordicDeveloperAcademy/bt-fund](https://github.com/NordicDeveloperAcademy/bt-fund/tree/main/l5/l5_e1) |
| 97 | +- `experiments/targets/RPiPico2W` is based on an example in [raspberrypi/pico-examples](https://github.com/raspberrypi/pico-examples/tree/master/pico_w/bt/standalone) |
| 98 | +- `scripts/diff_hyps.sh` is copied from [protocol-fuzzing/edhoc-fuzzer](https://github.com/protocol-fuzzing/edhoc-fuzzer/blob/main/scripts/diff_hyps.sh) |
0 commit comments