Skip to content

Commit 13f4d95

Browse files
committed
Initial commit
0 parents  commit 13f4d95

File tree

190 files changed

+20655
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+20655
-0
lines changed

.github/workflows/ci.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI
2+
on: [push, pull_request]
3+
4+
jobs:
5+
NimBLE:
6+
runs-on: ubuntu-latest
7+
timeout-minutes: 30
8+
strategy:
9+
fail-fast: false
10+
steps:
11+
- uses: actions/checkout@v4
12+
with:
13+
path: ble-fuzzer
14+
- uses: actions/checkout@v4
15+
with:
16+
repository: 'protocol-fuzzing/protocol-state-fuzzer'
17+
ref: 'ddef362dd042dba83e6a50067e38414194d72e60'
18+
path: protocol-state-fuzzer
19+
- uses: actions/setup-java@v4
20+
with:
21+
java-version: '17'
22+
distribution: 'temurin'
23+
- uses: actions/setup-go@v3
24+
with:
25+
go-version: 'stable'
26+
- uses: actions/setup-python@v5
27+
with:
28+
python-version: '3.13'
29+
- name: Build ProtocolState-Fuzzer
30+
shell: bash
31+
run: |
32+
cd protocol-state-fuzzer
33+
bash install.sh
34+
- name: Build ble-fuzzer
35+
shell: bash
36+
run: |
37+
set -ex
38+
cd ble-fuzzer
39+
source scripts/setup_venv.sh
40+
mvn package
41+
- name: Install newt
42+
shell: bash
43+
run: |
44+
go install mynewt.apache.org/newt/newt@latest
45+
- name: Build NimBLE
46+
shell: bash
47+
run: |
48+
set -ex
49+
cd ble-fuzzer/experiments/targets/NimBLE/workspace
50+
newt upgrade --shallow 1
51+
newt build sim_testapp
52+
- name: Test NimBLE
53+
shell: bash
54+
run: |
55+
set -ex
56+
cd ble-fuzzer
57+
source scripts/setup_venv.sh
58+
experiments/targets/NimBLE/workspace/bin/targets/sim_testapp/app/apps/testapp/testapp.elf | grep --line-buffered '^uart1' &> iface.txt &
59+
sleep 2
60+
SERIAL_PORT=$(cat iface.txt | cut -d ' ' -f 3)
61+
java -jar target/ble-fuzzer-1.0-SNAPSHOT.jar @experiments/args/NimBLE_pairing -mapper CI -adapter $SERIAL_PORT -roundLimit 4
62+
./scripts/diff_hyps.sh experiments/results_saved/NimBLE_pairing experiments/results/NimBLE_pairing 4
63+
- uses: actions/upload-artifact@v4
64+
if: always()
65+
with:
66+
name: NimBLE_pairing
67+
path: experiments/results/NimBLE_pairing/
68+
if-no-files-found: error
69+
retention-days: 7

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/ble-learning/
2+
/debugging/
3+
/experiments/results/
4+
/experiments/tests/test*.txt
5+
/experiments/tests/repro_nimble_*.txt
6+
/experiments/targets/NimBLE/workspace/apps/bleprph/
7+
/experiments/targets/NimBLE/workspace/apps/blinky/
8+
/experiments/targets/NimBLE/workspace/repos/
9+
/experiments/targets/NimBLE/workspace/env.txt
10+
/experiments/targets/RPiPico2W/pico-sdk/
11+
/dependency-reduced-pom.xml
12+
13+
.mvn/
14+
__pycache__/
15+
bin/
16+
build/
17+
target/
18+
venv/
19+
settings.json
20+
.gdb_cmds
21+
.gdb_history

README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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+
![Test setup architecture](architecture.png)
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 (lists 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)

architecture.png

65.4 KB
Loading

experiments/alphabets/pairing.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!-- Inputs necessary for "LE legacy pairing" and key re-negotiation -->
2+
<alphabet>
3+
<InputBLE name="LL_ADV_CONNECT_IND"/>
4+
<InputBLE name="LL_CTRL_ENC_REQ"/>
5+
<InputBLE name="LL_CTRL_START_ENC_RSP"/>
6+
<InputBLE name="LL_CTRL_FEATURE_REQ"/>
7+
<InputBLE name="LL_CTRL_PAUSE_ENC_REQ"/>
8+
<InputBLE name="LL_CTRL_PAUSE_ENC_RSP"/>
9+
<InputBLE name="LL_CTRL_LENGTH_REQ"/>
10+
<InputBLE name="SM_PAIRING_REQ"/>
11+
<InputBLE name="SM_CONFIRM"/>
12+
<InputBLE name="SM_RANDOM"/>
13+
<InputBLE name="ATT_READ_REQ"/>
14+
</alphabet>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!-- Inputs necessary for "LE Secure Connections" pairing and key re-negotiation -->
2+
<alphabet>
3+
<InputBLE name="LL_ADV_CONNECT_IND"/>
4+
<InputBLE name="LL_CTRL_ENC_REQ"/>
5+
<InputBLE name="LL_CTRL_START_ENC_RSP"/>
6+
<InputBLE name="LL_CTRL_PAUSE_ENC_REQ"/>
7+
<InputBLE name="LL_CTRL_PAUSE_ENC_RSP"/>
8+
<InputBLE name="SM_PAIRING_REQ_SC"/>
9+
<InputBLE name="SM_CONFIRM"/>
10+
<InputBLE name="SM_RANDOM"/>
11+
<InputBLE name="SM_PUBLIC_KEY"/>
12+
<InputBLE name="SM_DHKEY_CHECK"/>
13+
<InputBLE name="ATT_READ_REQ"/>
14+
</alphabet>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
state-fuzzer-server
2+
3+
-output
4+
experiments/results/ArduinoNanoESP32_pairing
5+
6+
-alphabet
7+
experiments/alphabets/pairing.xml
8+
9+
-logQueries
10+
11+
-mapper
12+
ArduinoNanoESP32
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
state-fuzzer-server
2+
3+
-output
4+
experiments/results/IntelAX200BlueZ_pairing
5+
6+
-alphabet
7+
experiments/alphabets/pairing.xml
8+
9+
-logQueries
10+
11+
-mapper
12+
IntelAX200BlueZ

experiments/args/NimBLE_default

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
state-fuzzer-server
2+
3+
-output
4+
experiments/results/NimBLE_default
5+
6+
-logQueries
7+
8+
-mapper
9+
NimBLE
10+
11+
-connect
12+
11:22:33:44:55:66

experiments/args/NimBLE_pairing

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
state-fuzzer-server
2+
3+
-output
4+
experiments/results/NimBLE_pairing
5+
6+
-alphabet
7+
experiments/alphabets/pairing.xml
8+
9+
-equivalenceQueryBound
10+
5000
11+
12+
-logQueries
13+
14+
-mapper
15+
NimBLE
16+
17+
-connect
18+
11:22:33:44:55:66

0 commit comments

Comments
 (0)