Uninformed: Informative Information for the Uninformed

Vol 3» 2006.Jan


Introducing breakdance.c

Although file fuzzing is relatively simple, tools help reduce the amount of time it takes for you to reconstruct a format to reach deep into a section buried within several structures. I typically use xxd -i, hd (hexdump), or shred (hexeditor) for windows to reconstruct a binary image and fuzz the structures manually, but I decided to develop a tool to do the work for me in the case of PE. The following options are available:

Usage: ./breakdance [parameters]
Options:
        -v                      verbose
        -o [file]               File to write to (defaults) out.ext
        -f [file]               File to read from
        -e [value]              Modify Export Directory Table's number
                                of functions and number of names
        -p                      Print sections of a PE file and exit
        -c                      Create new section (.pepe) not to be used with -m
        -s [section]            Section to overwrite (can be used with -c)
        -m [section] [value]
        -n [length]             Fuzz Export Directory Table's Strings
                                Modify [section] with [int] where:
                                section is one of [image_start] [number_of_sections]

                ex. ./breakdance -v -o out -f pebin -m "image_start" 65536
                ex. ./breakdance -v -o out -f pebin -c -s .rdata

[Warning if -o option isn't provided with mod options, changes are discarded]

The following is a list of binary parsers affected by the fuzzing options provided by breakdance.c, the list is by no means comprehensive in the sense of PE parsers but it is all I test against. The fuzzing capabilities are rather minimal considering the number of structures and elements accompanied by the PE/COFF specification, however it is enough to demonstrate how broken, binary parsers can be.

Figure: Affected Toolsets
  +--------------+-----------------+-------------------+
  | Tool Name    | Vendor          | Section           |
  +--------------+-----------------+-------------------+
  | PE View      | Wayne Radburn   | All               |
  | MSVS bindump | Microsoft       | All               |
  | OllyDbg      | Oleh Yuschuk    | NumberOfFunctions |
  | PE Explorer  | Haeventools.com | NumberOfSections  |
  +--------------+-----------------+-------------------+

Although I can almost guarantee other parsers are just as buggy, this selection is pretty well known and should suffice as a demonstration. The only issue I will elaborate on is the OllyDebug denial of service attack. This issue is interesting due to the fact that even after modifying the PE Image to DoS OllyDebug, the binary itself is still executable. This can be leveraged as an attack vector against reverse engineerers who rely on olly debug to reverse binaries. The following is a run of breakdance against a DLL.

(xbud@yakuza <~/code/random>) $./breakdance -v -e 4294967295 -f \
/home/xbud/code/libpe/testbins/vncdll.dll -o vnc.dll

...

NumberOfFunctions 58, NumberOfNames: 58, now 2147483647,2147483647
Dumping 348160 bytes

(xbud@yakuza <~/code/random>) $

-- Inside WinDbg --

This exception may be expected and handled.
eax=005d44d0 ebx=0000049c ecx=005d46c8 edx=000001f8 esi=01ed0465 edi=00000000
eip=0045cda4 esp=0012e70c ebp=0012ede8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293

*** WARNING: Unable to verify checksum for C:\tools\odbg110\OLLYDBG.EXE
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for
C:\tools\odbg110\OLLYDBG.EXE -

OLLYDBG!Createlistwindow+0x1bb4:
0045cda4 668b0459         mov     ax,[ecx+ebx*2]        ds:0023:005d5000=????

0:000> kb
ChildEBP RetAddr  Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ede8 0045f7eb 01ed0465 76bf1f1c 76bf2075 OLLYDBG!Createlistwindow+0x1bb4
00000000 00000000 00000000 00000000 00000000 OLLYDBG!Decoderange+0x180b

Conclusions

The general rule of thumb here is not to trust any user modifiable data. The trust between application and input components such as sockets, file I/O, named pipes etc. should always be minimal and at an extreme, should be considered dangerous. The fact that a file format specification exists is not an excuse to assume all data gathered from an alleged file is valid. Validate your input against a working ruleset, and if the assertion fails, raise an exception. Keeping your code simple means accept only valid input, deny all variants.

All the code referenced is provided in the attached tar ball, a safer version of the library for parsing the hypothetical file format developed for this paper is included for demonstration purposes.