Remote code execution in LDAP Account manager through CVE-2024-23333 (Exploiting web applications Part I)

During red teaming engagements, the first step is to gain a foothold in the client’s network. That might happen through a phishing attempt, malicious payloads, physical access to the client’s site or an assumed breach. But what happens once you got access to the network? With the goal to overtake the company by gaining domain dominance in mind, you need to move step-by-step. So, during one engagement, we were at this point. We had gained initial access, could poke around in the client’s network but did not yet have any domain credentials which we could abuse for our attack. We were carefully looking around in the customer’s network, trying to get ourselves onto a server, in the hope of it being domain-joined and being able to extract valid domain credentials. As we were poking around, we stumbled across a webserver that had an application called LDAP Account Manager (LAM) running.

This blog post describes the path of identifying, understanding and exploiting a remote code execution (RCE) vulnerability in LAM.

Identify a potential vulnerability

LAM is an open-source application that helps with managing LDAP entries. At this point, there were no publicly known vulnerabilities that one could exploit for gaining remote code execution on the server. So we did our own research.

On the main screen of LAM’s landing page, there is menu item called “configuration”, which sounded interesting.

LAM

It seems to allow the modification of various settings.

LAM

However, a master password is required.

LAM

A quick Google search revealed that the default master password is lam, as the vendor describes in the documentation.

Success! No one changed the default password. We see this often in red teaming engagements—that default passwords work for all kinds of applications: printers, web applications, settings, etc. A strong-willed attacker will use the slightest indication of success to penetrate a system. Therefore, everything will be exploited. We strongly recommend that you change your default login credentials to avoid giving attackers a target.

LAM

With access to the configuration panel, we looked through the various options and stumbled across the logging feature. Log data can be saved to an arbitrary filepath, which releases the smell of log poisoning in the air - let’s give it a try.

Our idea for gaining remote code execution (RCE) was the following:

  1. Create a log file within the web root, using a .php extension so that the web server directs it to the PHP interpreter.
  2. Identify an input value that can be controlled and saved in this log file to inject PHP code.
  3. Access the log file via the web server to execute remote code (RCE).

Source code analysis

When exploiting vulnerabilities, it is a good idea to have a look at and to understand the source code (if accessible). It can only make it easier to perform the exploitation, and it helps to see if there are any constraints or side-effects from the exploitation. Also, when studying the source code, you may find even more vulnerabilities or bugs that could be chained together.

So, we have a look in the source code in the file templates/config/mainmanage.php, since this is what we see in our browser’s address bar.

if (isset($_POST['logFile']) && ($_POST['logFile'] != "") &&
        preg_match("/^[a-z0-9\\/\\\\:\\._-]+$/i", $_POST['logFile'])) {
    $cfg->logDestination = $_POST['logFile'];
} else {
    $errors[] = _("The log file is empty or contains invalid characters!
                    Valid characters are: a-z, A-Z, 0-9, /, \\, ., :, _ and -.");
}

As we can see, there is no checking for path traversal, file extensions sanitization or any other form of sanitization. This is promising for our exploitation.

We further saw in the same file that the settings are saved via $cfg->save();.

// save settings
if (isset($_POST['submit'])) {
    $cfg->save();
    if (sizeof($errors) == 0) {
        metaRefresh('../login.php?confMainSavedOk=1');
        exit();
    }
}

$cfg is an object of class LAMConfig defined in lib/config.inc. The save() function also does not do any further sanitization and thus saves it to the file directly.

Now we need to know an absolute path on the webserver, in order to deliberately store the malicious log file. We could not find an information disclosure in LAM, but as luck was on our side, there is a file on the server in old/phpinfo.php. We found this directory using ffuf. As the name suggests, the phpinfo.php calls phpinfo() and thus prints the absolute filepath on the server, among a bunch of other information. With this information in hand, we configured LAM to write the config file to /var/www/html/old/demo.php.

Note: A correct LAM installation, as described in offical sources, does not expose any writable paths. Thus, the exploitation relies on either a misconfigured installation or “third-party” writable file systems paths.

Finding a poisonable log entry

Now we need to find a user controllable value that is written to the log file. First, we need to find how log entries are created. So, we grep through the code with ack and look for the already known config value logDestination.

$ ack logDestination

[..]

lib/security.inc
267:    if (($cfg->logDestination == 'NONE')
276:    if ($cfg->logDestination == 'SYSLOG') {
280:    elseif (strpos($cfg->logDestination, 'REMOTE') === 0) {
285:            @touch($cfg->logDestination);
286:            if (is_writable($cfg->logDestination)) {
287:                    $file = fopen($cfg->logDestination, 'a');
300:                    StatusMessage('ERROR', 'Unable to write to log file!', $cfg->logDestination);
791:    $remoteParts = explode(':', $cfgMain->logDestination);

[..]

Among other hits, lib/security.inc seems to be the correct location. Looking in the actual file reveals the function logNewMessage, which is the next keyword that we grep ack for.

ack logNewMessage

templates/login.php
109:    logNewMessage(LOG_DEBUG, "Change server profile to " . $_GET['useProfile']);
186:    logNewMessage(LOG_DEBUG, "Display login page");
508:                    logNewMessage(LOG_DEBUG, "Empty password for login");
567:                            logNewMessage(LOG_ERR, 'User ' . $username . ' (' . $clientSource . ') 
                                    failed to log in. ' . $searchError . '');
590:    logNewMessage(LOG_NOTICE, 'User ' . $username . ' (' . $clientSource . ') successfully logged in.');

Nice! A failed login saves the username? That looks good! Let’s try!

First, we verify that the log file is accessible by opening the page: LAM

Success! So let us poison the username with PHP source code :). We use Burp to intercept the login request.

LAM

We send it to the repeater and insert a PHP payload that runs the id command.

LAM

Let us see how the log file now looks like:

LAM

Oh yes, the PHP code got interpreted and the id command executed on the server. The result is rendered in the log file! We got RCE on the server and can continue compromising the customer!

Conclusion

Default credentials are always dangerous, even if only simple settings can be configured. Also, it is not a good idea to expose old/test/dev files on your servers; simple information such as a filepath can be useful for an attacker to successfully breach your system. Just because a project is 20 years old doesn’t mean that it doesn’t contain security vulnerabilities or that they have all been discovered. Hence, researching for vulnerabilities can end in success when attempting to gain access to systems.

Vulnerability Details

This vulnerability has been assigned CVE-2024-23333 via GHSA-fm9w-7m7v-wxqv with a CVSS 3 score of 7.9.

The issue has been fixed in LAM version 8.7, affected versions are < 8.7.

Additionally, vulnerability CVE-2024-52792 has been discovered, that could bypass the security fix.

Timeline

  • 2024-01-11: Vulnerability CVE-2024-23333 reported to the vendor.
  • 2024-03-16: Vendor has reported that the vulnerability has been fixed.
  • 2024-11-15: Vulnerability CVE-2024-52792 reported to the vendor.
  • 2024-11-19: Vendor has reported that the vulnerability has been fixed.
  • 2025-01-14: This blog post was published.