_____ _ | ___| _ _______(_)_ __ __ _ | |_ | | | |_ /_ / | '_ \ / _` | | _|| |_| |/ / / /| | | | | (_| | |_| \__,_/___/___|_|_| |_|\__, | |___/ _ _ _ | (_) |__ ___ __ _ ___ __ _ | | | '_ \ / __/ _` |/ __/ _` | | | | |_) | (_| (_| | (_| (_| | |_|_|_.__/ \___\__,_|\___\__,_|
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.