In this article, we are going to review ASLR, Mandatory ASLR, and Bottom Up/High-entropy ASLR.
Address space layout randomization aka ASLR was first introduced in the PaX patch for Linux in 2001. The goal of ASLR is to randomize the memory address space of applications and operating system. In other words, when you launch a program, it should not have the same memory addresses as in previous executions. Randomized memory negatively impacts exploit development time and complexity. The attacker can’t assume that the functionality they need is at the same address across all PCs, so they have to invest in circumvention techniques.
It’s important to note that ASLR doesn’t remove underlying problems, just makes memory manipulation vulnerabilities (like stack and heap overflows and underflows, format string vulnerabilities, array index overflows, uninitialized variables, etc) that are sensitive to the memory layout of the program harder to exploit.
To enable ASLR, application and its modules need to be compiled with
/DYNAMICBASE. Since Windows 7, users can choose to enable it for all applications even if they weren’t compiled with
/DYNAMICBASE flag. While this will incur additional costs, it’s a price worth paying for the security features ASLR provides.
How Does ASLR work?
In order to enable ASLR, the executable image (EXE/DLL) has to be compiled as position independent code so that the code can be executed regardless of its base address. When the
/DYNAMICBASE is supplied, the code is compiled as position independent and the
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (located at offset
0x40) option in
DllCharacteristics PE Header will be set. In fact, any executable with PE header can elect to participate in ASLR by setting the
When the image with ASLR bit set is loaded, OS will put its base at a random global image offset which is selected once upon the system booting from a set of 256 64k-aligned values. This means that the program code, data segment, and libraries will be randomized only between reboots. Important to note, Windows will not just shift everything by a random global base offset - each image will be placed pseudorandomly somewhere in the memory taking the original base address into consideration.
Each process's memory layout is randomized further:
- The stack address is selected from a range of 32 slots, each separated by
STACK_SIZEoption (usually 64kb or 256kb).
- The stack pointer is decremented by a random amount with the following constraints: address is 4 byte aligned on IA32, 8 bytes aligned on I64 and the offset is no greater than half a page (2048 bytes).
- Each heap (default, private, CRT) is also placed randomly at the address selected from a range of 32 slots. However, each slot is separated by 64kb blocks only. The heap's address space must also not be colliding with the stack or other heaps of the process.
- The Process Environment Block (PEB) is also placed randomly regardless of ASLR flag.
- Stack, heap, and PEBs will be random on each program execution.
Windows Defender Exploit Guard Settings
As you can see, ASLR is a useful tool for adding entropy to the address space and making it more difficult to abuse address space information where possible. Which brings us to the Windows Defender settings: we have three options - Mandatory ASLR, Bottom Up ASLR and High-entropy ASLR, and the way they play with each other may not be that straightforward.
Mandatory ASLR essentially ignores whether the image chooses to participate in ASLR with
/DYNAMICBASE. When this option enabled, Windows kernel will rebase all executables. It works by mimicking the behavior of a base address collision. When a non-ASLR EXE/DLL is mapped, the base collision occurs and the new base address of the EXE/DLL is selected by searching for a free region starting from the bottom of the address space.
In order to add entropy for mandatory ASLR allocations, the "randomize memory allocations" must be also turned on. This option led to some confusion and even a CERT-US publication in November 2017, where Will Dormann, a security researcher, noticed that a non-ASLR EXE file always loads at the same address. The reason for that is that Mandatory ASLR only creates a base address collision, while the bottom-up randomization works by reserving a random number (between 0 and 256) of 64K regions via
VirtualAlloc. By consuming a small random portion of the bottom part of the address space, this technique makes the base address collision resolution less predictable. Without Bottom Up randomization, the bottom part of the stack is randomized only by the sizes of the heap, stack and EXE file, which is fairly static.
Here is the reference published by Microsoft to explain how this works out:
The effectiveness of ASLR increases with extra entropy in the system. The High-entropy ASLR (aka HiASLR) option adds additional variability to Bottom-up ASLR. Essentially, it introduces 1TB of variance in start address of heap (as well as stack and other allocations) in 64-bit processes, which means an attacker would need to allocate over 1 TB of memory to be able to write shellcode into a predictable memory location. Guessing is absolutely out of the question since with 24 bits of entropy we have 1 in 16,777,216 chance of guessing the start address correctly. High-entropy bottom-up randomization is only meaningful for native 64-bit processes since 32-bit systems are practically constrained by the hardware to only 2GB of entropy.
How to exploit
Bypassing ASLR became a sort of sport among security researchers and exploit writers. Even though ASLR makes it difficult to guess the address of features useful in exploitation, a number of exploit techniques were developed.
Load a function from a non-ASLR module
This is by far the easiest way to bypass ASLR and the reason why Mandatory ASLR is so important. If you can access necessary instructions from modules that are not compiled with ASLR
Partial EIP overwrite due to poor randomization of high order bits
All Windows has a minimum allocation granularity of 64kb, which means it allocated memory at the 64kb boundary. The two low order bytes of any address in an image file mapping will not be affected by ASLR as a result of this. Which means if our return address is
0x00120000 and we can find a useful gadget on the same 16 block (
0x0012****) we can potentially exploit this. This is a very small space that often gets even shorter due to
\x00 character being appended to an overflown string. While this technique is hard to exploit, it has been done by Alexander Sotirov in 2007 for Animated Cursor Handling Vulnerability Exploit (MS Advisory 935423).
For 32 bit systems, it was sometimes possible to brute-force the address space. Since we already know that the lower 2 bytes do not change, our search space shrinks to
0x0000 - 0xffff values, which has 65535 variations.
Create a big block of NOPs to increase the chance of jump landing on legit memory. Difficult, but possible even when all modules are ASLR-enabled. Won't work if DEP is switched on though.
Leaky pointers aka dangling pointers are the most reliable way to bypass any layered security. A dangling pointer is an improperly managed area of memory that allows the attacker to read arbitrary memory addresses or injecting code. This is a whole family of vulnerabilities ranging from simple "null terminator" abuse to Spectre/Meltdown exploits. If you can read arbitrary memory, it becomes easy to derandomize memory (which is the core of ASLR). Once the memory is derandomized, other techniques can be used to exploit it. Memory leaks are well researched in browser and scripting languages attacks. They are also a huge topic and I may write a separate series on memory leaks abuse.
I hope this article gives you a good idea as to why you need ASLR, what ASLR related options in Windows Defender Exploit Guard do and how some of the exploits bypass it.
Part 1 - Windows Defender Exploit Guard for Pentesters - Validate Exception Chains (SEHOP)
Part 2 - Windows Defender Exploit Guard for Pentesters - ASLR
Part 3 - Windows Defender Exploit Guard for Pentesters - DEP
Part 4 - Windows Defender Exploit Guard for Pentesters - CFG
Part 5 - Windows Defender Exploit Guard for Pentesters - CIG & ACG