📜 ⬆️ ⬇️

Windows 8 - let it be SMEP!


With the advent of a new generation of Intel processors based on the Ivy Bridge architecture, a new hardware security tool was introduced. It is called Intel SMEP. Like the NX bit, which prevents execution of code on a memory page, it adds a headache when exploiting kernel mode vulnerabilities.

In turn, Microsoft implemented SMEP support in Windows 8, thus making this OS even safer. However, the first “head on” implementation of SMEP support turned out with a slight flaw, thanks to which the attacker still has the possibility of exploiting vulnerabilities relatively painless for him.

What is SMEP?


SMEP stands for “Supervisor Mode Execution Prevention” - preventing code execution in supervisor mode. The supervisor mode is the preferred mode of the processor in which the Windows 8 kernel is executed. In terms of the OS, this mode is also called the kernel mode. The opposite is the user mode — in this mode, user applications are executed.

OS protection is based on the fact that user applications cannot perform privileged operations, for example, access I / O ports, control registers of the processor, etc. In addition, the memory used in kernel mode is protected from access from user mode. A user application can neither read, nor change, nor execute code in the kernel memory directly. Interaction with the OS kernel occurs indirectly through the system call interface.
')
Privileged mode in turn has no restrictions, if not SMEP. If it is enabled, any attempt to execute code that resides in the memory of the user application will result in a page fault (page fault). In particular, in the error handler of pages on Windows 8, this situation will cause a bugcheck.
Simply put, if any driver or system kernel module tries to execute code located in the memory of a user application, it will all end with a blue screen of death with a sad emoticon.

What's the point?


Kernel-mode vulnerabilities are the most “tasty” for an attacker, because with successful exploitation he gets full control over the target system. The point is that during the exploitation of kernel mode vulnerabilities, an attacker, as a rule, allocates user mode memory to store the shellcode.

“But in kernel mode it is now impossible to execute code from user memory pages! And where is the shellcode stored now? And what is the point of an attack without its own shell-code? Or maybe not then attack? ”

With the expectation of a similar train of thought of the attacker, this technology was created. It is able to protect the end user from a whole class of attacks, if you bring its implementation to the mind and cover the "rear" with other defense mechanisms.



The first pancake is lumpy


Let's meditate. Shell user code cannot be stored in user space. It means that it should be located in the kernel’s memory (the choice is not great - just two modes), the contents of this memory section should be controlled by us (you can’t write directly from user mode), and you should be able to find out the address of this memory section from user mode and read from user mode directly). What can be used to deliver shellcode to the kernel?

The most obvious solution is to use Windows objects. Those with which applications work through descriptors (handle). These are various timers, events, mutexes, I / O completion ports, graphical objects, etc. The body of such an object is located in the memory of the kernel, and the contents can be changed from the user mode, and we can find out what address in the kernel space they are located!

For example, when we open a file with the CreateFile () function, we get a handle to the open file. If an application needs to read a couple of bytes of this file into a buffer, then we call the ReadFile () function, which with the help of a system call transfers control to the OS kernel, where it finds the required file object using the descriptor table. In this case, the object is of type _FILE_OBJECT, and the variable field in it is the file name. Those. theoretically, you can create a file called "\ 0xBAADC0DE", which will contain our shellcode. Then we exploit some kind of kernel mode vulnerability and transfer control to our shellcode.

0: kd> dt nt! _FILE_OBJECT
+ 0x000 Type: Int2B
+ 0x002 Size: Int2B
...
+ 0x050 Flags: Uint4B
+ 0x058 FileName: _UNICODE_STRING
+ 0x068 CurrentByteOffset: _LARGE_INTEGER
...
+ 0x0c0 IrpList: _LIST_ENTRY
+ 0x0d0 FileObjectExtension: Ptr64 Void

Success? Not quite yet. The fact is that SMEP on Windows 8 is complemented by another protection mechanism. Despite the fact that the code is located on the kernel mode page, this page has a mark (NX bit) indicating that it is non-executable, i.e. On this page can not be executed code! It turns out that Windows objects are protected from execution, therefore, are also not suitable for storing shell code. This statement is true for the x64 version of Windows 8. However, in the x86 version, the bodies of graphic objects are located in executable memory!

The palette was the most suitable object for delivering the shellcode. It is created using the CreatePalette () function and the LOGPALETTE structure, the contents of which is filled with the shell code. Still, how to validate colors in a palette? Indeed, in our palette will be exactly the colors that we want! And we want a lot of NOP bytes (0x90), and a lot of shellcode bytes. This is the “evil” palette ...



Total we have a SMEP bypass scheme on Windows 8 x86:
1. Create the “evil” LOGPALETTE structure, filling it with a shell code.
2. Create a palette through CreatePalette ().
3. Find the address of the palette object in the kernel through a shared GDI table.
4. We transfer control by some offset from the palette object.
five. ???????
6. PROFIT !!!

And what to do with x64?


Want to bypass SMEP on Windows 8 x64? I have them! Perhaps the method is not so interesting, but working. SMEP on x64 is managed using return-oriented programming (ROP). In short, ROP uses portions of code from other modules already present in memory. Thus, it is not necessary to forward your shellcode to the kernel.

Of course, the ability of an attacker to compose a payload in this case is severely limited. But all that an attacker needs is to disable SMEP, and for this, the “ntoskrnl” module has “presents” in the form of functions HvlEndSystemInterrupt () and KiConfigureDynamicProcessor (). The last bytes of these functions allow you to disable SMEP on a given processor.

HvlEndSystemInterrupt(): … pop rax pop rcx retn 


 KiConfigureDynamicProcessor(): … mov cr4, rax add rsp, 28h retn 


 // ROP chain to refresh cr4 value // vTrash vROPChain DWORD_PTR dwRopStack[7 + 10] = {0}; // HvlEndSystemInterrupt gadget dwRopStack[7 + 0] = dwKernelBase + HvlGadgetOffset; // New CR4 value dwRopStack[7 + 1] = 0x00000000000506F8; // KiConfigureDynamicProcessor dwRopStack[7 + 3] = dwKernelBase + Cr4GadgetOffset; // Out address (shellcode) dwRopStack[7 + 9] = (DWORD_PTR)pTestBuf; 




Down with restrictions


After SMEP is disabled, the attacker is able to execute code from the user buffer, i.e. There are no more restrictions on the size of the shellcode. You can use the kernel vulnerability, which was used to disable SMEP, to transfer already to the "evil" shellcode.

Conclusion


Of course, both methods are not universal. Each vulnerability has its own characteristics of exploitation. In some cases, bypass schemes will have to finish, while in others they are generally not applicable.

It is also important to understand that this is not an exploitable vulnerability in itself. This is just a way to bypass one of the protection mechanisms, and it can only be used in conjunction with some other exploitable vulnerability.

PS SMEP is disabled by 13 bytes of code. For details, please follow the links below.
How to beat SMEP on Windows 8 x86
How to beat SMEP on Windows 8 x64

Authors: Artyom Shishkin and Ilya Smith

Source: https://habr.com/ru/post/152365/


All Articles