From 4321919c9f59341377ab748d0e1800a3422c867a Mon Sep 17 00:00:00 2001 From: klemou Date: Sat, 1 Oct 2022 09:26:32 +0200 Subject: [PATCH 1/7] run smbv1 scan in runfinger --- tools/RunFinger.py | 380 ++++++++++++++++++++++++--------------------- 1 file changed, 199 insertions(+), 181 deletions(-) diff --git a/tools/RunFinger.py b/tools/RunFinger.py index 7a9cd5f..869928f 100755 --- a/tools/RunFinger.py +++ b/tools/RunFinger.py @@ -32,6 +32,7 @@ parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None) parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None) +parser.add_option('-o','--outfile', action="store", help="Output file", dest="OutFilename", metavar="output.txt", default=None) parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2) options, args = parser.parse_args() @@ -44,6 +45,7 @@ if options.TARGET == None and options.Filename == None: Timeout = options.Timeout Host = options.TARGET Filename = options.Filename +Outputfile = None if options.OutFilename==None else open(options.OutFilename,"w") SMB1 = "True" SMB2signing = "False" DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db" @@ -69,10 +71,10 @@ else: if not os.path.exists(DB): - cursor = sqlite3.connect(DB) - cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)') - cursor.commit() - cursor.close() + cursor = sqlite3.connect(DB) + cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)') + cursor.commit() + cursor.close() def StructWithLenPython2or3(endian,data): #Python2... @@ -99,104 +101,107 @@ def longueur(payload): return length def ParseNegotiateSMB2Ans(data): - if data[4:8] == b"\xfeSMB": - return True - else: - return False + if data[4:8] == b"\xfeSMB": + return True + else: + return False def SMB2SigningMandatory(data): - global SMB2signing - if data[70] == "\x03": - SMB2signing = "True" - else: - SMB2signing = "False" + global SMB2signing + if data[70] == "\x03": + SMB2signing = "True" + else: + SMB2signing = "False" def WorkstationFingerPrint(data): - return { - b"\x04\x00" :"Windows 95", - b"\x04\x0A" :"Windows 98", - b"\x04\x5A" :"Windows ME", - b"\x05\x00" :"Windows 2000", - b"\x05\x01" :"Windows XP", - b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", - b"\x06\x00" :"Windows Vista/Server 2008", - b"\x06\x01" :"Windows 7/Server 2008R2", - b"\x06\x02" :"Windows 8/Server 2012", - b"\x06\x03" :"Windows 8.1/Server 2012R2", - b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)", - }.get(data, 'Other than Microsoft') + return { + b"\x04\x00" :"Windows 95", + b"\x04\x0A" :"Windows 98", + b"\x04\x5A" :"Windows ME", + b"\x05\x00" :"Windows 2000", + b"\x05\x01" :"Windows XP", + b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", + b"\x06\x00" :"Windows Vista/Server 2008", + b"\x06\x01" :"Windows 7/Server 2008R2", + b"\x06\x02" :"Windows 8/Server 2012", + b"\x06\x03" :"Windows 8.1/Server 2012R2", + b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)", + }.get(data, 'Other than Microsoft') def GetOsBuildNumber(data): - ProductBuild = struct.unpack(" Date: Wed, 19 Oct 2022 08:44:05 -0300 Subject: [PATCH 2/7] Removed machine accounts dump, since they are not crackable --- DumpHash.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/DumpHash.py b/DumpHash.py index 0e383d7..6ce39db 100755 --- a/DumpHash.py +++ b/DumpHash.py @@ -28,14 +28,20 @@ def GetResponderCompleteNTLMv2Hash(cursor): res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)") Output = "" for row in res.fetchall(): - Output += '{0}'.format(row[0])+'\n' + if "$" in row[0]: + pass + else: + Output += '{0}'.format(row[0])+'\n' return Output def GetResponderCompleteNTLMv1Hash(cursor): res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)") Output = "" for row in res.fetchall(): - Output += '{0}'.format(row[0])+'\n' + if "$" in row[0]: + pass + else: + Output += '{0}'.format(row[0])+'\n' return Output cursor = DbConnect() From 709df2c6e18ec2fa6647fdaaa4d9f9e2cb7920f8 Mon Sep 17 00:00:00 2001 From: requin Date: Mon, 31 Oct 2022 17:31:16 +0100 Subject: [PATCH 3/7] add hostname on smbv2 scan result --- tools/RunFinger.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tools/RunFinger.py b/tools/RunFinger.py index 869928f..d0a6474 100755 --- a/tools/RunFinger.py +++ b/tools/RunFinger.py @@ -104,7 +104,7 @@ def ParseNegotiateSMB2Ans(data): if data[4:8] == b"\xfeSMB": return True else: - return False + return False def SMB2SigningMandatory(data): global SMB2signing @@ -130,8 +130,8 @@ def WorkstationFingerPrint(data): def GetOsBuildNumber(data): ProductBuild = struct.unpack(" Date: Wed, 2 Nov 2022 19:16:10 +0100 Subject: [PATCH 4/7] add flag (-s) to enable smbv1scan --- tools/RunFinger.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/RunFinger.py b/tools/RunFinger.py index d0a6474..8190286 100755 --- a/tools/RunFinger.py +++ b/tools/RunFinger.py @@ -34,6 +34,7 @@ parser.add_option('-i','--ip', action="store", help="Target IP address or class parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None) parser.add_option('-o','--outfile', action="store", help="Output file", dest="OutFilename", metavar="output.txt", default=None) parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2) +parser.add_option('-s','--smbv1', action='store_true', help="Enable smbv1 scan", dest="Smbv1", default=False) options, args = parser.parse_args() @@ -49,6 +50,7 @@ Outputfile = None if options.OutFilename==None else open(options.OutFilename,"w" SMB1 = "True" SMB2signing = "False" DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db" +SCAN_SMBV1 = options.Smbv1 class Packet(): fields = OrderedDict([ @@ -406,7 +408,7 @@ def handle(data, host): ################## def ShowSmallResults(Host): ConnectAndChoseSMB((Host,445)) - if SMB1 == "True": + if SCAN_SMBV1 and SMB1 == "True": try: Hostname, DomainJoined = DomainGrab((Host, 445)) Signing, OsVer, LanManClient = SmbFinger((Host, 445)) From 9d4f919b391200247f342dce50eb48921f13a545 Mon Sep 17 00:00:00 2001 From: Stephen Shkardoon Date: Sun, 6 Nov 2022 01:27:28 +1300 Subject: [PATCH 5/7] 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 5c1b94e..c6350a4 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 aeab473..6ef8862 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 0000000..5ba69cf --- /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 bae810a..0367f24 100755 --- a/settings.py +++ b/settings.py @@ -99,6 +99,7 @@ class Settings: 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 @@ class Settings: 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 1ecea92..8b9175f 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:") From 660b6ca309558e597da6789216afca861bcf4d45 Mon Sep 17 00:00:00 2001 From: SAERXCIT <78735647+SAERXCIT@users.noreply.github.com> Date: Tue, 8 Nov 2022 12:23:01 +0100 Subject: [PATCH 6/7] Extend --disable-ess to HTTP --- packets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packets.py b/packets.py index 03ec50f..ecff5f7 100755 --- a/packets.py +++ b/packets.py @@ -359,7 +359,7 @@ class NTLM_Challenge(Packet): ("TargetNameLen", "\x06\x00"), ("TargetNameMaxLen", "\x06\x00"), ("TargetNameOffset", "\x38\x00\x00\x00"), - ("NegoFlags", "\x05\x02\x89\xa2"), + ("NegoFlags", "\x05\x02\x81\xa2" if settings.Config.NOESS_On_Off else "\x05\x02\x89\xa2"), ("ServerChallenge", ""), ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), ("TargetInfoLen", "\x7e\x00"), From f39079da77cbf6d6afa9632dcdf70ff76da18cf8 Mon Sep 17 00:00:00 2001 From: lgandx Date: Tue, 8 Nov 2022 09:22:41 -0300 Subject: [PATCH 7/7] Revert "run smbv1 scan in runfinger" --- tools/RunFinger.py | 383 +++++++++++++++++++++------------------------ 1 file changed, 181 insertions(+), 202 deletions(-) diff --git a/tools/RunFinger.py b/tools/RunFinger.py index 8190286..7a9cd5f 100755 --- a/tools/RunFinger.py +++ b/tools/RunFinger.py @@ -32,9 +32,7 @@ parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None) parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None) -parser.add_option('-o','--outfile', action="store", help="Output file", dest="OutFilename", metavar="output.txt", default=None) parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2) -parser.add_option('-s','--smbv1', action='store_true', help="Enable smbv1 scan", dest="Smbv1", default=False) options, args = parser.parse_args() @@ -46,11 +44,9 @@ if options.TARGET == None and options.Filename == None: Timeout = options.Timeout Host = options.TARGET Filename = options.Filename -Outputfile = None if options.OutFilename==None else open(options.OutFilename,"w") SMB1 = "True" SMB2signing = "False" DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db" -SCAN_SMBV1 = options.Smbv1 class Packet(): fields = OrderedDict([ @@ -73,10 +69,10 @@ else: if not os.path.exists(DB): - cursor = sqlite3.connect(DB) - cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)') - cursor.commit() - cursor.close() + cursor = sqlite3.connect(DB) + cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)') + cursor.commit() + cursor.close() def StructWithLenPython2or3(endian,data): #Python2... @@ -103,108 +99,104 @@ def longueur(payload): return length def ParseNegotiateSMB2Ans(data): - if data[4:8] == b"\xfeSMB": - return True - else: - return False + if data[4:8] == b"\xfeSMB": + return True + else: + return False def SMB2SigningMandatory(data): - global SMB2signing - if data[70] == "\x03": - SMB2signing = "True" - else: - SMB2signing = "False" + global SMB2signing + if data[70] == "\x03": + SMB2signing = "True" + else: + SMB2signing = "False" def WorkstationFingerPrint(data): - return { - b"\x04\x00" :"Windows 95", - b"\x04\x0A" :"Windows 98", - b"\x04\x5A" :"Windows ME", - b"\x05\x00" :"Windows 2000", - b"\x05\x01" :"Windows XP", - b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", - b"\x06\x00" :"Windows Vista/Server 2008", - b"\x06\x01" :"Windows 7/Server 2008R2", - b"\x06\x02" :"Windows 8/Server 2012", - b"\x06\x03" :"Windows 8.1/Server 2012R2", - b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)", - }.get(data, 'Other than Microsoft') + return { + b"\x04\x00" :"Windows 95", + b"\x04\x0A" :"Windows 98", + b"\x04\x5A" :"Windows ME", + b"\x05\x00" :"Windows 2000", + b"\x05\x01" :"Windows XP", + b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", + b"\x06\x00" :"Windows Vista/Server 2008", + b"\x06\x01" :"Windows 7/Server 2008R2", + b"\x06\x02" :"Windows 8/Server 2012", + b"\x06\x03" :"Windows 8.1/Server 2012R2", + b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)", + }.get(data, 'Other than Microsoft') def GetOsBuildNumber(data): - ProductBuild = struct.unpack("