mercredi 14 janvier 2015

Let's have some fun with afl

1/ Let's play

Let's play with the fuzzer afl. I'll write some blogposts about my research with afl. This can be seen as a diary of a fuzzer :-)

2/ At first, choose your target

I think that afl has been pretty much used on usual unix binaries (compressor, file format, and so on), so I did a
$ ls /usr/bin

and choose one of them in order to fuzz. afl is great at fuzzing programs which take a file as argument and don't produce too much output. There is a lot of them which can be fuzzed.

That's easy, just grab the sources of the binary you want to fuzz, recompile it using afl-gcc (or afl-g++), and roll!
Sometimes, it's better to desactivate checksum computations: fuzzing goes faster, fuzzing goes farther (doesn't stop for a bad checksum) and in case of a crash, you can easily recalculate the checksum and see if crash is still here.

After fuzzing a lot of software, I managed to reach two crashes:

That's enough for a good start. Those two crashes will be investigated.

I don't look at hangs: my computer do a lot of things (loadavg > 1 most of the time), and afl has an aggressive value of 50ms for saying that program has stopped. So, there is a lot of false positive. And I'm mostly interested in crashes anyway.

3/ Keep focused

Afl comes with an handy helper call Peruvian were rabbit. Just feed afl-fuzz with some known files causing a crash and it will make some variation around it in order to see if some new crashes appears.

$ cd ..
$ mkdir crashes crashes/findings crashes/testcases
$ cp fuzzy/findings/crashes/id\:000001* crashes/testcases/case1
$ cp fuzzy/findings/crashes/id\:000002* crashes/testcases/case2
$ cd crashes
$ afl-gcc -C -i testcases/ -o findings/ unnamed -t @@

And unsurprisingly, number of crashes grow very fast:

I have now 255 files causing crashes.

What's really interesting in my case is that the unmodified program (the one doing checksum) segfaults too :-) It writes a message "bad checksum", but segfault like a boss:

mitsurugi@mitsu:~/fuzz$ ./unnamed-no-cksum -t case1
Segmentation fault
mitsurugi@mitsu:~/fuzz$ ./unnamed-ori -t case1
    failed (checksum error)
Segmentation fault

mitsurugi@mitsu:~/fuzz$ ./unnamed-no-cksum -t case1
Segmentation fault

mitsurugi@mitsu:~/fuzz$ dmesg | tail -1
[784784.901989] unnamed-no-cksum[29344]: segfault at 0 ip   (null) sp bf89d38c error 14 in unnamed-no-cksum[8048000+57000]
And it seems promising, because it crash on a bad EIP value (and not a losy read or write in forbidden location). My senseï said:

"If you manage to control EIP, you'll soon manage to control the world"

4/ Let's investigate

I have a good lead, the next step is to force EIP to a choosen value (0x41414141 for example) instead of 0x00000000.

The crash appears here:
=> 0x804daf0:    call   DWORD PTR [eax+0x40]
   0x804daf3:    cmp    eax,0x3
   0x804daf6:    je     0x804db54

And the memory layout around eax is:
gdb$ x/12dwx $eax + 0x30
0x80618b0:   0x0804a580    0x0804a560    0x00000000    0x0000eaea
0x80618c0:   0x00000000    0x00000000    0x080601e8    0x08060080
0x80618d0:   0x00000000    0x080618dc    0x080618dc    0x00000000

unfortunately, I don't have 0xeaea followed by some 0x00 in source file. So I think I'll have to dig really further.

I also have 255 files, I choose 10 of them, all of them crash with EIP=0x00000000. It's time to industrialize the checkings.

That's all for today :-)

Aucun commentaire:

Enregistrer un commentaire