This is the repository of our paper DICE to appear at the Proceedings of the 42nd IEEE Symposium on Security and Privacy (Oakland'21).
Besides DICE, we have a series of work on firmware rehosting, including P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling (a USENIX Security 2020 paper, source code published here) and AIM: Automatic Interrupt Modeling for Dynamic Firmware Analysis (an IEEE Trans. on Dependable and Secure Computing 2023 paper, source code published here). DICE, P2IM, and AIM all aim to enable firmware testing in an emulator that does not support peripherals. They perform automated modeling for DMA, MMIO, and interrupt channels used by peripherals respectively.
Talk preview video at IEEE S&P Youtube channel: https://www.youtube.com/watch?v=i7o9fsj2AkI
If your research find one or several components of DICE useful, please use the following citation:
@inproceedings{dice,
abstract = {Microcontroller-based embedded devices are at the core of Internet-of-Things (IoT) and Cyber-Physical Systems (CPS). The security of these devices is of paramount importance. Among the approaches to securing embedded devices, dynamic firmware analysis (e.g., vulnerability detection) gained great attention lately, thanks to its offline nature and low false- positive rates. However, regardless of the analysis and emulation techniques used, existing dynamic firmware analyzers share a major limitation, namely the inability to handle firmware using DMA (Direct Memory Access). It severely limits the types of devices supported and firmware code coverage.
We present DICE, a drop-in solution for firmware analyzers to emulate DMA input channels and generate or manipulate DMA inputs (from peripherals to firmware). DICE is designed to be hardware-independent (i.e., no actual peripherals or DMA controllers needed) and compatible with common MCU firmware (i.e., no firmware-specific DMA usages assumed) and embedded architectures. The high-level idea behind DICE is the identi- fication and emulation of the abstract DMA input channels, rather than the highly diverse peripherals and controllers. DICE identifies DMA input channels as the firmware writes the source and destination DMA transfer pointers into the DMA controller. Then DICE manipulates the input transferred through DMA on behalf of the firmware analyzer. DICE does not require firmware source code or additional features from firmware analyzers. We integrated DICE to the recently proposed firmware an- alyzer P2IM (for ARM Cortex-M architecture) and a PIC32 emulator (for MIPS M4K/M-Class architecture). We evaluated it on 83 benchmarks and sample firmware, representing 9 different DMA controllers from 5 different vendors. DICE detected 33 out of 37 DMA input channels, with 0 false positives. It correctly supplied DMA inputs to 21 out of 22 DMA buffers that firmware actually use, which previous firmware analyzers cannot achieve due to the lack of DMA emulation. DICE’s overhead is fairly low, it adds 3.4% on average to P2IM execution time. We also fuzz-tested 7 real-world firmware using DICE and compared the results with the original P2IM. DICE uncovered tremendously more execution paths (as much as 79X) and found 5 unique previously-unknown bugs that are unreachable without DMA emulation.},
author = {Mera, Alejandro and Feng, Bo and Lu, Long and Kirda, Engin},
booktitle = {Proceedings of the 42nd IEEE Symposium on Security and Privacy},
month = {May},
series = {S&P/Oakland'21},
title = {DICE: Automatic Emulation of DMA Input Channels for Dynamic Firmware Analysis},
year = {2021}
}
DICE requires Ubuntu 16.04 or 18.04 64Bit LTS. We are aware of some issues with Ubuntu 20.04, therefore it is not supported.
DICE is based in many open source projects (check references in the paper), particularly it requires the P2IM framework for Fuzz testing and benchmarks of the ARM Cortex-M. Use the following commands to clone this repository and initialize all the required sub-modules:
git clone https://github.com/RiS3-Lab/DICE-DMA-Emulation.git
cd DICE-DMA-Emulation
git submodule update --init --recursive
After cloning and initializing all sub-modules the directory structure will be as follows:
.
├── DICE-Evaluation
│ ├── ARM
│ │ ├── DICE-P2IM-Utilities # DICE-P2IM scripts for model instantiation
│ │ ├── Fuzzing # Firmware binaries, source code and scripts for fuzz testing with DICE-P2IM
│ │ └── Unit-Test # Firmware binaries, source code and scripts for unit test with DICE-P2IM
│ └── MIPS
│ └── Unit-Test # Firmware binaries, source code and scripts for unit test with DICE-MIPS-emulator
├── DICE-Patches # DICE patches (Add-ons) for P2IM and MIPS-emulator
├── DICE-precompiled
│ ├── ARM_bin # Precompiled QEMU-DICE-P2IM binaries with DMA input channels identification and emulation for the ARM Cortex-M
│ ├── ARM_bin_Disabled # Precompiled QEMU-DICE-P2IM binaries with DMA input channels identification for the ARM Cortex-M
│ └── MIPS_bin # Precompiled QEMU-DICE-MIPS-emulator with DMA input channels identification for the MIPS M4K/M-class
├── mips-emulator # Vanilla MIPS emulator submodule
└── p2im # Vanilla P2IM framework submodule
Compile QEMU using the source code in the "p2im" directory of DICE and the instructions provided here. Do not proceed if the compilation of vanilla QEMU P2IM fails. You must solve any dependencies or compilation issues before proceeding.
After compilation, from the root of the DICE directory structure, execute the following command ignoring any warning messages:
git apply ./DICE-Patches/DICE-P2IM.patch --unsafe-paths --directory ./p2im/qemu/src/qemu.git/
Compile QEMU again to finish the integration of DICE and QEMU P2IM.
The compiled QEMU binaries will be located at:
./p2im/qemu/src/install/debian64/qemu/bin
From the root of the DICE directory execute the following commands:
cd p2im
make -C afl/
The compiled AFL binaries will be located at:
./p2im/afl
From the root of the DICE directory execute the following commands ignoring any warning messages:
git apply ./DICE-Patches/DICE-MIPS-EMULATOR.patch --unsafe-paths --directory ./mips-emulator
cd mips-emulator
./configure --prefix=/usr/local/qemu-mips --target-list=mipsel-softmmu --disable-werror --disable-xen
make
We provide a helping script to automatically prepare the configuration file required by P2IM. This script launches DICE-P2IM to identify DMA input channels and instantiate peripheral models until firmware execution does not access new unknown interfaces.
./run.py f103 ./Firmware/Binaries-DICE/F103_ADC_SingleConversion_TriggerTimer_DMA.elf ./output
To verify the automatically identified DMA input channels and the access to the DMA buffers of the previous example, execute the following commands:
cd DICE-Evaluation/ARM/Unit-Test
./DMAtrace.py ./output/dma_trace ./dma.txt
The output file dma.txt
contains the filtered execution trace for DMA operations of the firmware.
For example:
DMA Stream configuration identified: *0x40020000 p_A:*0x40020010->*0x4001244c p_B:*0x40020014->*0x200000a4
Where:
0x40020000
is the mapped base address of the DMA controller in the STM32F103 MCU
p_A:*0x40020010->*0x4001244c
is a pointer to a register in a peripheral (Source), and
p_B:*0x40020014->*0x200000a4
is a pointer to a buffer in RAM (Destinantion)
Besides this example, the filtered trace file contains more self-explanatory messages related to the DMA buffer size inference and data consumption through DMA input channels.
We also provide the runbatch.py script to execute the whole unit test as described on the DICE paper. This script might require several minutes or a few hours to complete.
Fuzzing with DICE-P2IM follows the same workflow described for the P2IM framework. Therefore, the P2IM documentation is still relevant for the DICE-P2IM integration and you should check it for further details. Besides the similarities, we provide in this repository a set of slightly modified scripts in a specific directory structure to easily reproduce the experiments presented in our paper.
To fuzz the real firmware follow these steps:
- Create a base directory to store the fuzzing working files. We provide a handy script that will do it for you. We recommend to create the base directory in the root of your home directory, otherwise QEMU might complain about long paths and stop execution.
For example:
./DICE-Evaluation/ARM/Fuzzing/CreateBaseDir.py -B ~/FuzzBase -R 1.0
This script creates a complete working tree and default seed input for the 7 tested firmware as follows:
FuzzBase
├── GPSReceiver
│ └── 1.0
│ ├── inputs
│ │ └── input.data
│ └── outputs
├── GuitarPedal
│ └── 1.0
│ ├── inputs
│ │ └── input.data
│ └── outputs
:
:
└── StepperMotor
└── 1.0
├── inputs
│ └── input.data
└── outputs
- Configure your Linux kernel according to AFL requirements. Execute the following commands as root:
su -
echo core >/proc/sys/kernel/core_pattern
cd /sys/devices/system/cpu
echo performance | tee cpu*/cpufreq/scaling_governor
exit
- Launch the fuzzing campaign using the provided configuration files and the previously created base directory.
For example:
cd ./DICE-Evaluation/ARM/Fuzzing
export FUZZDIR=/home/$USER/FuzzBase
./fuzz.py -c ./Configs/Modbus.cfg
- Analyze the fuzzing results using the same instructions provided for P2IM.
Before launching the unit test you need to decompress the file system images of the BSD distribution
cd ./DICE-Evaluation/MIPS/Unit-Test/Unix/Filesystem
unzip ./filesystem.zip
cd ../../
To run the unit test of MIPS execute the script passing the corresponding configuration file.
For example:
cd ./DICE-Evaluation/MIPS/Unit-Test
./run.py -c ./Configs/runBSD-Lite-PIC32MZ.cfg -o ./dma.txt
This script will execute the QEMU DICE-Mips-emulator for 10 seconds and then will stop it automatically. The output dma.txt
file will contain similar traces as described for the ARM Cortex-M unit test. It is worth noting that some firmware are not DMA enabled and might not produce any DMA related trace, which is an expected result (no false positives).
Please refer to our paper.
Please open a new issue in the GitHub repository including the details of your particular inquiry.