ASLR


Address Space Layout Randomization (ASLR) is a technique that makes it more difficult for an exploit to locate system APIs, which in turn makes it harder to leverage system APIs in exploits to run arbitrary code. The approach involves randomizing where system libraries are loaded, all of the starting points of the stack, and the starting points of the heaps. On a Windows XP system, all of these are known to an attacker and may vary somewhat depending on the service pack level of the system. There are even references available on the Web that document this information by version and service pack level.

ASLR includes randomizing all of the following elements of a running program:

  • Image randomization  The addresses where the executable and DLLs are loaded varies

  • Stack randomization  The starting address for each thread’s stack varies

  • Heap randomization  The base address for heap allocations will also vary

One common attack is to call LoadLibrary to force the application to load a DLL. The assembly needed to do this is very trivial, and amounts to:

 Push location of path buffer Call location of LoadLibrary

Thus, if the attacker can write a path into a buffer with a known location–which need not involve an overflow–and then redirect execution into a spot where a very small amount of shell code is located, your application will load a library, possibly across the network, and invoke DllMain. As an attacker, this is a handy technique because a very complex attack can be written in a high-level language, while the minimum size of the shell code needed becomes very small.

ASLR can thwart such an attack by eliminating preconditions needed by the attacker. The first problem the attacker encounters is that the address to be jumped into needs to be known, although not exactly. If an attacker has a large buffer to work with, writing a large number of NOP (no-op) instructions into a buffer creates a NOP slide, and the instruction pointer only needs to be redirected to somewhere in the slide. Next, the address of the library path needs to be known exactly, and so does the address to call the LoadLibrary function. If the starting point of the stack isn’t exactly the same at all times, then finding the buffer with the path is more difficult and so is figuring out where to find the shell code. Finally, if LoadLibrary can’t be counted on to be in the same place at all times, this will pose additional difficulties.

Here’s an application you can use to take a look at how ASLR and stack randomization work on your system:

 #include <windows.h> #include <stdio.h> unsigned long g_GlobalVar = 0; void foo( void ) {    printf( "Address of function foo = %p\n", foo );    g_GlobalVar++; } int main( int argc, char* argv[] ) {    HMODULE hMod = LoadLibrary( L"Kernel32.dll" );    // Note – this is for release builds    HMODULE hModMsVc = LoadLibrary( L"MSVCR80.dll" );    char StackBuffer[256];    void* pvAddress = GetProcAddress(hMod, "LoadLibraryW");    printf( "Kernel32 loaded at %p\n", hMod );    printf( "Address of LoadLibrary = %p\n", pvAddress );    printf( "Address of main = %p\n", main );    pvAddress = GetProcAddress( hModMsVc, "system" );    printf( "MSVCR80.dll loaded at %p\n", hModMsVc );    printf( "Address of system function = %p\n", pvAddress );    foo();    printf( "Address of g_GlobalVar = %p\n", &g_GlobalVar );    printf( "Address of StackBuffer = %p\n", StackBuffer );    if( hMod ) FreeLibrary( hMod );    if( hModMsVc ) FreeLibrary( hModMsVc );    return 0; }

The test app was written using the retail shipping version of Visual Studio 2005, Service Pack 1, and the /dynamicbase linker option, released in Visual Studio 2005, Service Pack 1. Here we find that LoadLibrary shows up in different places across reboots of the system:

 First test: Kernel32 loaded at 77AC0000 Address of LoadLibrary = 77B01E7D Second test: Kernel32 loaded at 77160000 Address of LoadLibrary = 771A1E7D

What is also of interest is that the location of the C runtime library doesn’t change–it loads at address 0x78130000 across both reboots. The C runtime library this application is dynamically linked with was linked with an older linker that did not have the /dynamicbase capability, and it won’t utilize image randomization. If I’d gone to the trouble to load the entire Visual Studio update with the new C run-time DLL on my system, we wouldn’t see this problem, but it does show us something to be careful of–many applications are built using third-party components, and if all of the libraries your vendor supplies aren’t also rebuilt using the new flag, then they won’t be relocated and will counteract many of the benefits of ASLR. If it’s a library that comes with source, be sure to rebuild it yourself to get the benefits of ASLR, although you must also be careful to test and ensure that the change doesn’t break something. Most DLLs won’t be disturbed by ASLR, but this opt-in behavior is designed to keep applications from randomly breaking when upgrading to Vista.

Limitations of ASLR

ASLR is performed systemwide, once per reboot. One note is that if all of the processes using a particular DLL unload ASLR then it would be loaded in a random place on the next load, but many of the system DLLs are always loaded by several processes and only get randomized at the next reboot. If you’re dealing with a local attack, an attacker could easily determine addresses, and then launch the attack. This feature helps inhibit network-based attacks, especially worms. If an application has an information disclosure vulnerability (where it reveals exception details to an attacker) or has a format string vulnerability (which would allow the values on the stack to be read), it may be possible for an attacker to learn the memory locations needed to overcome this mitigation. An attacker-controller read might also be used to place information needed for an attack into either a known location or a location with a known offset. Another implication is that if the network service restarts itself on failure, the attacker now has more chances to find where to call the system API, which is why we recommend that services be configured to restart automatically a small number of times. To reduce virtual address space fragmentation, the library is only relocated across 256 different possible load addresses; note that the randomization is in the second-most significant byte of the address.

Performance and Compatibility Implications

One item that comes to mind immediately when thinking about relocating DLLs is that software developers sometimes spend considerable time figuring out just where to set the base address of a DLL, because when two DLLs try to load into the same spot (or have overlapping ranges), the last one to load is relocated to a different address. The relocation process can be very expensive. Every fixed address in the entire DLL needs to be changed to reflect the new starting point, so anyone concerned with load performance should try very hard to prevent relocation. If relocation is such a bad thing, then, what’s the impact of randomly relocating everything?

The way ASLR is implemented deals with the performance concerns by delaying fixups until that page of the DLL is loaded into memory. For example, Kernel32.dll exports 1,202 functions, occupying about 160 pages of memory. A typical console application might only use a dozen or so functions exported by Kernel32.dll and would only need to fix up the pages required to load those functions.

A second performance enhancement comes because the DLLs don’t set their own addresses any longer; Vista now packs them in with as little slack space between loaded DLLs as possible. While 2 gigabytes of address space used to seem like a lot, a modern application can often use as much memory as possible. With all the DLLs being loaded into a relatively contiguous space, there’s effectively more memory available for other purposes. Having the memory addresses relatively close to one another can sometimes help the processor cache perform more effectively.

As implemented in Windows Vista, the compatibility implications of ASLR aren’t much of an issue. Microsoft Office 2007 is a very large code base, and has a wide variety of programming practices and techniques. When Office enabled ASLR and ran a test pass, we didn’t find any substantial performance degradation, and no regressions. Although there may be things a developer could do to break themselves if ASLR were enabled, like hard-code function addresses, if all of Office can turn this on with remarkably few problems, most apps should be in great shape.



Writing Secure Code for Windows Vista
Writing Secure Code for Windows Vista (Best Practices (Microsoft))
ISBN: 0735623937
EAN: 2147483647
Year: 2004
Pages: 122

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net