In Python you can use a third-party library called PySNMP for interfacing with the snmp daemon.
You can install the PySNMP module by using the following pip command:
$ pip install pysnmp
In this screenshot we can see the dependencies we need to install for this module:
We can see that the installation of PySNMP requires the pyasn1 package. ASN.1 is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunication and computer networking.
For this module, we can find official documentation at the following page:
The main module for performing SNMP queries is the following:
pysnmp.entity.rfc3413.oneliner.cmdgen
And here is the CommandGenerator class that allows you to query the SNMP servers:
In this code, we can see the basic use of the CommandGenerator class:
from pysnmp.entity.rfc3413.oneliner import cmdgen
cmdGen = cmdgen.CommandGenerator()
cisco_contact_info_oid = "1.3.6.1.4.1.9.2.1.61.0"
We can perform SNMP using the getCmd() method. The result is unpacked into various variables. The output of this command consists of a four-value tuple. Out of those, three are related to the errors returned by the command generator, and the fourth one (varBinds) is related to the actual variables that bind the returned data and contains the query result:
errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(cmdgen.CommunityData('secret'),
cmdgen.UdpTransportTarget(('172.16.1.189', 161)),
cisco_contact_info_oid)
for name, val in varBinds:
print('%s = %s' % (name.prettyPrint(), str(val)))
You can see that cmdgen takes the following parameters:
- CommunityData(): Sets the community string as public.
- UdpTransportTarget(): This is the host target, where the SNMP agent is running. This is specified in the pairing of the hostname and the UDP port.
- MibVariable: This is a tuple of values that includes the MIB version number and the MIB target string (which in this case is sysDescr; this refers to the description of the system).
In these examples, we see some scripts where the objective is to obtain the data from a remote SNMP agent.
You can find the following code in the filename:snmp_example1.py:
from pysnmp.hlapi import *
SNMP_HOST = '182.16.190.78'
SNMP_PORT = 161
SNMP_COMMUNITY = 'public'
errorIndication, errorStatus, errorIndex, varBinds = next(
getCmd(SnmpEngine(),
CommunityData(SNMP_COMMUNITY, mpModel=0),
UdpTransportTarget((SNMP_HOST, SNMP_PORT)),
ContextData(),
ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
)
if errorIndication:
print(errorIndication)
elif errorStatus:
print('%s at %s' % (errorStatus.prettyPrint(),errorIndex and varBinds[int(errorIndex)-1][0] or '?'))
else:
for varBind in varBinds:
print(' = '.join([ x.prettyPrint() for x in varBind ]))
If we try to execute the previous script, we see the public data of the SNMP agent registered:
You can find the following code in the filename: snmp_example2.py:
from snmp_helper import snmp_get_oid,snmp_extract
SNMP_HOST = '182.16.190.78'
SNMP_PORT = 161
SNMP_COMMUNITY = 'public'
a_device = (SNMP_HOST, SNMP_COMMUNITY , SNMP_PORT)
snmp_data = snmp_get_oid(a_device, oid='.1.3.6.1.2.1.1.1.0',display_errors=True)
print(snmp_data)
if snmp_data is not None:
output = snmp_extract(snmp_data)
print(output)
If we try to execute the previous script, we see the public data of the SNMP agent registered:
You can find the following code in the filename: snmp_example3.py:
from pysnmp.entity.rfc3413.oneliner import cmdgen
SNMP_HOST = '182.16.190.78'
SNMP_PORT = 161
SNMP_COMMUNITY = 'public'
snmpCmdGen = cmdgen.CommandGenerator()
snmpTransportData = cmdgen.UdpTransportTarget((SNMP_HOST ,SNMP_PORT ))
error,errorStatus,errorIndex,binds = snmpCmdGen
getCmd(cmdgen.CommunityData(SNMP_COMMUNITY),snmpTransportData,"1.3.6.1.2.1.1.1.0","1.3.6.1.2.1.1.3.0","1.3.6.1.2.1.2.1.0")
if error:
print("Error"+error)
else:
if errorStatus:
print('%s at %s' %(errorStatus.prettyPrint(),errorIndex and binds[int(errorIndex)-1] or '?'))
else:
for name,val in binds:
print('%s = %s' % (name.prettyPrint(),val.prettyPrint()))
If we try to execute the previous script, we see the public data of the SNMP agent registered:
In this example, we try to find communities for a specific SNMP server. For this task, we first get the file wordlist-common-snmp-community-strings.txt from fuzzdb that contains a list with communities available:
You can find the following code in the filename: snmp_brute_force.py:
from pysnmp.entity.rfc3413.oneliner import cmdgen
SNMP_HOST = '182.16.190.78'
SNMP_PORT = 161
cmdGen = cmdgen.CommandGenerator()
fd = open("wordlist-common-snmp-community-strings.txt")
for community in fd.readlines():
snmpCmdGen = cmdgen.CommandGenerator()
snmpTransportData = cmdgen.UdpTransportTarget((SNMP_HOST, SNMP_PORT),timeout=1.5,retries=0)
error, errorStatus, errorIndex, binds = snmpCmdGen.getCmd(cmdgen.CommunityData(community), snmpTransportData, "1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0", "1.3.6.1.2.1.2.1.0")
# Check for errors and print out results
if error:
print(str(error)+" For community: %s " %(community))
else:
print("Community Found '%s' ... exiting." %(community))
break
To obtain servers and SNMP agents, we can search in Shodan with the SNMP protocol and port 161, and we obtain the following results:
An interesting tool to check for connection with SNMP servers and obtain the value of the SNMP variable is the snmp-get that is available for both Windows and Unix environments:
https://snmpsoft.com/shell-tools/snmp-get/
With SnmpGet for Windows, we can obtain information about SNMP servers.
In the following screenshot, we can see command-line parameters for this tool.
Also, a similar tool is available for the Ubuntu operating system:
http://manpages.ubuntu.com/manpages/bionic/man1/snmpget.1.html