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
- Pull the repo:
git clone https://github.com/killswitch-GUI/Fuzz-FFmpeg.git
- 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
- 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.
- 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
- There are many ways to check the status of your workload, it can be done with
afl-statsor 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