In this post I'm describing the inner working of IsBad*Ptr, the steps the attacker may follow to abuse them, and mention few examples of binaries that have a reference to these banned functions.
Inner Working
When IsBad*Ptr is executed it first registers an exception handler. Then, it attempts to access to the memory specified in the argument list.For example, IsBadReadPtr has the following instruction to read memory. ECX is the memory address specified in the argument list.
mov al,byte ptr [ecx]
If the instruction raises an exception, the execution is transferred to the exception-handler code. And IsBad*Ptr returns TRUE, meaning, it is a "bad" pointer because the data pointed by is inaccessible.
If the instruction executes without an exception being raised IsBad*Ptr returns FALSE.
Steps of Attacking
The attack against IsBad*Ptr looks like this.- The attacker attempts to supply an invalid pointer parameter to IsBad*Ptr that returns TRUE.
The attacker refines step #1 in a way that the supplied invalid pointer becomes valid due to a forced allocation for the location pointed by the invalid pointer.The attacker refines step #1 in a way that the supplied invalid pointer will point to valid memory location allocated by heap spray. And so, IsBad*Ptr returns FALSE leading to enter in an inconsistent state; that may or may not be an exploitable state.- If the attacker can perform step #2 with IsBadWritePtr, when the call returns, it's expected to reach code that writes the location pointed by the pointer -- and that has attacker controlled data. And so, he reaches a presumably exploitable condition.
Examples
.text:72A0FEE5 push 38h ; ucb
.text:72A0FEE7 push edi ; attacker supplies pointer was invalid before
.text:72A0FEE8 call ds:IsBadReadPtr ; and now it's valid because he's filled memory up
.text:72A0FEEE test eax, eax
.text:72A0FEF0 jnz loc_72A0FF80 ; fall through
.text:72A0FEF6 mov eax, [edi+4]
.text:72A0FEF9 mov eax, [eax+4]
.text:72A0FEFC mov esi, [eax+8] ; ESI is attacker controlled
.text:72A0FEFF and [ebp+arg_0], 0
.text:72A0FF03 mov ax, [edi+2]
.text:72A0FF07 test esi, esi
.text:72A0FF09 jz short loc_72A0FF42 ; fall through
.text:72A0FF0B movzx ebx, ax
.text:72A0FF0E mov eax, [esi] ; EAX is attacker controlled
.text:72A0FF10 push esi
.text:72A0FF11 call dword ptr [eax+0Ch] ; EIP is attacker controlled
This one below can be found in dxtrans.dll in Windows folder.
.text:35C6142C push 4 ; ucb
.text:35C6142E push esi ; attacker supplies pointer was invalid before
.text:35C6142F call ds:__imp__IsBadWritePtr@8 ; and now it's valid because he's filled memory up
.text:35C61435 test eax, eax
.text:35C61437 jz short loc_35C61440 ; jump is taken
.text:35C61439 mov eax, 80004003h
.text:35C6143E jmp short loc_35C6144A
.text:35C61440 loc_35C61440: ; CODE XREF: CDXBaseSurface::GetAppData(ulong *)+14
.text:35C61440 mov eax, [ebp+this]
.text:35C61443 mov eax, [eax+24h]
.text:35C61446 mov [esi], eax ; ESI is attacker controlled
.text:7A0D17FB push eax ; ucb
.text:7A0D17FC push ebx ; attacker supplies pointer was invalid before
.text:7A0D17FD call ds:__imp__IsBadReadPtr@8 ; and now it's valid because he's filled memory up
.text:7A0D1803 test eax, eax
.text:7A0D1805 jz short loc_7A0D17A7 ; jump is taken
[...]
.text:7A0D17A7 cmp edi, esi
.text:7A0D17A9 jle short loc_7A0D17BF
.text:7A0D17AB push esi ; cchWideChar
.text:7A0D17AC push esi ; lpWideCharStr
.text:7A0D17AD push edi ; cbMultiByte
.text:7A0D17AE push ebx ; lpMultiByteStr - attacker's data
.text:7A0D17AF push 1 ; dwFlags
.text:7A0D17B1 push esi ; CodePage
.text:7A0D17B2 call ?WszMultiByteToWideChar@@YGHIKPBDHPAGH@Z ; WszMultiByteToWideChar(uint,ulong,char const *,int,ushort *,int)
UPDATE 13/May/2014 To add IsBad*Ptr to the program doesn't automatically mean to create bugs. However if IsBad*Ptr is present we have reason to believe that the function is expecting a pointer that might be invalid in certain circumstances. In that case IsBad*Ptr may be used to attack the program. And that's why it's important to conduct the audit according to this.
UPDATE 16/May/2014 The term "valid pointer" had an ambiguous meaning in the part Steps of Attacking. This is now reworded. Reference.
[1] IsBad*Ptr functions are IsBadReadPtr, IsBadCodePtr, IsBadWritePtr, and IsBadStringPtr. All of them are exports of kernel32.dll.