Jay Taylor's notesback to listing index
lcamtuf's blog[web search]
Original source (lcamtuf.blogspot.com)
Clipped on: 2022-01-28
November 07, 2014
This is an interesting demonstration of the capabilities of afl; I was actually pretty surprised that it worked!
$ mkdir in_dir $ echo 'hello' >in_dir/hello $ ./afl-fuzz -i in_dir -o out_dir ./jpeg-9a/djpegIn essence, I created a text file containing just "hello" and asked the fuzzer to keep feeding it to a program that expects a JPEG image (djpeg is a simple utility bundled with the ubiquitous IJG jpeg image library; libjpeg-turbo should also work). Of course, my input file does not resemble a valid picture, so it gets immediately rejected by the utility:
$ ./djpeg '../out_dir/queue/id:000000,orig:hello' Not a JPEG file: starts with 0x68 0x65Such a fuzzing run would be normally completely pointless: there is essentially no chance that a "hello" could be ever turned into a valid JPEG by a traditional, format-agnostic fuzzer, since the probability that dozens of random tweaks would align just right is astronomically low.Luckily, afl-fuzz can leverage lightweight assembly-level instrumentation to its advantage - and within a millisecond or so, it notices that although setting the first byte to 0xff does not change the externally observable output, it triggers a slightly different internal code path in the tested app. Equipped with this information, it decides to use that test case as a seed for future fuzzing rounds:
$ ./djpeg '../out_dir/queue/id:000001,src:000000,op:int8,pos:0,val:-1,+cov' Not a JPEG file: starts with 0xff 0x65When later working with that second-generation test case, the fuzzer almost immediately notices that setting the second byte to 0xd8 does something even more interesting:
$ ./djpeg '../out_dir/queue/id:000004,src:000001,op:havoc,rep:16,+cov' Premature end of JPEG file JPEG datastream contains no imageAt this point, the fuzzer managed to synthesize the valid file header - and actually realized its significance. Using this output as the seed for the next round of fuzzing, it quickly starts getting deeper and deeper into the woods. Within several hundred generations and several hundred million execve() calls, it figures out more and more of the essential control structures that make a valid JPEG file - SOFs, Huffman tables, quantization tables, SOS markers, and so on:
$ ./djpeg '../out_dir/queue/id:000008,src:000004,op:havoc,rep:2,+cov' Invalid JPEG file structure: two SOI markers ... $ ./djpeg '../out_dir/queue/id:001005,src:000262+000979,op:splice,rep:2' Quantization table 0x0e was not defined ... $ ./djpeg '../out_dir/queue/id:001282,src:001005+001270,op:splice,rep:2,+cov' >.tmp; ls -l .tmp -rw-r--r-- 1 lcamtuf lcamtuf 7069 Nov 7 09:29 .tmpThe first image, hit after about six hours on an 8-core system, looks very unassuming: it's a blank grayscale image, 3 pixels wide and 784 pixels tall. But the moment it is discovered, the fuzzer starts using the image as a seed - rapidly producing a wide array of more interesting pics for every new execution path:
if (strcmp(header.magic_password, "h4ck3d by p1gZ")) goto terminate_now;In practical terms, this means that afl-fuzz won't have as much luck "inventing" PNG files or non-trivial HTML documents from scratch - and will need a starting point better than just "hello". To consistently deal with code constructs similar to the one shown above, a general-purpose fuzzer would need to understand the operation of the targeted binary on a wholly different level. There is some progress on this in the academia, but frameworks that can pull this off across diverse and complex codebases in a quick, easy, and reliable way are probably still years away.PS. Several folks asked me about symbolic execution and other inspirations for afl-fuzz; I put together some notes in this doc.
Subscribe to: Post Comments (Atom)