This repository contains and organizes code that we used to evaluate Randezvous.
Randezvous is a software defense against control-flow hijacking attacks on embedded microcontroller (MCU) systems, built up on diversification and eXecute-Only Memory (XOM). Unlike other control-flow hijacking defenses on MCU systems, Randezvous assumes a broader threat model in which attackers can not only use buffer overflows to corrupt memory but also use buffer overreads to leak memory content. In order to mitigate such powerful attacks, Randezvous employs several novel techniques to protect in-memory control data from leakage and corruption. It also slows down brute force attacks to make randomization effective even with MCUs' limited memory.
For more details, please check out our ACSAC paper. To cite Randezvous, you can use the following BibTeX entry:
@inproceedings{Randezvous:ACSAC22,
author = {Shen, Zhuojia and Dharsee, Komail and Criswell, John},
title = {Randezvous: Making Randomization Effective on {MCUs}},
booktitle = {Proceedings of the 38th Annual Computer Security Applications Conference},
series = {ACSAC '22},
year = {2022},
isbn = {978-1-4503-9759-9},
location = {Austin, TX, USA},
pages = {28--41},
numpages = {14},
url = {https://doi.org/10.1145/3564625.3567970},
doi = {10.1145/3564625.3567970},
publisher = {ACM},
address = {New York, NY, USA},
}
Randezvous
|-- build # Directory for building LLVM, Newlib, and compiler-rt
| |-- build.llvm.sh # Script to build LLVM
| |-- build.newlib.sh # Script to build Newlib
| |-- build.compiler.rt.sh # Script to build compiler-rt
|
|-- data # Directory containing generated experiment data (to
| # be created by our scripts)
|
|-- debug # Directory containing compiled binaries and build
| # logs (to be created by our scripts)
|
|-- llvm-project # A submodule containing source code of LLVM and
| # Randezvous passes
|
|-- newlib-cygwin # A submodule containing source code of Newlib
|
|-- scripts # Directory containing scripts
| |-- import.sh # Script to import projects into IDE
| |-- hal.sh # Script to compile HAL library for MIMXRT685-EVK
| |-- mbedtls.sh # Script to compile MbedTLS library
| |-- beebs.sh # Script to compile/debug/run BEEBS benchmarks
| |-- coremark-pro.sh # Script to compile/debug/run CoreMark-Pro benchmarks
| |-- mbedtls-benchmark.sh # Script to compile/debug/run MbedTLS-Benchmark
| |-- pinlock.sh # Script to compile/debug/run PinLock
| |-- sdcard_fatfs.sh # Script to compile/debug/run FatFs-SD
| |-- shell.sh # Script to compile/debug/run LED-Shell
| |-- exploit.sh # Script to compile/debug/run proof-of-concept exploit
| |-- cve.sh # Script to compile/debug/run CVE exploit
| |-- gen_csv.py # Script to collect experiment results into CSV files
|
|-- workspace # Directory containing source code
| |-- mimxrt685s # Source code of HAL library for MIMXRT685-EVK
| |-- mbedtls # Source code of MbedTLS library
| |-- beebs # Source code of BEEBS benchmarks
| |-- coremark-pro # Source code of CoreMark-Pro benchmarks
| |-- mbedtls-benchmark # Source code of MbedTLS-Benchmark
| |-- pinlock # Source code of PinLock
| |-- sdcard_fatfs # Source code of FatFs-SD
| |-- shell # Source code of LED-Shell
| |-- exploit # Source code of application used in proof-of-concept exploit
| |-- cve # Source code of application used in CVE exploit
|
|-- README.md # This README file
- We assume the host operating system is Linux. Other operating systems may work but were not tested.
- We use CMake, Ninja, and Clang to build the LLVM-based Randezvous compiler,
so
cmake
,ninja
, andclang
of appropriate versions must be found inPATH
. - We use the Randezvous compiler to build Newlib and compiler-rt, so make sure
that common development tools needed to build Newlib and compiler-rt for
bare-metal ARM environments (such as
arm-none-eabi-gcc
andmake
) are there inPATH
. In particular, one of our build scripts usesarm-none-eabi-gcc
to find out where a bare-metal ARMlibgcc
is installed. - We use MCUXpresso IDE
to build, run, and debug programs and require the IDE to be installed at
/usr/local
,/opt
, or$HOME
. - We use an NXP MIMXRT685-EVK board
to run programs and assume a
readable/writable character device
/dev/ttyACM0
is connected to the board's serial port after plugging in the board. - We use GNU Screen to receive program output from the board's serial port, so
screen
of an appropriate version must be found inPATH
. - We use GDB to debug ELF binaries and have debugging support included in our
scripts.
If you would like to use our script for debugging, make sure either
gdb-multiarch
orarm-none-eabi-gdb
is there inPATH
.
The following steps will set up the environment from scratch. They only need to be done once.
- Download MCUXpresso IDE
and install it at
/usr/local
,/opt
, or$HOME
. - Clone this repository.
git clone --recurse-submodules https://github.com/URSec/Randezvous.git
- Build the Randezvous compiler.
Note that all our scripts (in the
cd Randezvous && ./build/build.llvm.sh
build
andscripts
directories) are CWD-agnostic; each of them can be run from any working directory and would have the same outcome. After./build/build.llvm.sh
finishes, the Randezvous compiler will be installed inbuild/llvm/install
. - Build Newlib and compiler-rt.
After the two scripts finish, Newlib will be installed in
./build/build.newlib.sh && ./build/build.compiler.rt.sh
build/newlib-cygwin/install
and compiler-rt will be installed inbuild/compiler-rt/install
. - Import all the IDE projects in the
workspace
directory into the IDE../scripts/import.sh
- Build a
baseline
version of the HAL library. All our programs will be linked against thebaseline
HAL library../scripts/hal.sh baseline
- Build a
baseline
version of the MbedTLS library. A benchmark and an application used in our evaluation will be linked against thebaseline
MbedTLS library../scripts/mbedtls.sh baseline
We have six scripts (beebs.sh
, coremark-pro.sh
, mbedtls-benchmark.sh
,
pinlock.sh
, sdcard_fatfs.sh
, and shell.sh
)
that can compile, debug, and run three benchmark suites
(BEEBS,
CoreMark-Pro, and
MbedTLS-Benchmark)
and three real-world applications (PinLock, FatFs-SD, and LED-Shell),
respectively.
These scripts support identical command-line argument formats
./scripts/<script-name>.sh <CONFIG> [PROGRAM [PROGRAM]...]
or
./scripts/<script-name>.sh run <CONFIG> [PROGRAM [PROGRAM]...]
or
./scripts/<script-name>.sh debug <CONFIG> <PROGRAM>
where CONFIG
is the name of a configuration (see below) and PROGRAM
is the
name of a program in the corresponding benchmark suite.
For compile and run,
if PROGRAM
is not specified, all the programs in the corresponding benchmark
suite will be compiled/run.
For example, running ./scripts/beebs.sh baseline
will compile all the benchmark programs in BEEBS using the baseline
configuration, and running ./scripts/coremark-pro.sh run randezvous zip-test
will run the zip-test
program in CoreMark-Pro that was compiled using the
randezvous
configuration.
More specifically, we use two configurations of experiments for each benchmark suite and application:
- Baseline: Compile the programs without any of our passes, denoted as
baseline
. - Randezvous: Turn on all the Randezvous passes with all seeds set to zero,
denoted as
randezvous
.
The following shell code compiles all benchmarks and applications we use, with all possible configurations:
for conf in baseline randezvous; do
./scripts/beebs.sh $conf
./scripts/coremark-pro.sh $conf
./scripts/mbedtls-benchmark.sh $conf
./scripts/pinlock.sh $conf
./scripts/sdcard_fatfs.sh $conf
./scripts/shell.sh $conf
done
Note that compilation using our scripts must be done one at a time (i.e., no parallel compiling of multiple programs). This is because the IDE runs a singleton mode.
The following shell code runs all benchmarks and applications compiled by the above shell code:
for conf in baseline randezvous; do
./scripts/beebs.sh run $conf
./scripts/coremark-pro.sh run $conf
./scripts/mbedtls-benchmark.sh run $conf
./scripts/pinlock.sh run $conf
./scripts/sdcard_fatfs.sh run $conf
./scripts/shell.sh run $conf
done
Note that in order to run programs, an NXP MIMXRT685-EVK board must be connected to the host machine. Also note that FatFs-SD requires an SD card inserted into the board's SD card slot.
After compiling a program, an ELF binary with a .axf
suffix will be
placed in the debug
directory, and after running a program, experiment data
with performance metrics will be generated in the data
directory.
The names
of all the subdirectories and files under debug
and data
are
self-explanatory.
For example, debug/beebs-baseline/baseline-whetstone.axf
is the ELF binary of the whetstone
program in BEEBS compiled using the
baseline
configuration, and
data/coremark-pro-randezvous/randezvous-core.stat
contains the
execution time of running the core
program in CoreMark-Pro compiled with the
randezvous
configuration.
You can use the scripts/gen_csv.py
script to collect the raw experiment data
and write the summarized results to a CSV file.
This script takes three
optional command-line arguments:
-b benchmark_name # "beebs", "coremark-pro", "mbedtls-benchmark", "pinlock", "sdcard_fatfs", or "shell", default "beebs"
-t data_type # "perf", "codesize", or "datasize", default "perf"
-o output_file # Path of the output CSV file; if not specified, a default
# name "data_type-benchmark_name.csv" will be used
For example, if you want to see the performance numbers on BEEBS, run
./scripts/gen_csv.py -b beebs -t perf
and you will get an output file named perf-beebs.csv
in the working directory.
In addition to performance evaluation, this repository also contains a
proof-of-concept (PoC) exploit and a real-world CVE exploit that we used to
demonstrate Randezvous's security.
The PoC exploit consists of a script scripts/exploit.sh
representing an
attacker and a vulnerable application in workspace/exploit
.
The CVE exploit consists of a script scripts/cve.sh
representing an attacker
and a benign application in workspace/cve
that is linked against a vulnerable
HAL library with
CVE-2021-27421
(a cve
version of the HAL library can be built by ./scripts/hal.sh cve
).
Both scripts take the same command-line argument formats as those used in
performance evaluation.
Unlike in performance evaluation, here we use three configurations for both the PoC and CVE exploits:
- Baseline: Compile the application without any of our passes, denoted as
baseline
. - Randomization plus XOM: Compile the application with only code/data
layout randomization and XOM support, denoted as
randxom
. As the entropy of randomization on MCU systems heavily depends on memory size, we picked three exemplary MCUs of different memory sizes, deriving three sub-configurations denoted asrandxom-small
,randxom-medium
, andrandxom-large
. - Randezvous: Compile the application with all the Randezvous passes on and
all seeds set to zero, denoted as
randezvous
. Likewise, we derived three sub-configurations denoted asrandezvous-small
,randezvous-medium
, andrandezvous-large
for the three different-sized MCUs.
For each (sub-)configuration, the PoC script will generate attack payloads using the best strategies for the attacker and keep sending payloads in a brute-forcing manner, while the CVE script will do the same except that attack payloads are generated using less efficient strategies. In order to keep the exploit running, both scripts will reboot the application each time before sending a new payload. For either the PoC or CVE exploit, you can compile the application and run the script to see how long the exploit takes to succeed for each case.
Zhuojia Shen: zshen10@cs.rochester.edu
Komail Dharsee: kdharsee@cs.rochester.edu
John Criswell: criswell@cs.rochester.edu