Shellcoding on Windows: Part II - Stack Overflow Problems

February 12th, 2008 Greg

The stack overflow has been discussed to death. If you don’t know the basic principle, then you should check out some of the the sixty-eight thousand hits on Google. Many of these descriptions would have you believe that any overflowable stack buffer will immediately allow the attacker to get root (or whatever the Windows equivalent might be), but if you’ve ever tried to exploit a real-world stack overflow vulnerability you’d realise that it’s a lot harder than it sounds. Here are some of the more common problems:

  • A user-modifiable stack buffer is usually designed to hold string data, but even when this isn’t the case, it’s rare to find a situation where arbitrary input is accepted and blindly copied to the stack. It’s not infeasible that your shellcode will be restricted to null-terminated printable ASCII (that’s 0×20-0×7E inclusive), and if you’ve ever tried to write code that assembles into this range you’ll realise that it’s no mean feat. Furthermore, not all strings are ASCII and even a seasoned hacker can have trouble crafting an executable Unicode string.
  • If you’re able to provide an arbitrary amount of data then overflowing a return-address is easy. But what’s not so straightforward is ensuring that the function actually gets a chance to return - after all, you have just corrupted every stack variable between the buffer and the return-address.
  • Suppose that your shellcode compiles okay, passes the input filters; no crashes occur and that you now own EIP after the vulnerable function returns. Just where should you make the target return to? Understand that the address from which to commence execution must be known at the time the shellcode is provided, and moreover that - in the paradigm case - your shellcode lies ’somewhere’ on the stack. Inherent in the nature of stack-based function architecture is the fact that the same function can execute many times without ever taking the same value of ESP. This problem of locating your shellcode after injection is one that never seems to go away and has become the bane of many hackers’ lives.
  • If we weren’t already struggling enough, the recent shift in focus towards security has prompted the Windows kernel developers to take more and more precautions regarding the execution of data buffers. Windows XP SP2 introduced DEP (data-execution prevention) for Windows Services, and Vista/Server 2003 extended this to protect all processes by default. This means that as of Windows Vista, any attempts to execute code on the stack will fail with a warning dialog from the OS, provided the system’s processor supports the NX/XD bit (Intel and AMD couldn’t agree on nomenclature, apparently).
  • Because the OS can only do so much, many compilers now ship with support for automatic security code-generation. In particular, Visual Studio 2005 introduced the GS flag, which creates what Microsoft are calling a Security Cookie (but to everyone else, a stack canary) within each function’s stack frame. With this option enabled, each function will push a pseudo-random dword onto the stack in its prologue, and check that it hasn’t been modified by the time the epilogue is reached. This way, any attempts to overflow into the return-address will corrupt the canary and alert the program before the RETN occurs.

All of these problems can be appeased to a degree through a variety of techniques. Notably, the use of structured exception handling in the target application can make our job as an attacker considerably easier as we may be able to abuse the SEH records and sidestep several of these problems in one go. Details next time.

Run-time determination of VC++ virtual member function addresses: Take II

February 6th, 2008 Greg

I wrote about this tricky little problem a while ago and wasn’t too happy with the desperate methods that seemed necessary. Since then, I’ve been shown a much cleaner way to do the same thing, by manipulating the vTable manually. It seems that Microsoft haven’t changed their vTable implementation since Visual Studio 6 (at least) and so with a little modification, the following piece of inline-assembly will do the trick: no muss, no fuss.

__declspec(naked) void* ResolveVirtualFunction(IDirect3DDevice9* pDevice, ...) {
    __asm {
        mov eax, dword ptr ss:[esp+0x08]
        add eax, 0x8
        cmp byte ptr ds:[eax-1], 0xA0
        mov eax, dword ptr ds:[eax]
        je normal_index
        and eax, 0xFF
normal_index:
        mov ecx, eax
        mov eax, dword ptr ss:[esp+0x4]
        mov eax, dword ptr ds:[eax]
        mov eax, dword ptr ds:[eax+ecx]
        retn
    }
}
 
// ...
 
// The function should be invoked like this:
void* address_device_present = ResolveVirtualFunction(device, &IDirect3DDevice9::Present);

Thanks go to Vuurvlieg for this function. The beauty (or horror), here, is the use of a variadic parameter-list to overcome C++’s strong-typing that would otherwise make this operation very difficult. Obviously, this implementation will only work for objects of type IDirect3DDevice9, but the method extends to any other class by simply replacing the class name in the function declaration. Don’t be tempted to generalise this function to IUnknown or some other common base-class, as you’ll quickly run into problems with object-slicing. A final warning to those still using Visual C++ 6 (not that you deserve any help for such a crime): you’ll need to drop the ampersand from the second argument in the function call, as VC++6 handles function pointers slightly differently.

Direct3D 9 Hook v1.1

February 1st, 2008 Greg

By popular demand, I’ve updated the Direct3D 9 Hooking Sample to accommodate Windows Vista. The same binary should work on both Vista and XP. I’ve only tested it on Vista 64-bit, so it’d be nice to know if it works with Vista 32 or not. Other than this, most of the same caveats apply as last time.

Screenshot