_____ _
| ___| _ _______(_)_ __ __ _
| |_ | | | |_ /_ / | '_ \ / _` |
| _|| |_| |/ / / /| | | | | (_| |
|_| \__,_/___/___|_|_| |_|\__, |
|___/
_ _ _
| (_) |__ ___ __ _ ___ __ _
| | | '_ \ / __/ _` |/ __/ _` |
| | | |_) | (_| (_| | (_| (_| |
|_|_|_.__/ \___\__,_|\___\__,_|
Fuzzing libcaca and more
Scott Griffy
September 14th, 2016
back to homepage
-- Contents --
Introduction
Materials
Method
Fuzzing Caca
Fuzzing objdump
Conclusion
-- Introduction --
Fuzzing is a method which is now prevalent in the security researcher field.
It's the process of sending random input to software to test if it will break.
Pretty simple in concept, but fuzzers can become very complex. But for this
blog post I'll be using a very simple fuzzer: zzuf.
-- Materials --
Zzuf simply which simply changes a percentage of a file to random bytes. And is
meant to be used on files that a program would normally work on without error.
And I'll be fuzzing libcaca (where the title of this blog gets it's name).
Libcaca is an ASCII utility library, specifically I'll be fuzzing the utility
img2txt, which takes images and converts them into ASCII formats.
-- Method --
I'm pretty much just following a guide I found online here:
https://fuzzing-project.org/tutorial1.html
Nothing all that fancy, but a good place to start. I've worked a lot with Image
Magick, so I created the 3x3 image with that:
$ convert -size 3x3 xc:white example.gif
To get the different file formats, you use more convert commands like it says
in the tutorial:
$ convert example.png example.gif
$ convert example.png example.xwd
$ convert example.png example.tga
Now, you use the fuzzer to get your giant array of corrupted images:
$ for i in {1000..3000}; do for f in example.*; \
do zzuf -r 0.01 -s $i < "$f" > "$i-$f"; \
done; done
I love bash, so this is how I do loops (also this is how the tutorial did it),
but you might be able to do this another scripting language. This script is
iterating from 1000 to 3000 and giving that as a seed to change a fraction
(0.01) of the input file randomly. It's also iterating through all the
different file formats I made with Image Magick.
You can then use these images to test any program that would normally take
images as an input. Because the format looks familiar it will get far into the
code before an error is found, which usually has less secure code than the code
that initially rejects files.
Note that this is a lot faster if you make a ramfs or even better, use zzuf to
fuzz and hand the files directy to the executable you're testing.
-- Fuzzing Caca --
I marched my army of corrupted files to libcaca's door step, trying out the
img2txt utility. The img2txt utility takes an image file and spits out an ASCII
representation of it.
$ bash -c ' \
echo `date`; \
for f in *-example*; do echo "doing $f"; \
img2txt $f 1>/dev/null ; \
done' &> i2tRes
I'm iterating through all 2000 of the corrupted image files and dumping the
ASCII straight to /dev/null. The file 'i2tRes' is going to have the stderr of
all the iterations and is hopefully going to have some segfaults to make this
blog worthwhile ...
And it did! ... at first. I found this in the output file:
doing 2027-example.gif
bash: line 1: 14537 Segmentation fault img2txt $f > /dev/null
Wow! I found a bug! Well, hold on there. I was testing with the version of
libcaca found in the debian repository: 0.99.beta19, but when I downloaded
0.99.beta20, I found that this bug had already been fixed, which makes sense
because zzuf was written by the same guy who made libcaca. This illustrates a
good takeaway for anyone doing security research: always use the latest
version. It may save sometime to simply download the binaries from your
repo, but this code is much less likely to have bugs in it.
-- Fuzzing objdump --
Unphased by the defeat at the battle of img2txt, I struggled on to Firefox,
where I couldn't find a good place to even create a test suite. Then to
WordPress, whose json and emoji parsing engines could not be breached. Finally
I decided to finish the tutorial I started because I thought it might have some
more information I could use. And doing the very next step found me a
legitimate bug:
zzuf -s 0:1000000 -c -C 0 -q -T 3 objdump -x win9x.exe
"win9x.exe" is from the tutorial's archive. The rest of the options get rid of
stdin, create a timeout, "-c" isn't necessary and "-C 0" makes sure that the
program finds as many bugs as it can.
On seed 16915 it found a segfault! But surely this was because I was using an
old stable release! ... Not so! I downloaded the source from GNU binutils'
website, built it, and ran the test again:
zzuf -s 16915 -c -C 0 -q -T 3 objdump -x win9x.exe
And to my surprise it segfaulted. I then tried to run valgrind, but I didn't
know exactly how to interpret it, so I ran gdb on it, which I use consistently
to debug:
$ gdb ~/checkout/binutils-gdb/binutils/objdump
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
...
Reading symbols from /home/grifball/checkout/binutils-gdb/binutils/objdump...done.
(gdb) set args -x crash.exe
(gdb) r
Starting program: /home/grifball/checkout/binutils-gdb/binutils/objdump -x crash.exe
Program received signal SIGSEGV, Segmentation fault.
bfd_getl32 (p=0x85a000) at libbfd.c:552
552 return v;
(gdb) where
#0 bfd_getl32 (p=0x85a000) at libbfd.c:552
#1 0x00000000004acaea in _bfd_pei_swap_debugdir_in (abfd=abfd@entry=0x83a1c0, ext1=0x85a000, in1=in1@entry=0x7fffffffcfa0) at peigen.c:1116
#2 0x00000000004a89dc in pe_bfd_read_buildid (abfd=0x83a1c0) at peicode.h:1342
#3 pe_bfd_object_p (abfd=0x83a1c0) at peicode.h:1486
#4 0x000000000044913d in bfd_check_format_matches (abfd=abfd@entry=0x83a1c0, format=format@entry=bfd_object, matching=matching@entry=0x7fffffffded0) at format.c:308
#5 0x0000000000408888 in display_object_bfd (abfd=0x83a1c0) at ./objdump.c:3461
#6 display_any_bfd (file=file@entry=0x83a1c0, level=level@entry=0) at ./objdump.c:3552
#7 0x000000000040a9a3 in display_file (filename=0x7fffffffe2f0 "crash.exe", target=) at ./objdump.c:3573
#8 0x0000000000404cca in main (argc=3, argv=0x7fffffffe078) at ./objdump.c:3856
(gdb)
Great! Now I have enough information to write up a bug report and file it.
https://sourceware.org/bugzilla/show_bug.cgi?id=20605
-- Conclusion --
Hopefully this is just the beginning of my foray into fuzzing applications.
I've learned a lot, such as not writing fuzzed iterations to disk, making sure
to use the latest version of applications, and reading the tutorial fully. I
think the next place I'm going from here is to use American Fuzzy Lop along
with the address sanitizer. I ran the full 1000000 iterations on objdump,
finding nothing.