CVE-2022-3525: Deserialization of Untrusted Data (CWE-502)
value: Deserialization of Untrusted Data in GitHub repository librenms/librenms prior to 22.10.0.
CWE description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
CVSS v3 base score: 8.8
Published: 2022-11-20T05:15Z
Repository: https://github.com/librenms/librenms
Language: PHP
Files changed: doc/Extensions/Applications.md, includes/polling/applications/memcached.inc.php, includes/polling/unix-agent.inc.php, misc/notifications.rss
Commit date: 2022-10-16 11:15:17 -0500
Commit message: Fix memcached unserialize vulnerability (#14459)

Allows code injection, so remove it entirely.
This requires a memcached application script to restore functionality.

https://github.com/librenms/librenms-agent/pull/428
Diff: diff --git a/doc/Extensions/Applications.md b/doc/Extensions/Applications.md
index a0f1b3a38b2..d380ada2535 100644
--- a/doc/Extensions/Applications.md
+++ b/doc/Extensions/Applications.md
@@ -907,14 +907,14 @@ pass .1.3.6.1.4.1.3582 /usr/sbin/lsi_mrdsnmpmain
 ## Memcached
 
 ### SNMP Extend
 
 1. Copy the [memcached
-   script](https://github.com/librenms/librenms-agent/blob/master/agent-local/memcached)
+   script](https://github.com/librenms/librenms-agent/blob/master/snmp/memcached)
    to `/etc/snmp/` on your remote server.
 ```
-wget https://raw.githubusercontent.com/librenms/librenms-agent/master/agent-local/memcached -O /etc/snmp/memcached
+wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/memcached -O /etc/snmp/memcached
 ```
 
 2. Make the script executable:
 ```
 chmod +x /etc/snmp/memcached
diff --git a/includes/polling/applications/memcached.inc.php b/includes/polling/applications/memcached.inc.php
index 7bf223122f3..263e05c7498 100644
--- a/includes/polling/applications/memcached.inc.php
+++ b/includes/polling/applications/memcached.inc.php
@@ -1,22 +1,27 @@
 <?php
 
+use LibreNMS\Exceptions\JsonAppException;
 use LibreNMS\RRD\RrdDefinition;
 
 $name = 'memcached';
 
 if (! empty($agent_data['app']['memcached'])) {
-    $data = $agent_data['app']['memcached'][$app['app_instance']];
+    $data = $agent_data['app']['memcached'];
 } else {
-    $oid = '.1.3.6.1.4.1.8072.1.3.2.3.1.2.9.109.101.109.99.97.99.104.101.100';
-    $result = snmp_get($device, $oid, '-Oqv');
-    $data = trim($result, '"');
-    $data = unserialize(stripslashes(str_replace("<<<app-memcached>>>\n", '', $data)));
-    $data = reset($data);
-}
+    try {
+        $data = json_app_get($device, $name, '1.1')['data'];
+        $data = $data['data'][$app->app_instance] ?? reset($data['data']);
+    } catch (JsonAppException $e) {
+        echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL;
+        update_application($app, $e->getCode() . ':' . $e->getMessage(), []); // Set empty metrics and error message
 
-echo ' memcached(' . $app['app_instance'] . ')';
+        return;
+    }
+}
+echo ' memcached(' . $app->app_instance . ')';
+$data = $data[$app->app_instance] ?? reset($data);  // specified instance or just the first one
 
 $rrd_name = ['app', $name, $app->app_id];
 $rrd_def = RrdDefinition::make()
     ->addDataset('uptime', 'GAUGE', 0, 125000000000)
     ->addDataset('threads', 'GAUGE', 0, 125000000000)
diff --git a/includes/polling/unix-agent.inc.php b/includes/polling/unix-agent.inc.php
index 6f88ffddb2a..94d8c4cc1f7 100644
--- a/includes/polling/unix-agent.inc.php
+++ b/includes/polling/unix-agent.inc.php
@@ -157,11 +157,11 @@ if ($device['os_group'] == 'unix' || $device['os'] == 'windows') {
             }
         }
 
         // memcached
         if (! empty($agent_data['app']['memcached'])) {
-            $agent_data['app']['memcached'] = unserialize($agent_data['app']['memcached']);
+            $agent_data['app']['memcached'] = json_decode($agent_data['app']['memcached'], true);
             foreach ($agent_data['app']['memcached'] as $memcached_host => $memcached_data) {
                 if (dbFetchCell('SELECT COUNT(*) FROM `applications` WHERE `device_id` = ? AND `app_type` = ? AND `app_instance` = ?', [$device['device_id'], 'memcached', $memcached_host]) == '0') {
                     echo "Found new application 'Memcached' $memcached_host\n";
                     dbInsert(['device_id' => $device['device_id'], 'app_type' => 'memcached', 'app_status' => '', 'app_instance' => $memcached_host], 'applications');
                 }
diff --git a/misc/notifications.rss b/misc/notifications.rss
index 788235d813e..bb6aeb78d20 100644
--- a/misc/notifications.rss
+++ b/misc/notifications.rss
@@ -86,7 +86,12 @@
   <item>
     <title>ADSL discovery and polling moved to a new module</title>
     <description>Adsl statistics are now discovered and polled in a new module. Vdsl stats were also added. `lnms config:set enable_ports_adsl true`is not supported anymore. See https://github.com/librenms/librenms/pull/14207 for more information.</description>
     <pubDate>Wed, 7 Sept 2022 18:00:00 +0000</pubDate>
   </item>
+  <item>
+    <title>Memcached application compatibility break</title>
+    <description>Due to a security vulnerability, you must upgrade your memcached application scripts to the latest version. (1.1)</description>
+    <pubDate>Fri, 10 Oct 2022 18:00:00 +0000</pubDate>
+  </item>
 </channel>
 </rss>

Vulnerable code:    script](https://github.com/librenms/librenms-agent/blob/master/agent-local/memcached)
wget https://raw.githubusercontent.com/librenms/librenms-agent/master/agent-local/memcached -O /etc/snmp/memcached
    $data = $agent_data['app']['memcached'][$app['app_instance']];
    $oid = '.1.3.6.1.4.1.8072.1.3.2.3.1.2.9.109.101.109.99.97.99.104.101.100';
    $result = snmp_get($device, $oid, '-Oqv');
    $data = trim($result, '"');
    $data = unserialize(stripslashes(str_replace("<<<app-memcached>>>\n", '', $data)));
    $data = reset($data);
}
echo ' memcached(' . $app['app_instance'] . ')';
            $agent_data['app']['memcached'] = unserialize($agent_data['app']['memcached']);
Fixed code:    script](https://github.com/librenms/librenms-agent/blob/master/snmp/memcached)
wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/memcached -O /etc/snmp/memcached
use LibreNMS\Exceptions\JsonAppException;
    $data = $agent_data['app']['memcached'];
    try {
        $data = json_app_get($device, $name, '1.1')['data'];
        $data = $data['data'][$app->app_instance] ?? reset($data['data']);
    } catch (JsonAppException $e) {
        echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL;
        update_application($app, $e->getCode() . ':' . $e->getMessage(), []); // Set empty metrics and error message
        return;
    }
}
echo ' memcached(' . $app->app_instance . ')';
$data = $data[$app->app_instance] ?? reset($data);  // specified instance or just the first one
            $agent_data['app']['memcached'] = json_decode($agent_data['app']['memcached'], true);
  <item>
    <title>Memcached application compatibility break</title>
    <description>Due to a security vulnerability, you must upgrade your memcached application scripts to the latest version. (1.1)</description>
    <pubDate>Fri, 10 Oct 2022 18:00:00 +0000</pubDate>
  </item>