...
BFF includes the ability to perform string minimization during fuzzing. For every unique crash encountered, instead of minimizing the crashing testcase to the seed file, BFF will minimize the crashing testcase to a string of ASCII 'x' characters. The option is enabled with the following configuration item in bff.yaml
:
Code Block | ||
---|---|---|
| ||
runoptions: minimize: string |
...
Code Block | ||
---|---|---|
| ||
runoptions: keep_unique_faddr: True |
On non-Windows platforms supported by BFF, the crash identifier is generated using an MD5 hash, so the faulting address isn't obvious based solely on the directory name.
Combining These Options
When the above two options are both used, BFF is put into a mode where it becomes more obvious which crashes have an EFA that is directly influenced by the bytes in the fuzzed file. By looking for EFA patterns that have 0x78
in them, you can find crashes where you may be able to influence the code being executed. For example:
...
Here are multiple crashes where the faulting address appear to be influenced by the 'x' bytes in our fuzzed file. Again, to put BFF into this mode, use the following two options:
runoptions:
...
Code Block | ||||||
---|---|---|---|---|---|---|
|
runoptions: minimize: |
...
string keep_unique_faddr: True |
Assuming you have Cygwin installed on your Windows fuzzing VM, crashes that appear to have a controllable EFA can be found with these commands:
C
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
C:\BFF>find . -name "*78*msec" | grep --color 78 |
fuzz@UbuFuzz:~$ find ~ -name "*.gdb" | xargs egrep "^si_addr.*78*" | grep --color |
78 |
Digging Into BFF Results
...
When testing out fuzzing strategies, it can be effective to target old software. The assumption here is that older software is more likely to crash when fuzzed. This assumption turns out to be quite true:
0x5b334a69.0xae9fae70.0x58787878_0xe6b39f75.0x28e42113.0x7878787c - Exploitability rank: 5
Code Block | ||
---|---|---|
| ||
0x2cb0f334.0x4bb3d30a - Exploitability rank: 10 Fuzzed file: results\TARGET\crashers\EXPLOITABLE\ |
exception 0: ReadAVonIP accessing 0x78787878 *** Byte pattern is in fuzzed file! ***
78787878 ?? ???
Instruction pointer is not in a loaded module!
0x2cb0f334.0x4bb3d30a\sf_7d7bb89974213e3de4d2b9289fa0caba-4257-0x00130000-minimized.EXT
exception 0: ExceptionHandlerCorrupted accessing 0x00130000
0040eaec f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
Code executing in: image00400000
exception 1: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
exception 2: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
exception 3: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
exception 4: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
exception 5: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
exception 6: ReadAVonIP accessing 0x6e4e99dd *** Byte pattern is in fuzzed file! ***
6e4e99dd ?? ???
Instruction pointer is not in a loaded module!
|
This looks quite promising! The first thing we will do is take this crash and do a Metasploit string minimization on it:
C
Code Block | ||
---|---|---|
| ||
C:\BFF>tools\minimize.py -s -k -f results\psp501-x\crashers\EXPLOITABLE\0x5b334a69.0xae9fae70.0x58787878_0xe6b39f75.0x28e42113.0x7878787c\sf_1f25044e863e7b1bef5ae42d968fe27f-siv0qq-0x58787878.wpg |
After this is done, we will have a number of files in the minimizer_out
directory. The one I'm interested in has -min-mtsp
appended to the file name. We can run tools\repro.py
to reproduce the crash:
C
Code Block | ||
---|---|---|
| ||
C:\BFF>tools\repro.py minimizer_out\sf_1f25044e863e7b1bef5ae42d968fe27f-siv0qq-0x58787878-0x58787878-min-mtsp.wpg -p immunitydebugger |
Assuming that immunitydebugger.exe
is in our PATH, this will reproduce the newly-string-minimized crash in Immunity Debugger:
...
Other old target that I looked at was FastStone MaxView 1.6. After a short amount of fuzzing, this crash came up:
Code Block | ||
---|---|---|
| ||
0x3eda38dc.0x5ce6d1f9.0x00cc0000_0x3eda38dc.0x3e7d918a.0x7878787c_0x3eda38dc.0x7095d__ - Exploitability rank: 50 |
Fuzzed file: results\maxview-x\crashers\EXPLOITABLE\0x3eda38dc.0x5ce6d1f9.0x00cc0000_0x3eda38dc.0x3e7d918a.0x7878787c_0x3eda38dc.0x7095d__\sf_540cee04253030f363f7902b6edc732d-aikdpf-0x00cc0000.tga |
exception |
0: WriteAV accessing 0x00cc0000 004fd19c 880416 mov byte ptr [esi+edx], |
al ds:0023:00cc0000=?? |
Code executing in: image00400000 |
exception 1: WriteAV accessing |
0x7878787c *** Byte pattern is in fuzzed file! *** |
004022c2 894104 mov dword ptr [ecx+4],eax ds:0023:7878787c=???????? |
Here we have a crash that is ranked as a 50
. What makes this crash interesting is that we have a WriteAV
exception, and the faulting address looks to be under our control (due to the 78
's). Let's look in Immunity Debugger:
...
When fuzzing with BFF, the tool used for exploitability determination can affect what crashes look to be interesting. Microsoft !exploitable traces taint throughout the rest of the current, faulting basic block. The gdb exploitable tool only looks at the faulting instruction. The important thing to realize is that neither technique is sufficient to properly determine exploitability of a crash.
As the above diagram indicates, what if the bottom green basic block is one that is interesting? That is, for example, it performs a CALL
instruction based on tainted data. This would constitute an exploitable crash. It's important to realize that neither Microsoft !exploitable nor gdb exploitable can detect this situation.
...
Why does Microsoft !exploitable treat this as an UNKNOWN
? Remember that the !exploitable visibility is limited to the current basic block. Specifically:
300F57FD . F646 06 04 TEST BYTE PTR
Code Block | ||
---|---|---|
| ||
300F57FD . F646 06 04 TEST BYTE PTR DS:[ESI+6],4 |
300F5801 . 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10] |
300F5804 . 8975 F0 MOV DWORD PTR SS:[EBP-10],ESI |
300F5807 . 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX |
300F580A . 75 10 JNZ SHORT EXCEL.300F581C
300F580A . 75 10 JNZ SHORT EXCEL.300F581C |
We have an exception on the TEST
instruction, and the end of the basic block is a conditional jump: JNZ
. By configuring BFF to perform string minimization during fuzzing and also to also factor the EFA into the uniqueness of a crash, we have more insight into whether this crash is interesting. We know that we can control the EFA due to the presence of the 0x78
bytes. What if we take the exception and turn it into something that does not fault? That is, in our fuzzed file, we change the 0x78787878
pattern into an address that will allow TEST BYTE PTR DS:[ESI+6],4
to succeed.
...
Well now this is interesting! We have an access violation on a CALL
instruction. This is reported as PROBABLY_EXPLOITABLE
by !exploitable:
Code Block |
---|
| ||
30ea6b1a ff10 call dword ptr [eax] ds:0023:00000000=???????? |
0:000> !exploitable |
!exploitable 1.6.0.0 |
*** ERROR: Symbol file could not be found. |
Defaulted to export symbols for Excel.EXE - |
Exploitability Classification: PROBABLY_EXPLOITABLE |
Recommended Bug Title: Probably Exploitable - Read Access Violation on Control Flow starting at mso!Ordinal6543+0x0000000000001eda (Hash=0x3d855f61.0xa61eef28) |
Access violations near null in control flow instructions are considered probably exploitable. |
0: |
000> |
We'd like to do better than that, though. Use your favorite tracing techniques and determine how the EAX
register is set before the CALL
. Looking at the Excel code, we determine that EAX
is populated by dereferencing the pointer specified by our original exception twice. By using a pointer-to-a-pointer memory location as our address, we can now demonstrate full control of the CALL
instruction:
...
Jackpot! We've started with an UNKNOWN
crash, and we now have a demonstrably EXPLOITABLE
crash. All of this was made possible with the following two BFF options use together:
Code Block | ||||
---|---|---|---|---|
| ||||
runoptions: |
...
minimize: |
...
string keep_unique_faddr: True |