π SNMP Enumeration on Port 161: The Backdoor Many Forget to Secure
Port 161/UDP is home to SNMP (Simple Network Management Protocol), a protocol designed to monitor and manage network devices remotely. It sounds harmless, but when the configuration is weak (default community strings, read/write access without authentication) it becomes a goldmine of information β and sometimes a path to control β over the target system. In this article we’ll go over how to detect it, which configurations are dangerous, and how to thoroughly enumerate it with onesixtyone, snmpwalk/snmpbulkwalk and braa.
π‘ Step 1 β Detect the open port 161
Since SNMP runs over UDP, you need to tell Nmap explicitly:
nmap 10.129.2.28 -F -sU
nmap -sU --top-ports 1000 --min-rate 5000 -T4 10.129.144.145
Once the port is located, we can dig deeper with a specific version and script scan:
nmap -sUCV -P161 IP -On udpsCAN
Port 161 is the default port for network devices to which SNMP queries are sent during discovery and monitoring processes. SNMP (RFC 1157) was created to monitor network equipment, but it also allows managing configuration tasks and changing settings remotely.
π Step 2 β Understand the SNMP daemon configuration
The default configuration of the SNMP daemon lives in /etc/snmp/snmpd.conf and defines basic aspects such as IP addresses, ports, MIB, OID, authentication, and community strings. A typical example, filtering out comments and empty lines:
Jesuslopez@htb[/htb]$ cat /etc/snmp/snmpd.conf | grep -v "#" | sed -r '/^\s*$/d'
sysLocation Sitting on the Dock of the Bay
sysContact Me <[email protected]>
sysServices 72
master agentx
agentaddress 127.0.0.1,[::1]
view systemonly included .1.3.6.1.2.1.1
view systemonly included .1.3.6.1.2.1.25.1
rocommunity public default -V systemonly
rocommunity6 public default -V systemonly
rouser authPrivUser authpriv -V systemonly
All available settings for the SNMP daemon are documented on the manual page.
π« What went wrong? Dangerous configurations
Some administrators leave settings that overly widen SNMP access:
| Setting | Description |
|---|---|
rwuser noauth |
Provides access to the entire OID tree without authentication. |
rwcommunity <community string> <IPv4 address> |
Provides access to the entire OID tree regardless of where the requests were sent from. |
rwcommunity6 <community string> <IPv6 address> |
Equivalent to the previous one, but for IPv6. |
π‘ Step 3 β Find the community string with onesixtyone
To keep track of SNMP we have tools like snmpwalk, onesixtyone and braa. onesixtyone is used to brute-force community string names, since the administrator can name them arbitrarily, while snmpwalk is used to query the OIDs and their information. Since these strings can be linked to any source, identifying them can take time.
The first step is to figure out the community string with onesixtyone:
onesixtyone -c /usr/share/wordlists/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt 192.168.201.145
This may return something like:
10.10.10.92 [public] Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64
In this case we deduce that the community string is public. Note: there are more wordlists besides this one, so if there are no results it’s worth trying others.
π‘ Step 4 β Dump information with snmpwalk / snmpbulkwalk
With the community string in hand, it’s time to dump all the available information:
snmpwalk -c public -v2c 10.10.10.10 > snmpenum.rb
# to make it faster
snmpbulkwalk -c public -v2c 192.168.201.145 > snmpenum.rb
## also for machines
snmpwalk -v2c -c public 192.168.201.145 NET-SNMP-EXTEND-MIB::nsExtendObjects
snmpwalk -v2c -c security 192.168.111.110 > enum.rb
If in the output we see names instead of numbers on the left (for example SNMPv2-SMI) and lines like iso.3.6.1.2.1.1.9.1.2.8 = OID: iso.3.6.1.2.1.50, we’re looking at an OID: a node in a hierarchical namespace. A sequence of numbers uniquely identifies each node and allows it to be located in the tree β the longer the string, the more specific the information. Many nodes are nothing more than references to the ones below them. We can look up MIBs and their associated OIDs in the object identifier registry.
To see the names instead of the raw numbers, you can install:
apt install snmp-mibs-downloader
And then, in /etc/snmp/snmp.conf, comment out the line:
#mibs
If the dump is going too slow, snmpbulkwalk is the more efficient alternative, since it does the same thing but more powerfully.
π‘ Step 5 β Differentiate IPv4 and IPv6
It’s common for some ports/services to be exposed over IPv4 while different ones appear over IPv6. To detect this we use the ipAddressType parameter:
snmpwalk -c public -v2c 10.10.10.10 ipAddressType
Which may return something like:
IP-MIB::ipAddressType.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:b9:39:75" = INTEGER: unicast(1)
From that hexadecimal string we get the IPv6 address: dead:beef::250:56ff:feb9:3975.
π‘ Step 6 β Enumerate running processes
If on a website we’ve seen, for example, a python BaseHTTPServer process listening on port 33366, we can enumerate the system processes with the hrSWRunName parameter:
snmpwalk -c public -v2c 10.10.10.10 hrSWRunName
And filter by the process we’re interested in, in this case python:
snmpwalk -c public -v2c 10.10.10.10 hrSWRunName | grep "python"
or also .1.3.6.1.2.1.25.6.3.1.2 instead of hrSWRunName
This gives us the process identifier:
HOST-RESOURCES-MIB::hrSWRunName.718 = STRING: "python"
With that identifier (718 in this case) we can get more detail about the process, including the commands that were run:
snmpwalk -c public -v2c 10.10.10.10 hrSWRunTable | grep "718"
π‘ Step 7 β Playing with the OID tree
When snmpwalk traverses the system, by default it doesn’t start from the root: it starts from 2:
snmpwalk -c public -v2c 10.10.10.10 2
This is key when we don’t find anything relevant, since by forcing 1 we can discover much more interesting information that falls outside the default traversal:
snmpwalk -c public -v2c 10.10.10.10 1
π Note on patterns in community strings
Often, when certain community strings are linked to specific IP addresses, they’re named after the host’s hostname, and sometimes symbols are even added to make them harder to identify. However, on a large network with more than 100 servers managed via SNMP, those labels tend to follow some pattern, which allows us to use rules to guess them. To generate custom wordlists based on those patterns we can use the Crunch tool. Creating custom wordlists isn’t the focus of this article, but you can dig deeper into it in the Cracking Passwords With Hashcat module.
π‘ Step 8 β Enumerate with Braa as an alternative to snmpwalk
Besides snmpwalk, we can use braa once we have a community string:
Jesuslopez@htb[/htb]$ sudo apt install braa
Jesuslopez@htb[/htb]$ braa @:.1.3.6.* # Syntax
Jesuslopez@htb[/htb]$ braa [email protected]:.1.3.6.*
10.129.14.128:20ms:.1.3.6.1.2.1.1.1.0:Linux htb 5.11.0-34-generic #36~20.04.1-Ubuntu SMP Fri Aug 27 08:06:32 UTC 2021 x86_64
10.129.14.128:20ms:.1.3.6.1.2.1.1.2.0:.1.3.6.1.4.1.8072.3.2.10
10.129.14.128:20ms:.1.3.6.1.2.1.1.3.0:548
10.129.14.128:20ms:.1.3.6.1.2.1.1.4.0:[email protected]
10.129.14.128:20ms:.1.3.6.1.2.1.1.5.0:htb
10.129.14.128:20ms:.1.3.6.1.2.1.1.6.0:US
10.129.14.128:20ms:.1.3.6.1.2.1.1.7.0:78
...SNIP...
β Best practices / conclusion
SNMP is a powerful protocol for managing networks, but its default configuration (public community strings, read/write access without authentication) makes it a common source of information leakage during an audit: running processes, launched commands, both IPv4 and IPv6 network interfaces, and even credentials exposed in the OIDs. If you manage a device with SNMP enabled, avoid rwuser noauth and default community strings like public, restrict access by IP, and always review what information your OID tree exposes before an attacker does.
