Overview of Mitigations

From the perspective of an attacker, understanding countermeasures enables you to identify their limitations and develop appropriate exploitation techniques.

This section will give a brief overview of mitigation techniques implemented in the Windows Operating System. Details of specific bypass techniques will be presented in further sections where we need to bypass them.

Stack Canaries

The /GS flag, also known as the "Buffer Security Check," is a compiler flag used in Microsoft Visual C++ to enable a security mechanism called stack-based buffer overflow protection. This includes the generation of a stack canary, a random value placed on the stack before the return address.

The canary value is checked for integrity before a function returns, and if it has been modified (indicating a buffer overflow), the program will terminate, preventing potential exploits.

Typically the function prologue contains instructions to place a "canary" on the stack:

Assigning a canary
mov rax, qword ptr fs:0x28
mov qword ptr [rbp-0x8], rax

Line 1 takes the random canary from fs:0x28 and places it in the rax register. This is then placed on at a small offset from the base pointer on line 2.

The epilogue ontains the check:

Checking the canary
mov rcx, qword ptr [rbp-0x8]
xor rcx, qword ptr fs:0x28

Line 1 loads the value where the canary should be in to the rcx register, line 2 compares it to what the canary should be. A decision can now be made.

If a stack overflow occurs then the canary integrity will be compromised and an exception can be thrown.

Data Execution Prevention

Data Execution Prevention (DEP) was introduced in Windows XP Service Pack 2 (SP2) in 2004. The main purpose of DEP is to prevent malicious shellcode from executing in areas of computer memory that are intended for data storage.

DEP helps protect against certain types of attacks, such as buffer overflows and code injection techniques, by marking memory regions as non-executable unless explicitly designated for code execution.

DEP can be hardware-enforced or software-enforced on CPUs that do not support it. Hardware-enforced DEP sets the NX (Non-Executable) bit in the CPU. If the bit is set the CPU refuses to execute the code within the given memory region.

In Windows, there are four different global settings for DEP:

  1. OptIn mode - DEP is enabled only on system processes and custom defined applications.

  2. OptOut mode - DEP is enable for everything; except applications that are explicitly exempt.

  3. AlwaysOn mode - DEP is permanently enabled.

  4. AlwaysOff mode - DEP is permanently disabled.

Note: DEP is always enabled for system processes, including the Kernel.

Return-Oriented Programming (ROP) is a technique commonly used to bypass DEP in certain exploit scenarios. DEP aims to prevent the execution of arbitrary code from non-executable memory regions. However, ROP leverages existing code sequences, known as "gadgets," present in executable memory regions to chain together and form a sequence of instructions that can achieve a desired exploit outcome.

If we can change the marking in a memory region (to PAGE_EXECUTE_READ) it may be possible to execute code in otherwise non-executable areas. Common Win32 APIs to acheive this are VirtualProtect, VirtualAlloc, and WriteProcessMemory.

DEP is enabled in Microsoft compilers by default. By specifying /NXCOMPAT:NO, the developer instructs the compiler to diable DEP on the module.

Address Space Layout Randomization

Address Space Layout Randomization (ASLR) was first implemented in Windows Vista and Windows Server 2008 in 2006. ASLR was introduced to protect against memory-based attacks, such as buffer overflows. ASLR works by randomising the memory addresses at which system components, libraries, and executable code are loaded in a process's address space. By introducing this randomness, it becomes more challenging for an attacker to predict the memory layout, making it harder to exploit vulnerabilities reliably.

If we take a vanilla stack overflow, our objective is to find a jmp esp instruction in memory in order to redirect code flow to our shellcode on the stack. If the memory addresses change we cannot reliably locate the jmp esp instruction.

Memory leakage or information disclosure is considered one of the more effective techniques for bypassing ASLR. By exploiting vulnerabilities that allow us to leak memory addresses or gain insight into the memory layout, they can significantly undermine the effectiveness of ASLR.

A format string specifier attack is one such example of leaking memory.

Memory leakage can provide us with specific memory addresses or patterns, such as module base addresses or code pointers, which can aid in constructing reliable exploits. With this information, we can accurately target and overwrite the correct memory locations to execute malicious code or manipulate the program's execution flow.

ASLR is enabled in Microsoft compilers by default. By specifying /DYNAMICBASE:NO, the developer instructs the compiler to generate an executable without support for Dynamic Base and, therefore, without the randomisation of the module's base address during runtime. This is not recommended.

kASLR is the Kernel 'version' of ASLR and was introduced in Windows 8.1.

Control Flow Guard

CFG (Control Flow Guard): Initially introduced in Windows 8.1 and Windows Server 2012 R2 in 2014. It is designed to protect against memory corruption vulnerabilities, such as buffer overflows and function pointer hijacking, by safeguarding the control flow of a program.

When a program with CFG enabled encounters a function call or control transfer, CFG verifies the integrity of the target address by comparing it to a list of valid target addresses stored in a Control Flow Guard (CFG) function table. If the target address is not present in the table, an exception is raised, terminating the program and preventing the execution of unauthorised code.

It's important to note that CFG requires compatible hardware and software support, and is a compiler option that developers can enable during the compilation process to apply the CFG security feature to their applications.

When building an application, developers can specify the /guard:cf compiler flag. CFG is not enabled by default.

One technique used to bypass CFG is to start a ROP chain from a DLL not compiled with CFG.

kCFG, also known as Kernel Control Flow Guard, is a security feature introduced by Microsoft in Windows 10 and Windows Server 2016. It is an extension of Control Flow Guard (CFG) specifically designed for kernel-mode code execution.

Arbitrary Code Guard

ACG (Arbitrary Code Guard) was Implemented in Windows 10 (version 1703) released in 2017. ACG was introduced by Microsoft as part of the Windows operating system. It is designed to mitigate certain types of code injection attacks, such as DLL injection. ACG works by enforcing strict control over the execution of code, ensuring that only trusted code from legitimate modules can be executed.

It does this by preventing modules being marked as executable. When an application attempts to allocate memory in a process and it attempts to add the execution flag the memory allocation fails and throws an error.

It aims to prevent the execution of arbitrary code injected into a process. ACG primarily works in user-mode so it may be possible for us to bypass it using kernel exploitation.

Microsoft also advises that it is incompatible with Just-in-Time (JIT) compiler, like those in Web Browsers, this is because JavaScript is compiled in to native code on the fly and relies upon the creation of executable memory allocations.

Control-flow Enforcement Technology - Windows Defender Exploit Guard

Work in progress

Supervisor Mode Execution Prevention

Supervisor Mode Execution Protection (SMEP) was introduced in the x86 architecture by Intel. It was first implemented in the Intel Ivy Bridge microarchitecture, which was released in 2012.

When SMEP is enabled, attempts to execute instructions from user mode memory regions while in kernel mode will trigger a hardware exception, preventing the unauthorised execution of user mode code within the privileged kernel context.

SMEP is implemented by setting a bit in a CPU control register, specifically the 20th bit of the cr4 control register.

SMEP is not enabled by default on Windows operating systems before Windows 8, Windows 7 was released before SMEP was a security feature. To fully support SMEP, you need a compatible processor and an operating system that supports SMEP.

A common technique for bypassing SMEP is to clear the cr4 register bit using ROP.

Supervisor Mode Access Prevention

Work in progress

Kernel Patch Protection

Work in progress

Hypervisor-Enforced Code Integrity

Hypervisor-Enforced Code Integrity (HVCI) was introduced with the release of Windows 10 (version 1607) released in 2016. HVCI is a security feature that helps protect against code injection attacks by enforcing code integrity policies at the hypervisor level.

Meltdown KVA Shadow Mitigation

Work in progress

Secure Coding Practices

Work in progress

Conclusion

This section was a basic high-level introduction of the exploit mitigations in the Windows Operating system. Future sections will discuss techniques and details on how it may be possible to bypass these mitigations.

Last updated