From f4485ff279e1c34bafda9d69d1c461d92fb32c63 Mon Sep 17 00:00:00 2001 From: zblurx Date: Thu, 20 Oct 2022 18:08:30 +0200 Subject: [PATCH 01/20] fix kerberos authentication --- cme/cli.py | 3 +- cme/connection.py | 263 +++++++++++++++++++++++------------------- cme/protocols/ldap.py | 23 +++- cme/protocols/smb.py | 21 +++- 4 files changed, 186 insertions(+), 124 deletions(-) diff --git a/cme/cli.py b/cme/cli.py index 9528489f..a2849c64 100755 --- a/cme/cli.py +++ b/cme/cli.py @@ -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-cache", 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") diff --git a/cme/connection.py b/cme/connection.py index 60be6749..5a7b71ce 100755 --- a/cme/connection.py +++ b/cme/connection.py @@ -162,120 +162,151 @@ 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)) + print(creds) + 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 + if 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 + if self.plaintext_login(domain, username, password): return True + + except IndexError: + self.logger.error("Invalid database credential ID!") + if self.args.use_cache: + 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 + 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.args.kerberos: + if self.kerberos_login(self.domain, usr.strip(), '', f_hash.strip(), '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, usr.strip(), '', ntlm_hash.strip(), '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, usr.strip(), password, '', '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, user, f_pass.strip(), '', '', self.kdcHost, False): return True + 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.args.kerberos: + if self.kerberos_login(self.domain, user, password, '', '', self.kdcHost, False): return True + if 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 + + diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index e1544aab..0b17a715 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -237,15 +237,28 @@ def print_host_info(self): #self.logger.info(self.endpoint) return True - def kerberos_login(self, domain, aesKey, kdcHost): + def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): # Get ldap info (target, targetDomain, baseDN) target, self.targetDomain, self.baseDN = self.get_ldap_info(self.host) + lmhash = '' + nthash = '' + self.username = username + #This checks to see if we didn't provide the LM Hash + if ntlm_hash.find(':') != -1: + lmhash, nthash = ntlm_hash.split(':') + self.hash = nthash + else: + nthash = ntlm_hash + self.hash = ntlm_hash + if lmhash: self.lmhash = lmhash + if nthash: self.nthash = nthash + try: # Connect to LDAP self.ldapConnection = ldap_impacket.LDAPConnection('ldap://%s' % target, self.baseDN) - self.ldapConnection.kerberosLogin(self.username, self.password, self.domain, self.lmhash, self.nthash, - self.aesKey, kdcHost=kdcHost) + self.ldapConnection.kerberosLogin(username, password, domain, self.lmhash, self.nthash, + aesKey, kdcHost=kdcHost, useCache=useCache) if self.username == '': self.username = self.get_ldap_username() @@ -268,8 +281,8 @@ def kerberos_login(self, domain, aesKey, kdcHost): # We need to try SSL # Connect to LDAPS self.ldapConnection = ldap_impacket.LDAPConnection('ldaps://%s' % target, self.baseDN) - self.ldapConnection.kerberosLogin(self.username, self.password, self.domain, self.lmhash, self.nthash, - self.aesKey, kdcHost=kdcHost) + self.ldapConnection.kerberosLogin(username, password, domain, self.lmhash, self.nthash, + aesKey, kdcHost=kdcHost, useCache=useCache) if self.username == '': self.username = self.get_ldap_username() diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 1f25cf30..a16a0f54 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -335,14 +335,31 @@ def print_host_info(self): return self.laps_search(self.args.username, self.args.password, self.args.hash, self.domain) return True - def kerberos_login(self, domain, aesKey, kdcHost): + def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): #Re-connect since we logged off self.create_conn_obj() + lmhash = '' + nthash = '' # dirty code to check if user is admin but pywerview does not support kerberos auth ... error = '' try: - self.conn.kerberosLogin('', '', self.domain, self.lmhash, self.nthash, aesKey, kdcHost) + + self.username = username + #This checks to see if we didn't provide the LM Hash + if ntlm_hash.find(':') != -1: + lmhash, nthash = ntlm_hash.split(':') + self.hash = nthash + else: + nthash = ntlm_hash + self.hash = ntlm_hash + if lmhash: self.lmhash = lmhash + if nthash: self.nthash = nthash + + + self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache) + # self.check_if_admin() # currently pywerview does not support kerberos auth + except SessionError as e: error = e try: From e6250e1b9806273d87dfd55892985efe3299f0b2 Mon Sep 17 00:00:00 2001 From: zblurx Date: Thu, 20 Oct 2022 18:11:10 +0200 Subject: [PATCH 02/20] change parameter name --- cme/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cme/connection.py b/cme/connection.py index 5a7b71ce..824f17f2 100755 --- a/cme/connection.py +++ b/cme/connection.py @@ -195,7 +195,7 @@ def login(self): except IndexError: self.logger.error("Invalid database credential ID!") - if self.args.use_cache: + if self.args.use_kcache: with sem: if self.kerberos_login(self.domain, '', '', '', '', self.kdcHost, True): return True for user in self.args.username: From c52031f344ecb5196677aa8db590efc0cf50d21f Mon Sep 17 00:00:00 2001 From: zblurx Date: Thu, 20 Oct 2022 18:19:23 +0200 Subject: [PATCH 03/20] change parameter name --- cme/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cme/cli.py b/cme/cli.py index a2849c64..997027f8 100755 --- a/cme/cli.py +++ b/cme/cli.py @@ -50,7 +50,7 @@ def gen_cli_args(): 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") - std_parser.add_argument("--use-cache", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)") + 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") From 53f5791e7ce3d6df73f17d135842acd211d247db Mon Sep 17 00:00:00 2001 From: mpgn Date: Thu, 20 Oct 2022 15:40:53 -0400 Subject: [PATCH 04/20] Fix a lot things but good pr --- cme/connection.py | 25 ++++++++++++------------- cme/protocols/ldap.py | 33 +++++++++++++++++++++++++++------ cme/protocols/smb.py | 7 ++++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/cme/connection.py b/cme/connection.py index 824f17f2..5fe87964 100755 --- a/cme/connection.py +++ b/cme/connection.py @@ -168,7 +168,6 @@ def login(self): creds = self.db.get_credentials() else: creds = self.db.get_credentials(filterTerm=int(cred_id)) - print(creds) for cred in creds: logging.debug(cred) try: @@ -186,12 +185,12 @@ def login(self): 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 - if self.hash_login(domain, username, password): 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 - if self.plaintext_login(domain, username, password): return True + elif self.plaintext_login(domain, username, password): return True except IndexError: self.logger.error("Invalid database credential ID!") @@ -216,19 +215,19 @@ def login(self): 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 - if self.hash_login(self.domain, usr.strip(), f_hash.strip()): 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 - if self.hash_login(self.domain, usr.strip(), f_hash.strip()): 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 - if self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True + elif self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True elif self.args.password: with sem: @@ -241,7 +240,7 @@ def login(self): 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 - if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): 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: @@ -251,7 +250,7 @@ def login(self): 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 - if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): 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 @@ -259,7 +258,7 @@ def login(self): if hasattr(self.args, 'domain'): if self.args.kerberos: if self.kerberos_login(self.domain, usr.strip(), password, '', '', self.kdcHost, False): return True - if self.plaintext_login(self.domain, usr.strip(), password): return True + elif self.plaintext_login(self.domain, usr.strip(), password): return True else: if self.plaintext_login(usr.strip(), password): return True @@ -273,12 +272,12 @@ def login(self): 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 - if self.hash_login(self.domain, user, f_hash.strip()): 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 - if self.hash_login(self.domain, user, ntlm_hash.strip()): return True + elif self.hash_login(self.domain, user, ntlm_hash.strip()): return True elif self.args.password: with sem: @@ -290,7 +289,7 @@ def login(self): if hasattr(self.args, 'domain'): if self.args.kerberos: if self.kerberos_login(self.domain, user, f_pass.strip(), '', '', self.kdcHost, False): return True - if self.plaintext_login(self.domain, user, f_pass.strip()): 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 @@ -298,7 +297,7 @@ def login(self): if hasattr(self.args, 'domain'): if self.args.kerberos: if self.kerberos_login(self.domain, user, password, '', '', self.kdcHost, False): return True - if self.plaintext_login(self.domain, user, password): return True + elif self.plaintext_login(self.domain, user, password): return True else: if self.plaintext_login(user, password): return True diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 0b17a715..4abc31a1 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -238,6 +238,8 @@ def print_host_info(self): return True def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): + self.logger.extra['protocol'] = "LDAP" + self.logger.extra['port'] = "389" # Get ldap info (target, targetDomain, baseDN) target, self.targetDomain, self.baseDN = self.get_ldap_info(self.host) @@ -270,12 +272,25 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) - self.logger.extra['protocol'] = "LDAP" - self.logger.extra['port'] = "389" self.logger.success(out) if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True + except SessionError as e: + self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.username, + self.password, + str(e)), + color='red') + return False + except KeyError as e: + self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.username, + '', + ''), + color='red') except ldap_impacket.LDAPSessionError as e: if str(e).find('strongerAuthRequired') >= 0: # We need to try SSL @@ -300,6 +315,8 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True else: errorCode = str(e).split()[-2][:-1] self.logger.error(u'{}\\{}:{} {}'.format(self.domain, @@ -308,9 +325,9 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), color='magenta' if errorCode in ldap_error_status else 'red') - return True - def plaintext_login(self, domain, username, password): + self.logger.extra['protocol'] = "LDAP" + self.logger.extra['port'] = "389" self.username = username self.password = password self.domain = domain @@ -337,8 +354,6 @@ def plaintext_login(self, domain, username, password): self.username, self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) - self.logger.extra['protocol'] = "LDAP" - self.logger.extra['port'] = "389" self.logger.success(out) if not self.args.local_auth: @@ -366,6 +381,8 @@ def plaintext_login(self, domain, username, password): if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True except ldap_impacket.LDAPSessionError as e: errorCode = str(e).split()[-2][:-1] self.logger.error(u'{}\\{}:{} {}'.format(self.domain, @@ -391,6 +408,8 @@ def plaintext_login(self, domain, username, password): def hash_login(self, domain, username, ntlm_hash): + self.logger.extra['protocol'] = "LDAP" + self.logger.extra['port'] = "389" lmhash = '' nthash = '' @@ -456,6 +475,8 @@ def hash_login(self, domain, username, ntlm_hash): if not self.args.local_auth: add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True except ldap_impacket.LDAPSessionError as e: errorCode = str(e).split()[-2][:-1] self.logger.error(u'{}\\{}:{} {}'.format(self.domain, diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index a16a0f54..564d15bd 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -354,8 +354,6 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.hash = ntlm_hash if lmhash: self.lmhash = lmhash if nthash: self.nthash = nthash - - self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache) # self.check_if_admin() # currently pywerview does not support kerberos auth @@ -372,7 +370,10 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.conn.getCredentials()[0], highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) - return True + if not self.args.local_auth: + add_user_bh(username, domain, self.logger, self.config) + if not self.args.continue_on_success: + return True else: self.logger.error(u'{} {} {}'.format(self.domain, error, From 7e0613c883ba44dd2eef1b7e824d4947fe247882 Mon Sep 17 00:00:00 2001 From: mpgn Date: Thu, 20 Oct 2022 17:18:22 -0400 Subject: [PATCH 05/20] fix username to send to bh --- cme/protocols/smb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 564d15bd..58ba88da 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -371,7 +371,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: - add_user_bh(username, domain, self.logger, self.config) + add_user_bh(self.conn.getCredentials()[0], domain, self.logger, self.config) if not self.args.continue_on_success: return True else: From ed2b2b261ada1bce1fdd0c10a70efba18e98866b Mon Sep 17 00:00:00 2001 From: mpgn Date: Sat, 22 Oct 2022 16:38:29 -0400 Subject: [PATCH 06/20] fix for kerberoast function --- cme/protocols/ldap.py | 5 ++++- cme/protocols/smb.py | 15 +++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 4abc31a1..11297d78 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -240,6 +240,9 @@ def print_host_info(self): def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): self.logger.extra['protocol'] = "LDAP" self.logger.extra['port'] = "389" + self.username = username + self.password = password + self.domain = domain # Get ldap info (target, targetDomain, baseDN) target, self.targetDomain, self.baseDN = self.get_ldap_info(self.host) @@ -741,7 +744,6 @@ def kerberoasting(self): self.logger.highlight("No entries found!") elif resp: answers = [] - self.logger.info('Total of records returned %d' % len(resp)) for item in resp: if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True: @@ -792,6 +794,7 @@ def kerberoasting(self): pass if len(answers)>0: + self.logger.info('Total of records returned %d' % len(answers)) TGT = KerberosAttacks(self).getTGT_kerberoasting() dejavue = [] for SPN, sAMAccountName, memberOf, pwdLastSet, lastLogon, delegation in answers: diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 58ba88da..8a7407a5 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -253,13 +253,16 @@ def enum_host_info(self): try: self.conn.login('' , '') - except: - #if "STATUS_ACCESS_DENIED" in e: + self.domain = self.conn.getServerDNSDomainName() + self.hostname = self.conn.getServerName() + self.server_os = self.conn.getServerOS() + except Exception as e: + if "STATUS_NOT_SUPPORTED" in str(e): + # no ntlm supported + self.domain = self.args.domain + self.hostname = self.host pass - self.domain = self.conn.getServerDNSDomainName() - self.hostname = self.conn.getServerName() - self.server_os = self.conn.getServerOS() try: self.signing = self.conn.isSigningRequired() if self.smbv1 else self.conn._SMBConnection._Connection['RequireSigning'] except: @@ -358,7 +361,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey # self.check_if_admin() # currently pywerview does not support kerberos auth - except SessionError as e: + except (SessionError, Exception) as e: error = e try: self.conn.connectTree("C$") From 0a284bd2b048f4d8d8dc062f6e029b0ed2c5cc3e Mon Sep 17 00:00:00 2001 From: mpgn Date: Sat, 22 Oct 2022 17:29:56 -0400 Subject: [PATCH 07/20] remove message CCache file is not found + fix exec method with kerberos --- cme/protocols/ldap.py | 1 + cme/protocols/smb.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 11297d78..ce184dbf 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -238,6 +238,7 @@ def print_host_info(self): return True def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): + logging.getLogger("impacket").disabled = True self.logger.extra['protocol'] = "LDAP" self.logger.extra['port'] = "389" self.username = username diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 8a7407a5..07a89cce 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -339,6 +339,7 @@ def print_host_info(self): return True def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): + logging.getLogger("impacket").disabled = True #Re-connect since we logged off self.create_conn_obj() lmhash = '' @@ -346,8 +347,9 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey # dirty code to check if user is admin but pywerview does not support kerberos auth ... error = '' try: - - self.username = username + if not self.args.laps: + self.password = password + self.username = username #This checks to see if we didn't provide the LM Hash if ntlm_hash.find(':') != -1: lmhash, nthash = ntlm_hash.split(':') From 7dc90669d7f860f4cb7f1acdeee46fc9703f1c88 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 04:10:44 -0400 Subject: [PATCH 08/20] starting to add mssql kerberos login --- cme/protocols/mssql.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index 44003cbd..40a63026 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -134,6 +134,7 @@ def print_host_info(self): def create_conn_obj(self): try: + print(self.host) self.conn = tds.MSSQL(self.host, self.args.port, rowsPrinter=self.logger) self.conn.connect() except socket.error: @@ -158,6 +159,36 @@ def check_if_admin(self): return True + def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): + print(username, password, domain) + res = self.conn.kerberosLogin(None, username, password, domain, None, aesKey, kdcHost=kdcHost) + try: + + if res is not True: + self.conn.printReplies() + return False + + self.password = password + self.username = username + self.domain = domain + self.check_if_admin() + + out = u'{}{}:{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', + username, + password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, + highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) + self.logger.success(out) + if not self.args.local_auth: + add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True + except Exception as e: + self.logger.error(u'{}\\{}:{} {}'.format(domain, + username, + password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, + e)) + return False + def plaintext_login(self, domain, username, password): try: self.conn.disconnect() From fb1d7b181fdb2e562cac5fc0b9516f52a5e1e280 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 04:24:21 -0400 Subject: [PATCH 09/20] add mssql kerberos login --- cme/protocols/mssql.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index 40a63026..60ed2f1a 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -134,7 +134,6 @@ def print_host_info(self): def create_conn_obj(self): try: - print(self.host) self.conn = tds.MSSQL(self.host, self.args.port, rowsPrinter=self.logger) self.conn.connect() except socket.error: @@ -160,10 +159,14 @@ def check_if_admin(self): return True def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey = '', kdcHost = '', useCache = False): - print(username, password, domain) - res = self.conn.kerberosLogin(None, username, password, domain, None, aesKey, kdcHost=kdcHost) try: - + self.conn.disconnect() + except: + pass + self.create_conn_obj() + logging.getLogger("impacket").disabled = True + try: + res = self.conn.kerberosLogin(None, username, password, domain, None, None, kdcHost=kdcHost) if res is not True: self.conn.printReplies() return False From ef349a5309bd2548c28d752d14f24fc5dca374da Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 05:26:53 -0400 Subject: [PATCH 10/20] refactor check if admin func to be comptatible with kerberos --- cme/protocols/smb.py | 59 +++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 07a89cce..4e25d93f 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -11,9 +11,9 @@ from impacket.smb import SMB_DIALECT from impacket.examples.secretsdump import RemoteOperations, SAMHashes, LSASecrets, NTDSHashes from impacket.nmb import NetBIOSError, NetBIOSTimeout -from impacket.dcerpc.v5 import transport, lsat, lsad +from impacket.dcerpc.v5 import transport, lsat, lsad, scmr from impacket.dcerpc.v5.rpcrt import DCERPCException -from impacket.dcerpc.v5.transport import DCERPCTransportFactory +from impacket.dcerpc.v5.transport import DCERPCTransportFactory, SMBTransport from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE from impacket.dcerpc.v5.epm import MSRPC_UUID_PORTMAP from impacket.dcerpc.v5.dcom.wmi import WBEM_FLAG_FORWARD_ONLY @@ -360,17 +360,8 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if lmhash: self.lmhash = lmhash if nthash: self.nthash = nthash self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache) + self.check_if_admin() - # self.check_if_admin() # currently pywerview does not support kerberos auth - - except (SessionError, Exception) as e: - error = e - try: - self.conn.connectTree("C$") - self.admin_privs = True - except SessionError as e: - pass - if not error: out = u'{}\\{} {}'.format(self.domain, self.conn.getCredentials()[0], highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) @@ -379,20 +370,18 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey add_user_bh(self.conn.getCredentials()[0], domain, self.logger, self.config) if not self.args.continue_on_success: return True - else: + elif self.signing: # check https://github.com/byt3bl33d3r/CrackMapExec/issues/321 + try: + self.conn.logoff() + except: + pass + self.create_conn_obj() + except (SessionError, Exception) as e: self.logger.error(u'{} {} {}'.format(self.domain, - error, + str(e), '({})'.format(desc) if self.args.verbose else '')) return False - # check https://github.com/byt3bl33d3r/CrackMapExec/issues/321 - if self.signing: - try: - self.conn.logoff() - except: - pass - self.create_conn_obj() - def plaintext_login(self, domain, username, password): #Re-connect since we logged off self.create_conn_obj() @@ -545,15 +534,23 @@ def create_conn_obj(self): return False def check_if_admin(self): - lmhash = '' - nthash = '' - - if self.hash: - if self.hash.find(':') != -1: - lmhash, nthash = self.hash.split(':') - else: - nthash = self.hash - self.admin_privs = invoke_checklocaladminaccess(self.host, self.domain, self.username, self.password, lmhash, nthash) + rpctransport = SMBTransport(self.conn.getRemoteHost(), 445, r'\svcctl', smb_connection=self.conn) + dce = rpctransport.get_dce_rpc() + try: + dce.connect() + except: + pass + else: + dce.bind(scmr.MSRPC_UUID_SCMR) + try: + # 0xF003F - SC_MANAGER_ALL_ACCESS + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx + ans = scmr.hROpenSCManagerW(dce,'{}\x00'.format(self.host),'ServicesActive\x00', 0xF003F) + self.admin_privs = True + except scmr.DCERPCException as e: + self.admin_privs = False + pass + return def gen_relay_list(self): if self.server_os.lower().find('windows') != -1 and self.signing is False: From 0a218c534fca0a5caf1b755b2b7eab281fc635e7 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 05:43:52 -0400 Subject: [PATCH 11/20] add magenta color if user exist but connection KO --- cme/protocols/smb.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 4e25d93f..30c43e7c 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -54,7 +54,8 @@ "STATUS_PASSWORD_EXPIRED", "STATUS_PASSWORD_MUST_CHANGE", "STATUS_ACCESS_DENIED", - "STATUS_NO_SUCH_FILE" + "STATUS_NO_SUCH_FILE", + "KDC_ERR_CLIENT_REVOKED" ] def get_error_string(exception): @@ -344,8 +345,6 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.create_conn_obj() lmhash = '' nthash = '' - # dirty code to check if user is admin but pywerview does not support kerberos auth ... - error = '' try: if not self.args.laps: self.password = password @@ -377,9 +376,18 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey pass self.create_conn_obj() except (SessionError, Exception) as e: - self.logger.error(u'{} {} {}'.format(self.domain, - str(e), - '({})'.format(desc) if self.args.verbose else '')) + error, desc = e.getErrorString() + self.logger.error(u'{}\\{}:{} {} {}'.format(domain, + self.username, + self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, + error, + '({})'.format(desc) if self.args.verbose else ''), + color='magenta' if error in smb_error_status else 'red') + if error not in smb_error_status: + self.inc_failed_login(username) + return False + if not self.args.continue_on_success: + return True return False def plaintext_login(self, domain, username, password): From b42cb70cd85773ce8861d4b96d0762eccc1b0483 Mon Sep 17 00:00:00 2001 From: zblurx Date: Mon, 24 Oct 2022 13:30:07 +0200 Subject: [PATCH 12/20] enhance kerberos auth to mssql --- cme/protocols/mssql.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index 60ed2f1a..bc933c94 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -166,7 +166,15 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.create_conn_obj() logging.getLogger("impacket").disabled = True try: - res = self.conn.kerberosLogin(None, username, password, domain, None, None, kdcHost=kdcHost) + hashes = None + if ntlm_hash != '': + if ntlm_hash.find(':') != -1: + hashes = ntlm_hash.split(':') + else: + # only nt hash + hashes = ':%s' % ntlm_hash + + res = self.conn.kerberosLogin(None, username, password, domain, hashes, aesKey, kdcHost=kdcHost, useCache=useCache) if res is not True: self.conn.printReplies() return False @@ -176,9 +184,8 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.domain = domain self.check_if_admin() - out = u'{}{}:{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', + out = u'{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', username, - password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -186,9 +193,8 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if not self.args.continue_on_success: return True except Exception as e: - self.logger.error(u'{}\\{}:{} {}'.format(domain, + self.logger.error(u'{}\\{} {}'.format(domain, username, - password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, e)) return False From 53b612d3179d4326e1206a054dcce56d95fece29 Mon Sep 17 00:00:00 2001 From: zblurx Date: Mon, 24 Oct 2022 14:12:32 +0200 Subject: [PATCH 13/20] adapt outputed creds --- cme/protocols/ldap.py | 29 ++++++++++++++++++----------- cme/protocols/mssql.py | 19 ++++++++++++++----- cme/protocols/smb.py | 13 +++++++++---- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index fe4ce5e5..95836478 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -270,10 +270,12 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.check_if_admin() - # Prepare success credential text - out = u'{}\\{} {}'.format(domain, - self.username, - highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) + out = u'{}\\{}{} {}'.format(domain, + self.username, + # Show what was used between cleartext, nthash, aesKey and ccache + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.extra['protocol'] = "LDAP" self.logger.extra['port'] = "389" if not self.args.gmsa else "636" @@ -284,16 +286,18 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if not self.args.continue_on_success: return True except SessionError as e: - self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, - self.password, + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(e)), color='red') return False except KeyError as e: - self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, - '', + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ''), color='red') except ldap_impacket.LDAPSessionError as e: @@ -310,8 +314,10 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.check_if_admin() # Prepare success credential text - out = u'{}\\{} {}'.format(domain, + out = u'{}\\{}{} {}'.format(domain, self.username, + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.extra['protocol'] = "LDAPS" @@ -324,9 +330,10 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey return True else: errorCode = str(e).split()[-2][:-1] - self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, - self.password, + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), color='magenta' if errorCode in ldap_error_status else 'red') diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index bc933c94..3d62e105 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -166,13 +166,16 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.create_conn_obj() logging.getLogger("impacket").disabled = True try: + nthash = '' hashes = None if ntlm_hash != '': if ntlm_hash.find(':') != -1: - hashes = ntlm_hash.split(':') + hashes = ntlm_hash + nthash = ntlm_hash.split(':')[1] else: # only nt hash hashes = ':%s' % ntlm_hash + nthash = ntlm_hash res = self.conn.kerberosLogin(None, username, password, domain, hashes, aesKey, kdcHost=kdcHost, useCache=useCache) if res is not True: @@ -184,8 +187,11 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.domain = domain self.check_if_admin() - out = u'{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', + out = u'{}{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', username, + # Show what was used between cleartext, nthash, aesKey and ccache + " from ccache" if useCache + else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -193,9 +199,12 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if not self.args.continue_on_success: return True except Exception as e: - self.logger.error(u'{}\\{} {}'.format(domain, - username, - e)) + self.logger.error(u'{}\\{}{} {}'.format('{}\\'.format(domain) if not self.args.local_auth else '', + username, + # Show what was used between cleartext, nthash, aesKey and ccache + " from ccache" if useCache + else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + e)) return False def plaintext_login(self, domain, username, password): diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 30c43e7c..4886728f 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -361,8 +361,12 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache) self.check_if_admin() - out = u'{}\\{} {}'.format(self.domain, - self.conn.getCredentials()[0], + getCreds = self.conn.getCredentials() + out = u'{}\\{}{} {}'.format(self.domain, + getCreds[0], + # Show what was used between cleartext, nthash, aesKey and ccache + " from ccache" if getCreds[6] is not None + else ":%s" % (next(sub for sub in [binascii.hexlify(getCreds[4]).decode(), getCreds[1], getCreds[5]] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -377,9 +381,10 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.create_conn_obj() except (SessionError, Exception) as e: error, desc = e.getErrorString() - self.logger.error(u'{}\\{}:{} {} {}'.format(domain, + self.logger.error(u'{}\\{}{} {} {}'.format(domain, self.username, - self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, + " from ccache" if getCreds[6] is not None + else ":%s" % (next(sub for sub in [binascii.hexlify(getCreds[4]).decode(), getCreds[1], getCreds[5]] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), error, '({})'.format(desc) if self.args.verbose else ''), color='magenta' if error in smb_error_status else 'red') From b9699ab07835c9aeeaf709207d6b9dda9b0b0f24 Mon Sep 17 00:00:00 2001 From: zblurx Date: Mon, 24 Oct 2022 14:55:07 +0200 Subject: [PATCH 14/20] fix output modifs on smb protocol --- cme/protocols/smb.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 4886728f..befe25e4 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -361,16 +361,15 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.conn.kerberosLogin(username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache) self.check_if_admin() - getCreds = self.conn.getCredentials() out = u'{}\\{}{} {}'.format(self.domain, - getCreds[0], + self.username, # Show what was used between cleartext, nthash, aesKey and ccache - " from ccache" if getCreds[6] is not None - else ":%s" % (next(sub for sub in [binascii.hexlify(getCreds[4]).decode(), getCreds[1], getCreds[5]] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + " from ccache" if useCache + else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: - add_user_bh(self.conn.getCredentials()[0], domain, self.logger, self.config) + add_user_bh(self.username, domain, self.logger, self.config) if not self.args.continue_on_success: return True elif self.signing: # check https://github.com/byt3bl33d3r/CrackMapExec/issues/321 @@ -383,8 +382,9 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey error, desc = e.getErrorString() self.logger.error(u'{}\\{}{} {} {}'.format(domain, self.username, - " from ccache" if getCreds[6] is not None - else ":%s" % (next(sub for sub in [binascii.hexlify(getCreds[4]).decode(), getCreds[1], getCreds[5]] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + # Show what was used between cleartext, nthash, aesKey and ccache + " from ccache" if useCache + else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), error, '({})'.format(desc) if self.args.verbose else ''), color='magenta' if error in smb_error_status else 'red') From 5040ab6b40397b5e5b772d0a6cf1f555f8076910 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 08:30:31 -0400 Subject: [PATCH 15/20] ldap try catch + magenta --- cme/protocols/ldap.py | 80 ++++++++++++++++++++++++++++++------------- cme/protocols/smb.py | 3 ++ 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 95836478..03025e25 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -34,7 +34,8 @@ "532":"STATUS_PASSWORD_EXPIRED", "773":"STATUS_PASSWORD_MUST_CHANGE", "775":"USER_ACCOUNT_LOCKED", - "50":"LDAP_INSUFFICIENT_ACCESS" + "50":"LDAP_INSUFFICIENT_ACCESS", + "KDC_ERR_CLIENT_REVOKED":"KDC_ERR_CLIENT_REVOKED" } @@ -286,12 +287,13 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if not self.args.continue_on_success: return True except SessionError as e: + error, desc = e.getErrorString() self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(e)), - color='red') + color='magenta' if error in ldap_error_status else 'red') return False except KeyError as e: self.logger.error(u'{}\\{}{} {}'.format(self.domain, @@ -300,34 +302,63 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ''), color='red') + return False except ldap_impacket.LDAPSessionError as e: if str(e).find('strongerAuthRequired') >= 0: # We need to try SSL - # Connect to LDAPS - self.ldapConnection = ldap_impacket.LDAPConnection('ldaps://%s' % target, self.baseDN) - self.ldapConnection.kerberosLogin(username, password, domain, self.lmhash, self.nthash, - aesKey, kdcHost=kdcHost, useCache=useCache) - - if self.username == '': - self.username = self.get_ldap_username() + try: + # Connect to LDAPS + self.ldapConnection = ldap_impacket.LDAPConnection('ldaps://%s' % target, self.baseDN) + self.ldapConnection.kerberosLogin(username, password, domain, self.lmhash, self.nthash, + aesKey, kdcHost=kdcHost, useCache=useCache) + + if self.username == '': + self.username = self.get_ldap_username() + + self.check_if_admin() - self.check_if_admin() + # Prepare success credential text + out = u'{}\\{}{} {}'.format(domain, + self.username, + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) + + if self.username == '': + self.username = self.get_ldap_username() - # Prepare success credential text - out = u'{}\\{}{} {}'.format(domain, - self.username, - " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), - highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) + self.check_if_admin() + + # Prepare success credential text + out = u'{}\\{} {}'.format(domain, + self.username, + highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) + + self.logger.extra['protocol'] = "LDAPS" + self.logger.extra['port'] = "636" + self.logger.success(out) - self.logger.extra['protocol'] = "LDAPS" - self.logger.extra['port'] = "636" - self.logger.success(out) - - if not self.args.local_auth: - add_user_bh(self.username, self.domain, self.logger, self.config) - if not self.args.continue_on_success: - return True + if not self.args.local_auth: + add_user_bh(self.username, self.domain, self.logger, self.config) + if not self.args.continue_on_success: + return True + except ldap_impacket.LDAPSessionError as e: + errorCode = str(e).split()[-2][:-1] + self.logger.error(u'{}\\{}:{} {}'.format(self.domain, + self.username, + self.password if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8, + ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), + color='magenta' if errorCode in ldap_error_status else 'red') + return False + except SessionError as e: + error, desc = e.getErrorString() + self.logger.error(u'{}\\{}{} {}'.format(self.domain, + self.username, + " from ccache" if useCache + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + str(e)), + color='magenta' if error in ldap_error_status else 'red') + return False else: errorCode = str(e).split()[-2][:-1] self.logger.error(u'{}\\{}{} {}'.format(self.domain, @@ -336,6 +367,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), color='magenta' if errorCode in ldap_error_status else 'red') + return False def plaintext_login(self, domain, username, password): self.username = username diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index befe25e4..bf1962e1 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -378,6 +378,9 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey except: pass self.create_conn_obj() + except FileNotFoundError as e: + self.logger.error('CCache Error: {}'.format(e)) + return False except (SessionError, Exception) as e: error, desc = e.getErrorString() self.logger.error(u'{}\\{}{} {} {}'.format(domain, From 70f8d973cf43a651dab0371a87428b9c1d35d039 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 09:01:30 -0400 Subject: [PATCH 16/20] add KDC_ERR_PREAUTH_FAILED error --- cme/protocols/ldap.py | 7 ++++--- cme/protocols/smb.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 03025e25..db6ac22f 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -35,7 +35,8 @@ "773":"STATUS_PASSWORD_MUST_CHANGE", "775":"USER_ACCOUNT_LOCKED", "50":"LDAP_INSUFFICIENT_ACCESS", - "KDC_ERR_CLIENT_REVOKED":"KDC_ERR_CLIENT_REVOKED" + "KDC_ERR_CLIENT_REVOKED":"KDC_ERR_CLIENT_REVOKED", + "KDC_ERR_PREAUTH_FAILED":"KDC_ERR_PREAUTH_FAILED" } @@ -292,7 +293,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, " from ccache" if useCache else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), - str(e)), + str(error)), color='magenta' if error in ldap_error_status else 'red') return False except KeyError as e: @@ -356,7 +357,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, " from ccache" if useCache else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), - str(e)), + str(error)), color='magenta' if error in ldap_error_status else 'red') return False else: diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index bf1962e1..7e3ce0c3 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -55,7 +55,8 @@ "STATUS_PASSWORD_MUST_CHANGE", "STATUS_ACCESS_DENIED", "STATUS_NO_SUCH_FILE", - "KDC_ERR_CLIENT_REVOKED" + "KDC_ERR_CLIENT_REVOKED", + "KDC_ERR_PREAUTH_FAILED" ] def get_error_string(exception): From b62bd670e08681dd68fdc87c6fe34709eb3a2cd4 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 09:11:45 -0400 Subject: [PATCH 17/20] Don't block if account not green --- cme/protocols/smb.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 7e3ce0c3..71095983 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -395,8 +395,6 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if error not in smb_error_status: self.inc_failed_login(username) return False - if not self.args.continue_on_success: - return True return False def plaintext_login(self, domain, username, password): @@ -443,8 +441,6 @@ def plaintext_login(self, domain, username, password): if error not in smb_error_status: self.inc_failed_login(username) return False - if not self.args.continue_on_success: - return True except (ConnectionResetError, NetBIOSTimeout, NetBIOSError) as e: self.logger.error('Connection Error: {}'.format(e)) return False @@ -508,8 +504,6 @@ def hash_login(self, domain, username, ntlm_hash): if error not in smb_error_status: self.inc_failed_login(self.username) return False - if not self.args.continue_on_success: - return True except (ConnectionResetError, NetBIOSTimeout, NetBIOSError) as e: self.logger.error('Connection Error: {}'.format(e)) return False From d61d6f0339aea7797cc95f64107e2091d6b48240 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 09:59:43 -0400 Subject: [PATCH 18/20] add new color for asreproast account --- cme/protocols/ldap.py | 30 +++++++++++++++++++++++------- cme/protocols/mssql.py | 4 ++-- cme/protocols/smb.py | 5 +++-- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index db6ac22f..86ab9001 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -16,7 +16,7 @@ from impacket.smbconnection import SMBConnection, SessionError from impacket.smb import SMB_DIALECT from impacket.dcerpc.v5.samr import UF_ACCOUNTDISABLE, UF_DONT_REQUIRE_PREAUTH, UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION -from impacket.krb5.kerberosv5 import sendReceive, KerberosError, getKerberosTGT, getKerberosTGS +from impacket.krb5.kerberosv5 import sendReceive, KerberosError, getKerberosTGT, getKerberosTGS, SessionKeyDecryptionError from impacket.krb5.types import KerberosTime, Principal from impacket.ldap import ldap as ldap_impacket from impacket.krb5 import constants @@ -260,6 +260,14 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey if lmhash: self.lmhash = lmhash if nthash: self.nthash = nthash + if self.password == '' and self.args.asreproast: + hash_TGT = KerberosAttacks(self).getTGT_asroast(self.username) + if hash_TGT: + self.logger.highlight(u'{}'.format(hash_TGT)) + with open(self.args.asreproast, 'a+') as hash_asreproast: + hash_asreproast.write(hash_TGT + '\n') + return False + try: # Connect to LDAP proto = "ldaps" if self.args.gmsa else "ldap" @@ -276,7 +284,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.extra['protocol'] = "LDAP" @@ -287,12 +295,20 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey add_user_bh(self.username, self.domain, self.logger, self.config) if not self.args.continue_on_success: return True + except SessionKeyDecryptionError: + # for PRE-AUTH account + self.logger.error(u'{}\\{}{} {}'.format(domain, + self.username, + " account vulnerable to asreproast attack", + ""), + color='yellow') + return False except SessionError as e: error, desc = e.getErrorString() self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next((sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None)) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(error)), color='magenta' if error in ldap_error_status else 'red') return False @@ -300,7 +316,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ''), color='red') return False @@ -322,7 +338,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey out = u'{}\\{}{} {}'.format(domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) if self.username == '': @@ -356,7 +372,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(error)), color='magenta' if error in ldap_error_status else 'red') return False @@ -365,7 +381,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), color='magenta' if errorCode in ldap_error_status else 'red') return False diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index 3d62e105..d3558945 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -191,7 +191,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -203,7 +203,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), e)) return False diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index 71095983..dbc971a7 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -19,6 +19,7 @@ from impacket.dcerpc.v5.dcom.wmi import WBEM_FLAG_FORWARD_ONLY from impacket.dcerpc.v5.samr import SID_NAME_USE from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED +from impacket.krb5.kerberosv5 import SessionKeyDecryptionError from cme.connection import * from cme.logger import CMEAdapter from cme.servers.smb import CMESMBServer @@ -366,7 +367,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -388,7 +389,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '') if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '' or sub != None or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), error, '({})'.format(desc) if self.args.verbose else ''), color='magenta' if error in smb_error_status else 'red') From 132332a8fd7e6a0cec55fcb6ab12b5d626d9c64e Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 24 Oct 2022 10:02:01 -0400 Subject: [PATCH 19/20] add new color for asreproast account smb --- cme/protocols/smb.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index dbc971a7..e1e7cf58 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -380,6 +380,14 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey except: pass self.create_conn_obj() + except SessionKeyDecryptionError: + # for PRE-AUTH account + self.logger.error(u'{}\\{}{} {}'.format(domain, + self.username, + " account vulnerable to asreproast attack", + ""), + color='yellow') + return False except FileNotFoundError as e: self.logger.error('CCache Error: {}'.format(e)) return False From 3942eab31b9f07a4a6f64a5679eab40ff18e76e5 Mon Sep 17 00:00:00 2001 From: mpgn Date: Mon, 31 Oct 2022 08:33:41 -0400 Subject: [PATCH 20/20] update a little bit --- cme/protocols/ldap.py | 17 +++++++++++------ cme/protocols/mssql.py | 32 +++++++++++++++++++------------- cme/protocols/smb.py | 9 +++++++-- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/cme/protocols/ldap.py b/cme/protocols/ldap.py index 86ab9001..3e752ad7 100644 --- a/cme/protocols/ldap.py +++ b/cme/protocols/ldap.py @@ -268,6 +268,11 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey hash_asreproast.write(hash_TGT + '\n') return False + if not all('' == s for s in [self.nthash, password, aesKey]): + kerb_pass = next(s for s in [self.nthash, password, aesKey] if s) + else: + kerb_pass = '' + try: # Connect to LDAP proto = "ldaps" if self.args.gmsa else "ldap" @@ -284,7 +289,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.extra['protocol'] = "LDAP" @@ -308,7 +313,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next((sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None)) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(error)), color='magenta' if error in ldap_error_status else 'red') return False @@ -316,7 +321,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ''), color='red') return False @@ -338,7 +343,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey out = u'{}\\{}{} {}'.format(domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) if self.username == '': @@ -372,7 +377,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), str(error)), color='magenta' if error in ldap_error_status else 'red') return False @@ -381,7 +386,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.logger.error(u'{}\\{}{} {}'.format(self.domain, self.username, " from ccache" if useCache - else ":%s" % (next(sub for sub in [self.nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), ldap_error_status[errorCode] if errorCode in ldap_error_status else ''), color='magenta' if errorCode in ldap_error_status else 'red') return False diff --git a/cme/protocols/mssql.py b/cme/protocols/mssql.py index d3558945..603f5046 100755 --- a/cme/protocols/mssql.py +++ b/cme/protocols/mssql.py @@ -24,6 +24,7 @@ def __init__(self, args, db, host): self.server_os = None self.hash = None self.os_arch = None + self.nthash = '' connection.__init__(self, args, db, host) @@ -165,18 +166,23 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey pass self.create_conn_obj() logging.getLogger("impacket").disabled = True - try: - nthash = '' - hashes = None - if ntlm_hash != '': - if ntlm_hash.find(':') != -1: - hashes = ntlm_hash - nthash = ntlm_hash.split(':')[1] - else: - # only nt hash - hashes = ':%s' % ntlm_hash - nthash = ntlm_hash + nthash = '' + hashes = None + if ntlm_hash != '': + if ntlm_hash.find(':') != -1: + hashes = ntlm_hash + nthash = ntlm_hash.split(':')[1] + else: + # only nt hash + hashes = ':%s' % ntlm_hash + nthash = ntlm_hash + + if not all('' == s for s in [self.nthash, password, aesKey]): + kerb_pass = next(s for s in [self.nthash, password, aesKey] if s) + else: + kerb_pass = '' + try: res = self.conn.kerberosLogin(None, username, password, domain, hashes, aesKey, kdcHost=kdcHost, useCache=useCache) if res is not True: self.conn.printReplies() @@ -191,7 +197,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -203,7 +209,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash, password, aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), e)) return False diff --git a/cme/protocols/smb.py b/cme/protocols/smb.py index e1e7cf58..ec2e500d 100755 --- a/cme/protocols/smb.py +++ b/cme/protocols/smb.py @@ -347,6 +347,11 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.create_conn_obj() lmhash = '' nthash = '' + if not all('' == s for s in [self.nthash, password, aesKey]): + kerb_pass = next(s for s in [self.nthash, password, aesKey] if s) + else: + kerb_pass = '' + try: if not self.args.laps: self.password = password @@ -367,7 +372,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '' or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (kerb_pass if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else '')) self.logger.success(out) if not self.args.local_auth: @@ -397,7 +402,7 @@ def kerberos_login(self, domain, username, password = '', ntlm_hash = '', aesKey self.username, # Show what was used between cleartext, nthash, aesKey and ccache " from ccache" if useCache - else ":%s" % (next(sub for sub in [nthash,password,aesKey] if sub != '' or sub != None or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), + else ":%s" % (next(sub for sub in [nthash,password,aesKey] if (sub != '' and sub != None) or sub != None) if not self.config.get('CME', 'audit_mode') else self.config.get('CME', 'audit_mode')*8), error, '({})'.format(desc) if self.args.verbose else ''), color='magenta' if error in smb_error_status else 'red')