MindshaRE is our bi-weekly look at some simple reverse engineering tips and tricks. The goal is to keep things small and discuss every day aspects of reversing. You can view previous entries here by going through our blog history.
First off, determining exploitability takes time and skill. In some cases it takes more time than skill, or vice-versa. We see this problem all of the time when verifying cases for the ZDI. We may receive a submission where an access violation happens on a read at address 0x0000000. In 90% of cases this is unexploitable after verifying that the address of the read is not user controllable and does not have a negative side effect. This kind of analysis can take anywhere from 1 minute to several days based on the complexity of the software, and vulnerability. This is where Microsoft has stepped in to offer some help.
This new MSEC extension provides the !exploitable command for users of WinDbg. The command uses a defined rule set to determine the severity of a crash by processing the information post-mortem. It achieves this by processing meta-instructions such as a branch, data move, return, etc. The rule may ask "Is the faulting instruction a read violation of EIP?". If the answer is yes, it calls it a day and labels it exploitable. The details of the design can be found in the presentation slides here. Let's look at an example of the plugin.
0:000> g @@masm(`c:\test\call_taint.c:26+`)
ModLoad: 5cb70000 5cb96000 C:\WINDOWS\system32\ShimEng.dll
eax=00033258 ebx=0013ff78 ecx=00000000 edx=0041c4f0 esi=00fcf762 edi=00fcf6f2
eip=00401030 esp=0013ff68 ebp=0013ff78 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
call_taint!main+0x20:
00401030 8b55fc mov edx,dword ptr [ebp-4] ss:0023:0013ff74=41414141
0:000> t
eax=00033258 ebx=0013ff78 ecx=00000000 edx=41414141 esi=00fcf762 edi=00fcf6f2
eip=00401033 esp=0013ff68 ebp=0013ff78 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
call_taint!main+0x23:
00401033 ffd2 call edx {41414141}0:000> t
eax=00033258 ebx=0013ff78 ecx=00000000 edx=41414141 esi=00fcf762 edi=00fcf6f2
eip=41414141 esp=0013ff64 ebp=0013ff78 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
41414141 ?? ???
0:000> t
(ca0.79c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00033258 ebx=0013ff78 ecx=00000000 edx=41414141 esi=00fcf762 edi=00fcf6f2
eip=41414141 esp=0013ff64 ebp=0013ff78 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
41414141 ?? ???
0:000> !MSEC.exploitable -v
HostMachine\HostUser
Executing Processor Architecture is x86
Debuggee is in User Mode
Debuggee is a live user mode debugging session on the local machine
Event Type: Exception
Exception Faulting Address: 0x41414141
First Chance Exception Type: STATUS_ACCESS_VIOLATION (0xC0000005)
Exception Sub-Type: Read Access Violation
Exception Hash (Major/Minor): 0x2b214251.0x1a224251
Stack Trace:
Unknown
call_taint!main+0x25
call_taint!__tmainCRTStartup+0xfb
kernel32!BaseProcessStart+0x23
Instruction Address: 0x41414141
Description: Read Access Violation at the Instruction Pointer
Short Description: ReadAVonIP
Exploitability Classification: EXPLOITABLE
Recommended Bug Title: Exploitable - Read Access Violation at the Instruction Pointer
starting at Unknown Symbol @ 0xfce1dcffff000a
(Hash=0x2b214251.0x1a224251)
In this example I have written a test that overwrites a register being used in a call. When the access violation occurs I issue the !MSEC.exploitable -v command. The verbose output of this command shows the meta-info from the crash after processing the offending function and register state. Of importance is the "Short Description", "Exploitability Classification", and "Recommended Bug Title". Here, the plugin does a fantastic job of calling this one exploitable, or does it?
Access violations at the instruction pointer are exploitable if not near NULL.
In reality this bug is not exploitable. Here is the assembly.
_declspec(naked) int main()
{_asm
{push ebp
mov ebp, esp
sub esp, 0x10
mov dword ptr [ebp-4], 0x0
pre:
mov ecx, 0x10
lea ebx, [ebp-0x10]
cpy_loop:
test ecx, ecx
jz kill
mov byte ptr [ebx], 0x41
dec ecx
inc ebx
jmp cpy_loop
kill:
mov edx, dword ptr [ebp-4]
call edx
mov esp, ebp
pop ebp
retn 0x10
}
}The problem is the lack of user input. In my opinion, this is the most necessary question in "exploitability", and the one Microsoft themselves claim is a fundamental limitation. Their assumption is any register in the faulting instruction is user controllable. While this is a good stance to take, it is a bit misleading.
Lets take a look at another example.
_declspec(naked) int main()
{_asm
{push ebp
mov ebp, esp
sub esp, 0x10
mov dword ptr [ebp-4], 0x21212121
mov edx, dword ptr [ebp-4]
mov ebx, dword ptr [edx]
mov esp, ebp
pop ebp
retn 0x10
}
}As you can see, this is not exploitable. What does !exploitable say?
(5e4.918): Access violation - code c0000005 (!!! second chance !!!)
eax=00033258 ebx=7ffd5000 ecx=00000001 edx=21212121 esi=0127f766 edi=0127f6f2
eip=00401020 esp=0013ff68 ebp=0013ff78 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
read_untaint!main+0x10:
00401020 8b1a mov ebx,dword ptr [edx] ds:0023:21212121=????????
0:000> !MSEC.exploitable -v
HostMachine\HostUser
Executing Processor Architecture is x86
Debuggee is in User Mode
Debuggee is a live user mode debugging session on the local machine
Event Type: Exception
Exception Faulting Address: 0x21212121
Second Chance Exception Type: STATUS_ACCESS_VIOLATION (0xC0000005)
Exception Sub-Type: Read Access Violation
Faulting Instruction:00401020 mov ebx,dword ptr [edx]
Basic Block:
00401020 mov ebx,dword ptr [edx]
Tainted Input Operands: edx
00401022 mov esp,ebp
00401024 pop esp
00401025 ret 10h
Tainted Input Operands: edx
Exception Hash (Major/Minor): 0x72653670.0x5d651c5a
Stack Trace:
read_untaint!main+0x10
read_untaint!__tmainCRTStartup+0xfb
kernel32!BaseProcessStart+0x23
Instruction Address: 0x401020
Description: Data from Faulting Address may be used as a return value
Short Description: TaintedDataReturnedFromFunction
Exploitability Classification: UNKNOWN
Recommended Bug Title: Data from Faulting Address may be used as a return value
starting at read_untaint!main+0x10 (Hash=0x72653670.0x5d651c5a)
Hrmm UNKNOWN? Now what?
The data from the faulting address may later be used as a return value from this function.
The more crashes I look at with this plugin the more I understand its goal. The goal is to raise the attention of a developer that has little security knowledge regarding exploitation. In almost all cases I see an "UNKNOWN", "PROBABLY_EXPLOITABLE", or "EXPLOITABLE" label outputted by the plugin. While I agree with the approach of erring on the side of EXPLOITABLE, I also think it may lead to an influx in false positives. Microsoft themselves even claim "The lightweight flow analysis and the above assumption can result in over-assessing risk".
I applaud the work the security science team at Microsoft has done. The plugin design is impressive, including a functional meta-language and rule set. The problem is when the output is considered reliable as one media outlet claims. I hope the tool does not lead to an influx of "But !exploitable said its exploitable" or even worse "!exploitable said it is not exploitable". In the plugins current state I do not believe this tool saves security researchers time. Hopefully as the tool matures and more rules are added it becomes a goto plugin for determining exploitability.
As always feel free to leave your thoughts.
-Cody
