It is said that an ounce of prevention is worth a pound of cure. This is often true in practice when it comes to securing operating systems against the exploitation of security vulnerabilities.
For example from Windows 8 onwards, Microsoft denies programs the ability to allocate and/or map the “NULL page” (memory residing at virtual address 0x00000000 in the address space). By doing this, Microsoft successfully mitigates the direct exploitation of a whole class of vulnerabilities called “NULL pointer dereference” vulnerabilities. Regardless of where a flaw might be which may result in such a vulnerability, this mitigation reduces the possible impact of its exploitation to a Denial of Service (DoS) condition at best from what may have been a potential arbitrary code execution situation. As of Windows 7 Service Pack 1 (SP1) Microsoft has implemented this mitigation in Windows 7 as well. It is reassuring to see Microsoft backporting security mitigation technology originally implemented in Windows 8/8.1, to Windows 7 as well.
Vulnerabilities that Allow for Diverting the Kernel Execution Flow
Now let’s look at vulnerabilities that allow for diverting the kernel execution flow. Prior to Windows 8, the exploitation of such a flaw would allow the attacker to execute code of his choosing in the context of the kernel (under the ring0 CPU privilege level), resulting in privilege escalation to one of the highest levels (only below the level of a virtualization technology hypervisor or a Systems Management Mode handler). Such vulnerabilities would give attackers access to virtually all parts of the operating system because prior to Windows 8, the kernel has access to virtually everything.
There was little operating system developers could do to address this problem until Intel introduced the Supervisor Mode Execution Prevention (SMEP) feature in its Ivy Bridge and later processors.
SMEP is an augmentation to the x86/x64 CPU page level protection which uses the existing User/Supervisor flag (U/S) in the page table entries. This page table entry flag is used to mark if a memory page is for User access or Privileged access. When SMEP is enabled by setting the bit 20 of the CR4 control register (CR4.SMEP), if code running with Supervisor privileges (CPU privilege level, CPL <3), such as kernel mode threads, when it tries to access a page that is marked as a User a page, then a page fault is raised by the CPU. The Windows 8/8.1 implementation of this mitigation technology halts the system with a blue screen.
As the following excerpt from the Intel CPU manuals show, the SMEP flag implementation on the CPU is as follows::
For Supervisor level instruction fetching:
– For 32-bit paging or if IA32_EFER.NXE = 0, access rights depend on the value of CR4.SMEP:
If CR4.SMEP = 0, instructions may be fetched from any linear address with a valid translation.
If CR4.SMEP = 1, instructions may be fetched from any linear address with a valid translation for which the U/S flag (bit 2) is 0 in at least one of the paging-structure entries controlling the translation.
– For PAE paging or IA-32e paging with IA32_EFER.NXE = 1, access rights depend on the value of CR4.SMEP:
If CR4.SMEP = 0, instructions may be fetched from any linear address with a valid translation for which the XD flag (bit 63) is 0 in every paging-structure entry controlling the translation.
If CR4.SMEP = 1, instructions may be fetched from any linear address with a valid translation for which (1) the U/S flag is 0 in at least one of the paging-structure entries controlling the translation; and (2) the XD flag is 0 in every paging-structure entry controlling the translation.
For User level instruction fetching:
– For 32-bit paging or if IA32_EFER.NXE = 0, instructions may be fetched from any linear address with a valid translation for which the U/S flag is 1 in every paging-structure entry controlling the translation.
– For PAE paging or IA-32e paging with IA32_EFER.NXE = 1, instructions may be fetched from any linear address with a valid translation for which the U/S flag is 1 and the XD flag is 0 in every paging-structure entry controlling the translation.
A Windows 8/8.1 system halt due to an SMEP violation looks like the above picture. The BugCheck code supplied is ATTEMPTED_EXECUTE_OF_NO_EXECUTE_MEMORY (0x000000FC). Microsoft describes this BugCheck code here.
So is there any way to subvert the SMEP protection implementation in Windows 8/8.1?
Well, predictable areas of memory, marked Supervisor, where the content can however be user controlled, depending on the predictability and the degree of user control, can be used to subvert SMEP protection implementation. How would this work? A simple scenario is as follows.
– A user mode program indirectly places executable instruction code (shellcode) in kernel memory, marked Supervisor. A typical case where this would be possible is as parameters/data passed from user mode to a kernel service. One of the articles linked to below describes using a set of kernel objects introduced in Windows 7 called Reserve Objects in this fashion.
– The user mode program triggers a vulnerability which diverts the kernel execution flow to the above predictable address in kernel memory space, where the user has already placed the shellcode. This allows the user crafted executable instruction code to execute in the context of the kernel (in ring0).
Since the original introduction of the SMEP protection in Windows 8, Microsoft has addressed the issue of such memory areas, for example by marking them non-executable as well, thus making the SMEP protection progressively more robust. That said, it is still possible that such kernel memory areas which could be leveraged to bypass the SMEP protection implementation in Windows 8/8.1 still exists.
Can Return Oriented Programming (ROP) techniques be used to subvert the SMEP protections?
Yes, it is possible. However, with Address Space Loader Randomization (ASLR) in place, a kernel information disclosure vulnerability is probably required. In addition to that, an application sandbox may prevent the reading of the running kernel image file off disk, thus preventing reasonably locating the required ROP gadgets at runtime.
So while it is still possible to leverage ROP in the kernel space when exploiting vulnerabilities that allow diverting kernel execution flow, by implementing mitigation technology that uses the SMEP CPU feature present in Intel Ivy Bridge and newer CPUs by Windows 8/8.1 operatings systems, in conjunction with other mitigation technologies such as ASLR and DEP (Data Execution Prevention), there is no doubt it makes the exploitation of vulnerabilities that allows taking over kernel execution flow a much harder task.
See also:
“SMEP: What is it, and how to beat it on Windows”
“SMEP: What is It, and How to Beat It on Linux”