❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdayTenable TechBlog - Medium

Another Path to Exploiting CVE-2024-1212 in Progress Kemp LoadMaster

By: Ben Smith
2 April 2024 at 17:18

Intro

Rhino Labs discovered a pre-authentication command injection vulnerability in the Progress Kemp LoadMaster. LoadMaster is a load balancer product that comes in many different flavors and even has a free version. The flaw exists in the LoadMaster API. When an API request is received to either the β€˜/access’ or β€˜/accessv2’ endpoint, the embedded min-httpd server calls a script which in turn calls the access binary with the HTTP request info. The vulnerability works even when the API is disabled.

Rhino Labs showed that attacker controlled data is read by the access binary when sending an enableapi command to the /access endpoint. The attacker controlled data exists as the β€˜username’ in the Authorization header. The username value is put into the REMOTE_USER environment variable. The value stored in REMOTE_USER is retrieved by the access binary and ends up as part of a string passed to a system() call. The system call executes the validuser binary and a carefully crafted payload allows us to inject commands into the bashΒ shell.

GET request showing the resulting bash command. The response shows a bash syntax error that indicates the command line that was executed
GET request showing the resulting bashΒ command

We also found that the REMOTE_PASS environment variable is exploitable in the same way here via the Authorization header.

This command execution is possible via any API command if the API is enabled. As Rhino Labs points out, When sending a GET request to the access API indicating the enableapi command, the access binary skips checking whether the API is enabled first or not, and the Authorization header is checked rightΒ away.

APIv2

While investigating this vulnerability, I noticed that LoadMaster has two APIs, the v1 API indicated above, and a v2 API that functions via the /accessv2 endpoint and JSON data. The access binary still processes these requests, but a slightly different path is followed. The logic of the main function is largely duplicated as a new function and called if the APIv2 is requested. That function then performs the same checks as above, with the slight exception that it will decode the API and pass the values of the apiuser and apipass keys to the same system call. So, we have another path to the same exposure:

This is the second exploitable path via the APIv2. A POST request is sent to the LoadMaster APIv2, and a response indicates the output of the command we injected.
POST request to the LoadMaster APIv2, also exploitable

While we can still control the password variable, it’s no longer exploitable here. Somewhere along the path the password string gets converted to base64 before being passed through the system() call, nullifying any injectedΒ quotes.

POST request to the APIv2 showing that apipass is base64 encoded, effectively removing any singleΒ quotes

We can see below that the verify_perms function calls validu() with REMOTE_USER and REMOTE_PASS data in the APIv1 implementation; in the API v2 implementation the apiuser and apipass data is passed to validu() from the APIv2Β JSON.

Screenshot of the Ghidra decompilation showing the two different paths for API and APIv2
Ghidra decompilation showing API and APIv2Β paths

Patch

The patch solves these flaws quite simply by examining the username and password strings in the Authorization header for single quotes. If they contain a single quote, the patched function will truncate them just before the first single quote. Decompiling the patched access binary with Ghidra, we can seeΒ this:

Ghidra decompilation of the patched validu function. It shows the new function call and then the β€˜validuser’ string being concatenated and then the system() call after.
Ghidra decompilation of the patched validuΒ function
Code from Ghidra decompilation of the function added by the patch. The function loops over each character of the input string, and if it’s a single quote, it is replaced with a null terminator.
Ghidra decompilation of the function in the patch that null terminates strings at the first singleΒ quote

Here we see the addition of the new function call for both username and password. The function loops over each character in the input string and if it is a single quote, it’s changed to a \0, null terminating theΒ string.

Another Way to Test: Emulation

Even though we’ve got x86 linux binaries, we can’t run them natively on another linux machine due to potential library and ABI issues. Regardless, we can extract the filesystem and use a chroot and qemu to emulate the environment. Once we’ve extracted the filesystem, we can mount the ext2 filesystem ourselves:

sudo mount -t ext2 -o loop,exec unpatched.ext2 mnt/

Now we can explore the filesystem and execute binaries.

This provides us with a quick offline method to test our assumptions around injection. For instance, as we mentioned, the access binary is exploitable via the REMOTE_USER parameter:

Screenshot of a bash shell showing how we can emulate the access binary to test various different command injections.
Emulating binaries locally to easily test injection assumptions

First, we’ve copied the qemu-x86_64-static binary into our mounted filesystem. We’re using that with the -E flag to pass in a bunch of environment variables found via reversing access, one of which is the injectable REMOTE_USER. The whole thing is wrapped in chroot so that symbolic links and relative paths work correctly. We give /bin/access several flags which we’ve lifted straight from the CGI script that calls theΒ binary

exec /bin/${0/*\//} -C $CLUST -F $FIPS -H $HW_VERSION

and from checking the ps debugging feature in the LoadMaster UI. Pro tip: check ps while running another longer running debug command like top or tcpdump in order to see betterΒ results.

root 13333 0.0 0.0 6736 1640 ? S 15:54 0:00 /sbin/httpd -port 8080 -address 127.0.0.1
root 16733 0.0 0.0 6736 112 ? S 15:59 0:00 /sbin/httpd -port 8080 -address 127.0.0.1
bal 16734 0.0 0.0 12064 2192 ? S 15:59 0:00 /bin/access -C 0 -F 0 -H 3
bal 16741 0.2 0.0 11452 2192 ? S 15:59 0:00 /usr/bin/top -d1 -n10 -b -o%CPU
bal 16845 0.0 0.0 7140 1828 ? R 15:59 0:00 ps auxwww

While this doesn’t provide us the complete method to exploit externally, it is a nice quick method to try out different injection strings and test assumptions. We can also pass a -g <port> parameter to qemu and then attach gdb to the process to get even closer to what’s happening.

Conclusion

This was a really cool find by Rhino Labs. Here I add one additional exploitation path and some additional ways to test for this vulnerability.

Tenable’s got you covered and can detect this vulnerability as part of your VM program with Tenable VM, Tenable SC, and Tenable Nessus. The direct check plugin for this vulnerability can be found at CVE-2024-1212. The plugin tests test both APIv1 and APIv2 paths for this command execution exposure.

Resources

https://rhinosecuritylabs.com/research/cve-2024-1212unauthenticated-command-injection-in-progress-kemp-loadmaster/

https://support.kemptechnologies.com/hc/en-us/articles/24325072850573-Release-Notice-LMOS-7-2-59-2-7-2-54-8-7-2-48-10-CVE-2024-1212

https://support.kemptechnologies.com/hc/en-us/articles/23878931058445-LoadMaster-Security-Vulnerability-CVE-2024-1212


Another Path to Exploiting CVE-2024-1212 in Progress Kemp LoadMaster was originally published in Tenable TechBlog on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌
❌