Saturday, September 4, 2021

Simple fuzzing with Radamsa

 We will start looking into improving programs by fuzzing them. A simple fuzzer that gives very good results is Radamsa. It is part of the Fedora distribution, so all you need to do is install it.

Radamsa is a file mutator. It takes a file as input and modifies it. So, if we wanted to fuzz the audit search utility, we would gather a sample log, mutate it, and run a search on the mutated log. This is easily scriptable. For example, consider the following bash script:


#!/bin/sh
LOG_DIR="/tmp"
LOG="$LOG_DIR/test.log"
MLOG="$LOG_DIR/stmp.log"
PDIR="/home/audit-3.0.5"
OPTIONS="--format csv --extra-keys --extra-labels --extra-obj2 --extra-time"
export ASAN_OPTIONS=detect_stack_use_after_return=true:strict_string_checks=true:detect_invalid_pointer_pairs=2

# Get fresh log data to test with
echo "Collecting logs..."
ausearch -if /var/log/audit/audit.log --start today --raw > $LOG
echo "Log collected, starting to fuzz..."

# Now fuzz the logs over and over
while true
do
        cat $LOG | radamsa > $MLOG
        date
        LD_LIBRARY_PATH="$DIR"/auparse/.libs/:"$PDIR"/lib/.libs/  $PDIR/src/.libs/ausearch $OPTIONS -if $MLOG >/dev/null
        if [ "$?" != "0" ] ; then
                exit 1
        fi
        rm -f $MLOG
        echo "==="
done

The idea is to cause ausearch to choke on its input as it parses things. The thing is that many failures can happen but is not visible out side the program. Glibc uses 8 byte alignment for memory allocations. If we blow past the buffer by 1 byte, it is not likely to cause a crash.

To detect these kind of issues, we need to rebuild the audit software with gcc's address sanitizer. This build has all kinds of ways to look at the program to detect these overflows. What I would recommend is to download the source rpm and build it. If you need help setting up a build environment, I have instructions here.

Once it's done do the following:


cd audit-3.0.5
make clean
CFLAGS="-fsanitize=address,pointer-compare,pointer-subtract,unreachable,vla-bound,bounds,undefined,null,return,object-size,nonnull-attribute,returns-nonnull-attribute,bool,enum,builtin -ggdb -fno-sanitize-recover=signed-integer-overflow" ./configure --with-python=no --with-python3=yes --enable-gssapi-krb5=yes --with-arm --with-aarch64 --with-libcap-ng=yes --without-golang --enable-systemd --enable-experimental
make -j 8

Once this completes, you are ready to fuzz with the script above. If you do fuzz ausearch, you will probably find a couple direct memory leaks. If you look at the mutated log, you will probably see that it added 5 comm= fields. This will never happen in real life, so I have not patched ausearch to fix this.

You can apply this same fuzzing technique to other applications. Build it with the address sanitizer, get a sample input, adjust the script, and let it roll.

No comments: