/ Docker

Docker + AFL: Effective, scalable reproducible fuzzing

Fuzzing is an art of its own, and finding perfection is rough. It takes applicable targets, time and more time. The key to fuzzing is an optimization, and after a few solid dry runs you can often work out the bugs. This is not a 0-DAY post, but rather a technique we are using at Obscurity Labs to scale our fuzzing and provide others outside of a project to resume operations if needed or a new execution point needs to be tested.

Supporting Github Repo: https://github.com/killswitch-GUI/Fuzz-FFmpeg


The world of DevOps

DevOps has fundamentally changed the way we "IT", providing developers quick access to multiple operating systems and tooling. Combining this automation effort into your fuzzing pipeline can help reduce the time-on-target (TOT). While we all enjoy mocking up a full Ubuntu instance on KVM, building shell scripts and making small adjustments for compiles it is honestly hard to repeat.

Using a thing like LXC or Docker is a great way to reduce this TOT, which in turn allows refocusing human, physical, and logical resources to other pressing work. In this post, we mock up FFMPEG as our target and the use of docker-compose to help automate the build process slightly.

Afl-Fuzz + Afl-utils + Docker

Building afl-fuzz isn't complicated and is out-of-scope for this post as this had been covered in detail many times. In this example, we use Ubuntu 16.04 as our host OS and multiple supporting packages to properly support the FFmpeg install. We also added the afl-utils repo to the Docker image to support larger core nodes. Here is the Docker file that we used built to support this.

FROM ubuntu:16.04

MAINTAINER Obscuritylabs
LABEL version="1.0"
LABEL description="Dockerfile for ffmpeg fuzzing."

# docker hardcoded sh...
SHELL ["/bin/bash", "-c"]

# env setup
ENV DEBIAN_FRONTEND=noninteractive

# install proper tools
RUN apt-get update && \
    apt-get install -yq net-tools sudo nano htop

RUN sudo apt-get update -qq && sudo apt-get -y install \
    autoconf \
    automake \
    build-essential \
    cmake \
    git-core \
    libass-dev \
    libfreetype6-dev \
    libsdl2-dev \
    libtool \
    libva-dev \
    libvdpau-dev \
    libvorbis-dev \
    libxcb1-dev \
    libxcb-shm0-dev \
    libxcb-xfixes0-dev \
    pkg-config \
    texinfo \
    wget \
    zlib1g-dev \
    yasm \
    nasm \
    libx264-dev \ 
    libx265-dev \
    libnuma-dev \
    libvpx-dev \ 
    libfdk-aac-dev \ 
    libmp3lame-dev \ 
    libopus-dev \
    python3 \
    python3-pip \
    python2.7 \
    python-pip \
    screen 

# install pip / update
RUN pip install --upgrade pip && pip3 install --upgrade pip

# Install AFL
RUN git clone https://github.com/mirrorer/afl && \
    cd afl && \
    make -j12 && sudo make install

# Install AFL Ecploitable
RUN git clone https://gitlab.com/rc0r/exploitable.git && \ 
    apt install -y gdb && \     
    cd exploitable && python setup.py install

# Install AFL tools
RUN git clone https://gitlab.com/rc0r/afl-utils.git && \
    cd afl-utils && python setup.py install

# Install FFMPEG
RUN mkdir -p ~/ffmpeg_sources ~/bin && \
    cd ~/ffmpeg_sources && \
    wget -O ffmpeg-snapshot.tar.bz2 https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2 && \
    tar xjvf ffmpeg-snapshot.tar.bz2 && \
    cd ffmpeg && \
    PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
     --cc=afl-gcc \
     --cxx=afl-g++ \
     --prefix="$HOME/ffmpeg_build" \
     --pkg-config-flags="--static" \
     --extra-cflags="-I$HOME/ffmpeg_build/include" \
     --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
     --extra-libs="-lpthread -lm" \
     --bindir="$HOME/bin" \
     --enable-gpl \
     --enable-libass \
     --enable-libfdk-aac \
     --enable-libfreetype \
     --enable-libmp3lame \
     --enable-libopus \
     --enable-libvorbis \
     --enable-libvpx \
     --enable-libx264 \
     --enable-libx265 \
     --enable-nonfree && \
   PATH="$HOME/bin:$PATH" make -j12 && \
   make install && \
   hash -r
ENTRYPOINT ["tail", "-f", "/dev/null"]

Build & Deploy

  1. Pull the repo: git clone https://github.com/killswitch-GUI/Fuzz-FFmpeg.git
  2. Building the Docker image can take some time honestly, it requires an install of many dependencies and compiles of the FFmpeg project. This can be easily done like so: docker-compose up -d --build
  3. Drop into Docker image interactively using the following command: docker exec -ti <DOCKER NAME HERE> bash. This due to the image being set up in daemon mode with an entry point that will not exit upon completion.
  4. Starting your workload is easy with afl-multicore, this automates the process of starting multiple instances with nohup: python3 /afl-utils/afl-multicore -c ffmpeg_afl_scripts/afl_mc_ffmpeg.json start 12
  5. There are many ways to check the status of your workload, it can be done with afl-stats or even grep:
cd /ffmpeg_output#
cat */fuzzer_stats | grep unique_crashes | uniq
cat */fuzzer_stats | grep unique_hangs| uniq

The repo can be found here:  https://github.com/killswitch-GUI/Fuzz-FFmpeg

Alexander Rymdeko-Harvey

Alexander Rymdeko-Harvey

Alexander Rymdeko-Harvey is an experienced Red Teamer. He loves to develop on offensive TTPs and has a knack for Windows internals. He prides himself on being a husband, father and prior Army.

Read More