Skip to content
This repository has been archived by the owner on Dec 6, 2023. It is now read-only.

Commit

Permalink
Merge pull request #655 from zblurx/master
Browse files Browse the repository at this point in the history
Fix kerberos authentication and add kerbrute
  • Loading branch information
mpgn authored Oct 31, 2022
2 parents fedbfaf + 3942eab commit a36d314
Show file tree
Hide file tree
Showing 5 changed files with 429 additions and 198 deletions.
3 changes: 2 additions & 1 deletion cme/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def gen_cli_args():
std_parser.add_argument('-id', metavar="CRED_ID", nargs='+', default=[], type=str, dest='cred_id', help='database credential ID(s) to use for authentication')
std_parser.add_argument("-u", metavar="USERNAME", dest='username', nargs='+', default=[], help="username(s) or file(s) containing usernames")
std_parser.add_argument("-p", metavar="PASSWORD", dest='password', nargs='+', default=[], help="password(s) or file(s) containing passwords")
std_parser.add_argument("-k", "--kerberos", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
std_parser.add_argument("-k", "--kerberos", action='store_true', help="Use Kerberos authentication")
std_parser.add_argument("--use-kcache", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
std_parser.add_argument("--export", metavar="EXPORT", nargs='+', help="Export result into a file, probably buggy")
std_parser.add_argument("--aesKey", metavar="AESKEY", nargs='+', help="AES key to use for Kerberos Authentication (128 or 256 bits)")
std_parser.add_argument("--kdcHost", metavar="KDCHOST", help="FQDN of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter")
Expand Down
262 changes: 146 additions & 116 deletions cme/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,120 +162,150 @@ def over_fail_limit(self, username):
return False

def login(self):
if self.args.kerberos:
if self.kerberos_login(self.domain, self.aesKey, self.kdcHost): return True
else:
for cred_id in self.args.cred_id:
with sem:
if cred_id.lower() == 'all':
creds = self.db.get_credentials()
else:
creds = self.db.get_credentials(filterTerm=int(cred_id))

for cred in creds:
logging.debug(cred)
try:
c_id, domain, username, password, credtype, pillaged_from = cred

if credtype and password:

if not domain: domain = self.domain

if self.args.local_auth:
domain = self.domain
elif self.args.domain:
domain = self.args.domain

if credtype == 'hash' and not self.over_fail_limit(username):
if self.hash_login(domain, username, password): return True

elif credtype == 'plaintext' and not self.over_fail_limit(username):
if self.plaintext_login(domain, username, password): return True

except IndexError:
self.logger.error("Invalid database credential ID!")

for user in self.args.username:
if isfile(user):
with open(user, 'r') as user_file:
for usr in user_file:
if "\\" in usr:
tmp = usr
usr = tmp.split('\\')[1].strip()
self.domain = tmp.split('\\')[0]
if hasattr(self.args, 'hash') and self.args.hash:
with sem:
for ntlm_hash in self.args.hash:
if isfile(ntlm_hash):
with open(ntlm_hash, 'r') as ntlm_hash_file:
if self.args.no_bruteforce == False:
for f_hash in ntlm_hash_file:
if not self.over_fail_limit(usr.strip()):
if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
elif self.args.no_bruteforce == True:
user_file.seek(0) # HACK: this should really not be in the usr for loop
for usr, f_hash in zip(user_file, ntlm_hash_file):
if not self.over_fail_limit(usr.strip()):
if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
else: # ntlm_hash is a string
if not self.over_fail_limit(usr.strip()):
if self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True

elif self.args.password:
with sem:
for password in self.args.password:
if isfile(password):
with open(password, 'r') as password_file:
if self.args.no_bruteforce == False:
for f_pass in password_file:
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
else:
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
elif self.args.no_bruteforce == True:
user_file.seek(0) # HACK: this should really not be in the usr for loop
for usr, f_pass in zip(user_file, password_file):
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
else:
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
else: # password is a string
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.plaintext_login(self.domain, usr.strip(), password): return True
else:
if self.plaintext_login(usr.strip(), password): return True

else: # user is a string
if hasattr(self.args, 'hash') and self.args.hash:
with sem:
for ntlm_hash in self.args.hash:
if isfile(ntlm_hash):
with open(ntlm_hash, 'r') as ntlm_hash_file:
for f_hash in ntlm_hash_file:
if not self.over_fail_limit(user):
if self.hash_login(self.domain, user, f_hash.strip()): return True
else: # ntlm_hash is a string
if not self.over_fail_limit(user):
if self.hash_login(self.domain, user, ntlm_hash.strip()): return True

elif self.args.password:
with sem:
for password in self.args.password:
if isfile(password):
with open(password, 'r') as password_file:
for f_pass in password_file:
if not self.over_fail_limit(user):
if hasattr(self.args, 'domain'):
if self.plaintext_login(self.domain, user, f_pass.strip()): return True
else:
if self.plaintext_login(user, f_pass.strip()): return True
else: # password is a string
if not self.over_fail_limit(user):
if hasattr(self.args, 'domain'):
if self.plaintext_login(self.domain, user, password): return True
else:
if self.plaintext_login(user, password): return True
for cred_id in self.args.cred_id:
with sem:
if cred_id.lower() == 'all':
creds = self.db.get_credentials()
else:
creds = self.db.get_credentials(filterTerm=int(cred_id))
for cred in creds:
logging.debug(cred)
try:
c_id, domain, username, password, credtype, pillaged_from = cred

if credtype and password:

if not domain: domain = self.domain

if self.args.local_auth:
domain = self.domain
elif self.args.domain:
domain = self.args.domain

if credtype == 'hash' and not self.over_fail_limit(username):
if self.args.kerberos:
if self.kerberos_login(domain, username, '', password, '', self.kdcHost, False): return True
elif self.hash_login(domain, username, password): return True

elif credtype == 'plaintext' and not self.over_fail_limit(username):
if self.args.kerberos:
if self.kerberos_login(domain, username, password, '' , '', self.kdcHost, False): return True
elif self.plaintext_login(domain, username, password): return True

except IndexError:
self.logger.error("Invalid database credential ID!")
if self.args.use_kcache:
with sem:
if self.kerberos_login(self.domain, '', '', '', '', self.kdcHost, True): return True
for user in self.args.username:
if isfile(user):
with open(user, 'r') as user_file:
for usr in user_file:
if "\\" in usr:
tmp = usr
usr = tmp.split('\\')[1].strip()
self.domain = tmp.split('\\')[0]
if hasattr(self.args, 'hash') and self.args.hash:
with sem:
for ntlm_hash in self.args.hash:
if isfile(ntlm_hash):
with open(ntlm_hash, 'r') as ntlm_hash_file:
if self.args.no_bruteforce == False:
for f_hash in ntlm_hash_file:
if not self.over_fail_limit(usr.strip()):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), '', f_hash.strip(), '', self.kdcHost, False): return True
elif self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
elif self.args.no_bruteforce == True:
user_file.seek(0) # HACK: this should really not be in the usr for loop
for usr, f_hash in zip(user_file, ntlm_hash_file):
if not self.over_fail_limit(usr.strip()):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), '', f_hash.strip(), '', self.kdcHost, False): return True
elif self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
else: # ntlm_hash is a string
if not self.over_fail_limit(usr.strip()):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), '', ntlm_hash.strip(), '', self.kdcHost, False): return True
elif self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True

elif self.args.password:
with sem:
for password in self.args.password:
if isfile(password):
with open(password, 'r') as password_file:
if self.args.no_bruteforce == False:
for f_pass in password_file:
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True
elif self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
else:
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
elif self.args.no_bruteforce == True:
user_file.seek(0) # HACK: this should really not be in the usr for loop
for usr, f_pass in zip(user_file, password_file):
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True
elif self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
else:
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
else: # password is a string
if not self.over_fail_limit(usr.strip()):
if hasattr(self.args, 'domain'):
if self.args.kerberos:
if self.kerberos_login(self.domain, usr.strip(), password, '', '', self.kdcHost, False): return True
elif self.plaintext_login(self.domain, usr.strip(), password): return True
else:
if self.plaintext_login(usr.strip(), password): return True

else: # user is a string
if hasattr(self.args, 'hash') and self.args.hash:
with sem:
for ntlm_hash in self.args.hash:
if isfile(ntlm_hash):
with open(ntlm_hash, 'r') as ntlm_hash_file:
for f_hash in ntlm_hash_file:
if not self.over_fail_limit(user):
if self.args.kerberos:
if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True
elif self.hash_login(self.domain, user, f_hash.strip()): return True
else: # ntlm_hash is a string
if not self.over_fail_limit(user):
if self.args.kerberos:
if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True
elif self.hash_login(self.domain, user, ntlm_hash.strip()): return True

elif self.args.password:
with sem:
for password in self.args.password:
if isfile(password):
with open(password, 'r') as password_file:
for f_pass in password_file:
if not self.over_fail_limit(user):
if hasattr(self.args, 'domain'):
if self.args.kerberos:
if self.kerberos_login(self.domain, user, f_pass.strip(), '', '', self.kdcHost, False): return True
elif self.plaintext_login(self.domain, user, f_pass.strip()): return True
else:
if self.plaintext_login(user, f_pass.strip()): return True
else: # password is a string
if not self.over_fail_limit(user):
if hasattr(self.args, 'domain'):
if self.args.kerberos:
if self.kerberos_login(self.domain, user, password, '', '', self.kdcHost, False): return True
elif self.plaintext_login(self.domain, user, password): return True
else:
if self.plaintext_login(user, password): return True

elif self.args.aesKey:
with sem:
for aesKey in self.args.aesKey:
if not self.over_fail_limit(user):
if self.kerberos_login(self.domain, user, '', '', aesKey.strip(), self.kdcHost, False): return True



Loading

0 comments on commit a36d314

Please sign in to comment.