Introducing usb-racer

Introducing usb-racer

TL;DR: Introducing usb-racer, a tool for pentesting Time-of-check/Time-of-use (TOCTOU) issues with USB storage devices.

usb-racer

One issue that we are always on the lookout for when performing an embedded assessment are TOCTOU situations. Typically, these involve conditions where the authenticity of data is verified and then modified by an attacker before being consumed by the device. For example, we recently completed an engagement where the device booted from a USB drive in order to perform firmware updates and included a script similar to the following to mount the root file system from the initrd:

#!/bin/sh

ROOT_IMG="..."

openssl dgst -sha256 -verify ${SIGNING_KEY} -signature "${ROOT_IMG}.sig" ${ROOT_IMG}
if [ $? -ne 0 ]
then
    logger -p Error "Invalid signature on root filesystem."
    exit -1
fi
mount ${ROOT_IMG} /new_root
#...

This is a classic TOCTOU flaw, where the root file system's signature is verified then the image is mounted. If we swap the data between the check and the mount, we will be able to defeat the verified boot system. To exploit this issue, we built usb-racer.

Usage

usb-racer comes with some built in tools to handle basic cases; more complex scenarios may require a custom script.

Basic Mass Storage Device

A no frills basic mass storage device is included and can be launched simply:

> usbracer-storage --block-size 512 /path/to/disk.img

It is not very fast, so the standard mass storage gadget is a better choice if you just need to emulate a mass storage device. The tool has some options that are useful such as:

  • --write โ€“ Controls the write behavior, ALLOW, DENY returns an error on writes, DROP silently drops writes.
  • --cow โ€“ A simple copy on write that saves writes to another file. Makes it easier to see what changes and revert back to the original file.
  • --log & --log-data โ€“ Creates a binary recording read, writes, and optionally the data for each operation. Can be read with the usbracer-log-dump command.

TOCTOU Tool

The usbracer tool implements the TOCTOU attack:

usage: usbracer [-h] (--toggle-image TOGGLE_IMAGE | --offset-override OFFSET_OVERRIDE OFFSET_OVERRIDE) [--block-size BLOCK_SIZE]
                               [--toggle-delay TOGGLE_DELAY] [--toggle-read-block TOGGLE_READ_BLOCK] [--debug-level DEBUG_LEVEL]
                               disk

positional arguments:
  disk                  Path to disk image

options:
  -h, --help            show this help message and exit
  --block-size BLOCK_SIZE
  --toggle-delay TOGGLE_DELAY
                        Automatically toggles the disks after a delay (in seconds)
  --toggle-read-block TOGGLE_READ_BLOCK
                        Toggle disks after a read on a specific block
  --debug-level DEBUG_LEVEL

Second Image:
  --toggle-image TOGGLE_IMAGE
                        A full image to toggle between
  --offset-override OFFSET_OVERRIDE OFFSET_OVERRIDE
                        The next two arguments are used as an offset and a path, can be specified multiple times

There are a couple ways to specify the second/replacement image:

  • --toggle-image โ€“ Takes a path to a file the same size as disk and serves as the second image. When the toggle action happens all reads and writes get redirected to the second file. This is simple, easy to modify several files and directory structures, but can result in disk corruption. The OS typically has already cached a bunch of data, including metadata about the directory structure, which may cause issues.
  • --offset-override โ€“ This takes two arguments an offset to replace the data with the contents of a file (e.g.--offset-override 425 ~/malicious.bin). When compared to swapping the whole image, this method uses less disk space and risk of corruption is much smaller as reads and writes outside of the targeted blocks are unaffected. Takes a little more work to setup as you need to know the blocks in the file you are targeting, and if the file is fragmented you may need to patch up multiple offsets. Also, it is not easy to change the directory structure. The --offset-override argument can be specified multiple times to target multiple files or a fragmented file.

When to trigger the attack can also be controlled. The tool offers three ways:

  • Keyboard Toggle โ€“ Hitting enter will toggle (enable/disable) the TOCTOU attack. This option is always on, even if one of the other options is picked.
  • --toggle-delay โ€“ This option will automatically toggle after the specified seconds.
  • --toggle-read-block โ€“ This option watches read operations and will toggle after reading the specified block. In terms of a TOCTOU, we would watch the last block in the targeted file. After the "check" operation reads it, we swap the underlying data for the usage operation.

More complex scenarios can be implemented by creating your own script.

Disk Caching

There is an important wrinkle in swapping underlying storage blocks: OS level disk caching. OSs will heavily cache disk IO, so after the first read (to verify the integrity of the data), there may not be a second read when the system consumes the data. So, some strategizing and conditioning may be necessary to craft a working exploit. Here are some tips:

  • Target Larger Files โ€“ Processing large amounts of data will cause cache entries to be evicted. For example, a disk image of a root filesystem is unlikely to be fully cached during the signature verification step, while a configuration file a few hundred bytes long is easily cached.
  • Target Less Frequently Used Files โ€“ If the time between accesses is large then it gives the cache a chance to clear. For example, if a file is verified on boot but then not consumed until much later, the rest of the boot process or normal operations could have evicted the file from the cache.
  • Force Resource Consumption โ€“ Is there a web server? Firmware update? Network protocol that can be leveraged to allocate memory? Basically, we want to put a resource load on the device. The more memory we can tie up the less will be available for caching. The more IO we can force the faster the cache will turn over.

About the Author

Michael Milvich is a Fellow at Anvil Secure. Prior to joining Anvil, Michael worked as a Senior Principal Consultant IOActive Inc, and as a Cyber Security Researcher at Idaho National Laboratory (INL). Michael got his start in embedded security hacking SCADA and ICS systems and later broadened to encompass a wide variety of embedded systems across many industries. Michaelโ€™s strong technical background combined with his years of general consulting have been utilized to assist some of the leading technologies and most advanced security groups in improving their security posture.

Tools

awstracer - An Anvil CLI utility that will allow you to trace and replay AWS commands.


awssig - Anvil Secure's Burp extension for signing AWS requests with SigV4.


dawgmon - Dawg the hallway monitor: monitor operating system changes and analyze introduced attack surface when installing software. See the introductory blogpost


nanopb-decompiler - Our nanopb-decompiler is an IDA python script that can recreate .proto files from binaries compiled with 0.3.x, and 0.4.x versions of nanopb. See the introductory blogpost


ulexecve - A tool to execute ELF binaries on Linux directly from userland. See the introductory blogpost


usb-racer - A tool for pentesting TOCTOU issues with USB storage devices.

Recent Posts