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

Commit a36d314

Browse files
author
mpgn
authored
Merge pull request #655 from zblurx/master
Fix kerberos authentication and add kerbrute
2 parents fedbfaf + 3942eab commit a36d314

File tree

5 files changed

+429
-198
lines changed

5 files changed

+429
-198
lines changed

cme/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def gen_cli_args():
4949
std_parser.add_argument('-id', metavar="CRED_ID", nargs='+', default=[], type=str, dest='cred_id', help='database credential ID(s) to use for authentication')
5050
std_parser.add_argument("-u", metavar="USERNAME", dest='username', nargs='+', default=[], help="username(s) or file(s) containing usernames")
5151
std_parser.add_argument("-p", metavar="PASSWORD", dest='password', nargs='+', default=[], help="password(s) or file(s) containing passwords")
52-
std_parser.add_argument("-k", "--kerberos", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
52+
std_parser.add_argument("-k", "--kerberos", action='store_true', help="Use Kerberos authentication")
53+
std_parser.add_argument("--use-kcache", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
5354
std_parser.add_argument("--export", metavar="EXPORT", nargs='+', help="Export result into a file, probably buggy")
5455
std_parser.add_argument("--aesKey", metavar="AESKEY", nargs='+', help="AES key to use for Kerberos Authentication (128 or 256 bits)")
5556
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")

cme/connection.py

Lines changed: 146 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -162,120 +162,150 @@ def over_fail_limit(self, username):
162162
return False
163163

164164
def login(self):
165-
if self.args.kerberos:
166-
if self.kerberos_login(self.domain, self.aesKey, self.kdcHost): return True
167-
else:
168-
for cred_id in self.args.cred_id:
169-
with sem:
170-
if cred_id.lower() == 'all':
171-
creds = self.db.get_credentials()
172-
else:
173-
creds = self.db.get_credentials(filterTerm=int(cred_id))
174-
175-
for cred in creds:
176-
logging.debug(cred)
177-
try:
178-
c_id, domain, username, password, credtype, pillaged_from = cred
179-
180-
if credtype and password:
181-
182-
if not domain: domain = self.domain
183-
184-
if self.args.local_auth:
185-
domain = self.domain
186-
elif self.args.domain:
187-
domain = self.args.domain
188-
189-
if credtype == 'hash' and not self.over_fail_limit(username):
190-
if self.hash_login(domain, username, password): return True
191-
192-
elif credtype == 'plaintext' and not self.over_fail_limit(username):
193-
if self.plaintext_login(domain, username, password): return True
194-
195-
except IndexError:
196-
self.logger.error("Invalid database credential ID!")
197-
198-
for user in self.args.username:
199-
if isfile(user):
200-
with open(user, 'r') as user_file:
201-
for usr in user_file:
202-
if "\\" in usr:
203-
tmp = usr
204-
usr = tmp.split('\\')[1].strip()
205-
self.domain = tmp.split('\\')[0]
206-
if hasattr(self.args, 'hash') and self.args.hash:
207-
with sem:
208-
for ntlm_hash in self.args.hash:
209-
if isfile(ntlm_hash):
210-
with open(ntlm_hash, 'r') as ntlm_hash_file:
211-
if self.args.no_bruteforce == False:
212-
for f_hash in ntlm_hash_file:
213-
if not self.over_fail_limit(usr.strip()):
214-
if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
215-
elif self.args.no_bruteforce == True:
216-
user_file.seek(0) # HACK: this should really not be in the usr for loop
217-
for usr, f_hash in zip(user_file, ntlm_hash_file):
218-
if not self.over_fail_limit(usr.strip()):
219-
if self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
220-
else: # ntlm_hash is a string
221-
if not self.over_fail_limit(usr.strip()):
222-
if self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True
223-
224-
elif self.args.password:
225-
with sem:
226-
for password in self.args.password:
227-
if isfile(password):
228-
with open(password, 'r') as password_file:
229-
if self.args.no_bruteforce == False:
230-
for f_pass in password_file:
231-
if not self.over_fail_limit(usr.strip()):
232-
if hasattr(self.args, 'domain'):
233-
if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
234-
else:
235-
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
236-
elif self.args.no_bruteforce == True:
237-
user_file.seek(0) # HACK: this should really not be in the usr for loop
238-
for usr, f_pass in zip(user_file, password_file):
239-
if not self.over_fail_limit(usr.strip()):
240-
if hasattr(self.args, 'domain'):
241-
if self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
242-
else:
243-
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
244-
else: # password is a string
245-
if not self.over_fail_limit(usr.strip()):
246-
if hasattr(self.args, 'domain'):
247-
if self.plaintext_login(self.domain, usr.strip(), password): return True
248-
else:
249-
if self.plaintext_login(usr.strip(), password): return True
250-
251-
else: # user is a string
252-
if hasattr(self.args, 'hash') and self.args.hash:
253-
with sem:
254-
for ntlm_hash in self.args.hash:
255-
if isfile(ntlm_hash):
256-
with open(ntlm_hash, 'r') as ntlm_hash_file:
257-
for f_hash in ntlm_hash_file:
258-
if not self.over_fail_limit(user):
259-
if self.hash_login(self.domain, user, f_hash.strip()): return True
260-
else: # ntlm_hash is a string
261-
if not self.over_fail_limit(user):
262-
if self.hash_login(self.domain, user, ntlm_hash.strip()): return True
263-
264-
elif self.args.password:
265-
with sem:
266-
for password in self.args.password:
267-
if isfile(password):
268-
with open(password, 'r') as password_file:
269-
for f_pass in password_file:
270-
if not self.over_fail_limit(user):
271-
if hasattr(self.args, 'domain'):
272-
if self.plaintext_login(self.domain, user, f_pass.strip()): return True
273-
else:
274-
if self.plaintext_login(user, f_pass.strip()): return True
275-
else: # password is a string
276-
if not self.over_fail_limit(user):
277-
if hasattr(self.args, 'domain'):
278-
if self.plaintext_login(self.domain, user, password): return True
279-
else:
280-
if self.plaintext_login(user, password): return True
165+
for cred_id in self.args.cred_id:
166+
with sem:
167+
if cred_id.lower() == 'all':
168+
creds = self.db.get_credentials()
169+
else:
170+
creds = self.db.get_credentials(filterTerm=int(cred_id))
171+
for cred in creds:
172+
logging.debug(cred)
173+
try:
174+
c_id, domain, username, password, credtype, pillaged_from = cred
175+
176+
if credtype and password:
177+
178+
if not domain: domain = self.domain
179+
180+
if self.args.local_auth:
181+
domain = self.domain
182+
elif self.args.domain:
183+
domain = self.args.domain
184+
185+
if credtype == 'hash' and not self.over_fail_limit(username):
186+
if self.args.kerberos:
187+
if self.kerberos_login(domain, username, '', password, '', self.kdcHost, False): return True
188+
elif self.hash_login(domain, username, password): return True
189+
190+
elif credtype == 'plaintext' and not self.over_fail_limit(username):
191+
if self.args.kerberos:
192+
if self.kerberos_login(domain, username, password, '' , '', self.kdcHost, False): return True
193+
elif self.plaintext_login(domain, username, password): return True
194+
195+
except IndexError:
196+
self.logger.error("Invalid database credential ID!")
197+
if self.args.use_kcache:
198+
with sem:
199+
if self.kerberos_login(self.domain, '', '', '', '', self.kdcHost, True): return True
200+
for user in self.args.username:
201+
if isfile(user):
202+
with open(user, 'r') as user_file:
203+
for usr in user_file:
204+
if "\\" in usr:
205+
tmp = usr
206+
usr = tmp.split('\\')[1].strip()
207+
self.domain = tmp.split('\\')[0]
208+
if hasattr(self.args, 'hash') and self.args.hash:
209+
with sem:
210+
for ntlm_hash in self.args.hash:
211+
if isfile(ntlm_hash):
212+
with open(ntlm_hash, 'r') as ntlm_hash_file:
213+
if self.args.no_bruteforce == False:
214+
for f_hash in ntlm_hash_file:
215+
if not self.over_fail_limit(usr.strip()):
216+
if self.args.kerberos:
217+
if self.kerberos_login(self.domain, usr.strip(), '', f_hash.strip(), '', self.kdcHost, False): return True
218+
elif self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
219+
elif self.args.no_bruteforce == True:
220+
user_file.seek(0) # HACK: this should really not be in the usr for loop
221+
for usr, f_hash in zip(user_file, ntlm_hash_file):
222+
if not self.over_fail_limit(usr.strip()):
223+
if self.args.kerberos:
224+
if self.kerberos_login(self.domain, usr.strip(), '', f_hash.strip(), '', self.kdcHost, False): return True
225+
elif self.hash_login(self.domain, usr.strip(), f_hash.strip()): return True
226+
else: # ntlm_hash is a string
227+
if not self.over_fail_limit(usr.strip()):
228+
if self.args.kerberos:
229+
if self.kerberos_login(self.domain, usr.strip(), '', ntlm_hash.strip(), '', self.kdcHost, False): return True
230+
elif self.hash_login(self.domain, usr.strip(), ntlm_hash.strip()): return True
231+
232+
elif self.args.password:
233+
with sem:
234+
for password in self.args.password:
235+
if isfile(password):
236+
with open(password, 'r') as password_file:
237+
if self.args.no_bruteforce == False:
238+
for f_pass in password_file:
239+
if not self.over_fail_limit(usr.strip()):
240+
if hasattr(self.args, 'domain'):
241+
if self.args.kerberos:
242+
if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True
243+
elif self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
244+
else:
245+
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
246+
elif self.args.no_bruteforce == True:
247+
user_file.seek(0) # HACK: this should really not be in the usr for loop
248+
for usr, f_pass in zip(user_file, password_file):
249+
if not self.over_fail_limit(usr.strip()):
250+
if hasattr(self.args, 'domain'):
251+
if self.args.kerberos:
252+
if self.kerberos_login(self.domain, usr.strip(), f_pass.strip(), '', '', self.kdcHost, False): return True
253+
elif self.plaintext_login(self.domain, usr.strip(), f_pass.strip()): return True
254+
else:
255+
if self.plaintext_login(usr.strip(), f_pass.strip()): return True
256+
else: # password is a string
257+
if not self.over_fail_limit(usr.strip()):
258+
if hasattr(self.args, 'domain'):
259+
if self.args.kerberos:
260+
if self.kerberos_login(self.domain, usr.strip(), password, '', '', self.kdcHost, False): return True
261+
elif self.plaintext_login(self.domain, usr.strip(), password): return True
262+
else:
263+
if self.plaintext_login(usr.strip(), password): return True
264+
265+
else: # user is a string
266+
if hasattr(self.args, 'hash') and self.args.hash:
267+
with sem:
268+
for ntlm_hash in self.args.hash:
269+
if isfile(ntlm_hash):
270+
with open(ntlm_hash, 'r') as ntlm_hash_file:
271+
for f_hash in ntlm_hash_file:
272+
if not self.over_fail_limit(user):
273+
if self.args.kerberos:
274+
if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True
275+
elif self.hash_login(self.domain, user, f_hash.strip()): return True
276+
else: # ntlm_hash is a string
277+
if not self.over_fail_limit(user):
278+
if self.args.kerberos:
279+
if self.kerberos_login(self.domain, user, '', ntlm_hash.strip(), '', self.kdcHost, False): return True
280+
elif self.hash_login(self.domain, user, ntlm_hash.strip()): return True
281+
282+
elif self.args.password:
283+
with sem:
284+
for password in self.args.password:
285+
if isfile(password):
286+
with open(password, 'r') as password_file:
287+
for f_pass in password_file:
288+
if not self.over_fail_limit(user):
289+
if hasattr(self.args, 'domain'):
290+
if self.args.kerberos:
291+
if self.kerberos_login(self.domain, user, f_pass.strip(), '', '', self.kdcHost, False): return True
292+
elif self.plaintext_login(self.domain, user, f_pass.strip()): return True
293+
else:
294+
if self.plaintext_login(user, f_pass.strip()): return True
295+
else: # password is a string
296+
if not self.over_fail_limit(user):
297+
if hasattr(self.args, 'domain'):
298+
if self.args.kerberos:
299+
if self.kerberos_login(self.domain, user, password, '', '', self.kdcHost, False): return True
300+
elif self.plaintext_login(self.domain, user, password): return True
301+
else:
302+
if self.plaintext_login(user, password): return True
303+
304+
elif self.args.aesKey:
305+
with sem:
306+
for aesKey in self.args.aesKey:
307+
if not self.over_fail_limit(user):
308+
if self.kerberos_login(self.domain, user, '', '', aesKey.strip(), self.kdcHost, False): return True
309+
310+
281311

0 commit comments

Comments
 (0)