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

Commit 622245d

Browse files
author
mpgn
committed
Add support kerberos aesKey and kdcHost #22 add lssasy module kerberos support
add error when not credential foud on lsassy module #368
1 parent 52528a4 commit 622245d

File tree

7 files changed

+42
-28
lines changed

7 files changed

+42
-28
lines changed

cme/cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ def gen_cli_args():
4848
std_parser.add_argument("-u", metavar="USERNAME", dest='username', nargs='+', default=[], help="username(s) or file(s) containing usernames")
4949
std_parser.add_argument("-p", metavar="PASSWORD", dest='password', nargs='+', default=[], help="password(s) or file(s) containing passwords")
5050
std_parser.add_argument("-k", "--kerberos", action='store_true', help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
51+
std_parser.add_argument("--aesKey", action='store_true', help="AES key to use for Kerberos Authentication (128 or 256 bits)")
52+
std_parser.add_argument("--kdcHost", action='store_true', help="IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter")
53+
5154
fail_group = std_parser.add_mutually_exclusive_group()
5255
fail_group.add_argument("--gfail-limit", metavar='LIMIT', type=int, help='max number of global failed login attempts')
5356
fail_group.add_argument("--ufail-limit", metavar='LIMIT', type=int, help='max number of failed login attempts per username')

cme/connection.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ def __init__(self, args, db, host):
3131
self.password = ''
3232
self.username = ''
3333
self.kerberos = True if self.args.kerberos else False
34-
self.aesKey = None
35-
self.dc_ip = None
34+
self.aesKey = None if not self.args.aesKey else self.args.aesKey
35+
self.kdcHost = None if not self.args.kdcHost else self.args.kdcHost
3636
self.failed_logins = 0
3737
self.local_ip = None
3838

@@ -142,7 +142,7 @@ def over_fail_limit(self, username):
142142

143143
def login(self):
144144
if self.args.kerberos:
145-
if self.kerberos_login(): return True
145+
if self.kerberos_login(self.aesKey, self.kdcHost): return True
146146
else:
147147
for cred_id in self.args.cred_id:
148148
with sem:

cme/modules/lsassy.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def on_admin_login(self, context, connection):
7777
password = getattr(connection, "password", "")
7878
lmhash = getattr(connection, "lmhash", "")
7979
nthash = getattr(connection, "nthash", "")
80+
kerberos = getattr(connection, "kerberos", "")
8081

8182
password = "" if password is None else password
8283
lmhash = "" if lmhash is None else lmhash
@@ -102,6 +103,7 @@ def on_admin_login(self, context, connection):
102103
dump_options.dumpert_path = self.dumpert_path
103104

104105
lsassy = Lsassy(
106+
kerberos=kerberos,
105107
hostname=host,
106108
username=username,
107109
domain=domain_name,
@@ -114,13 +116,14 @@ def on_admin_login(self, context, connection):
114116
write_options=write_option
115117
)
116118
credentials = lsassy.get_credentials()
117-
118119
if not credentials['success']:
119120
context.log.error(credentials['error_msg'])
120121
if context.verbose and credentials['error_exception']:
121122
context.log.error(credentials['error_exception'])
122-
else:
123+
elif json.loads(credentials['credentials']).items():
123124
self.process_credentials(context, connection, credentials["credentials"])
125+
else:
126+
context.log.highlight("No credential found :'(")
124127

125128

126129
def process_credentials(self, context, connection, credentials):

cme/protocols/smb.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,22 @@ def print_host_info(self):
254254
self.domain,
255255
self.signing,
256256
self.smbv1))
257-
def kerberos_login(self):
258-
self.conn.kerberosLogin('', '', self.domain, self.lmhash, self.nthash, self.aesKey, self.dc_ip)
259-
# self.check_if_admin() # currently not working with kerberos so we set admin_privs to True
260-
self.admin_privs = True
261-
out = u'{}\\{} {}'.format(self.domain,
262-
self.conn.getCredentials()[0],
263-
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))
264-
self.logger.success(out)
265-
return True
257+
def kerberos_login(self, aesKey, kdcHost):
258+
try:
259+
self.conn.kerberosLogin('', '', self.domain, self.lmhash, self.nthash, aesKey, kdcHost)
260+
# self.check_if_admin() # currently not working with kerberos so we set admin_privs to True
261+
self.admin_privs = True
262+
out = u'{}\\{} {}'.format(self.domain,
263+
self.conn.getCredentials()[0],
264+
highlight('({})'.format(self.config.get('CME', 'pwn3d_label')) if self.admin_privs else ''))
265+
self.logger.success(out)
266+
return True
267+
except SessionError as e:
268+
error, desc = e.getErrorString()
269+
self.logger.error(u'{} {} {}'.format(self.domain,
270+
error,
271+
'({})'.format(desc) if self.args.verbose else ''))
272+
return False
266273

267274
def plaintext_login(self, domain, username, password):
268275
try:
@@ -410,7 +417,7 @@ def execute(self, payload=None, get_output=False, methods=None):
410417

411418
if method == 'wmiexec':
412419
try:
413-
exec_method = WMIEXEC(self.host, self.smb_share_name, self.username, self.password, self.domain, self.conn, self.kerberos, self.hash, self.args.share)
420+
exec_method = WMIEXEC(self.host, self.smb_share_name, self.username, self.password, self.domain, self.conn, self.kerberos, self.aesKey, self.kdcHost, self.hash, self.args.share)
414421
logging.debug('Executed command via wmiexec')
415422
break
416423
except:
@@ -430,7 +437,7 @@ def execute(self, payload=None, get_output=False, methods=None):
430437

431438
elif method == 'atexec':
432439
try:
433-
exec_method = TSCH_EXEC(self.host, self.smb_share_name, self.username, self.password, self.domain, self.kerberos, self.hash) #self.args.share)
440+
exec_method = TSCH_EXEC(self.host, self.smb_share_name, self.username, self.password, self.domain, self.kerberos, self.aesKey, self.kdcHost, self.hash) #self.args.share)
434441
logging.debug('Executed command via atexec')
435442
break
436443
except:
@@ -440,7 +447,7 @@ def execute(self, payload=None, get_output=False, methods=None):
440447

441448
elif method == 'smbexec':
442449
try:
443-
exec_method = SMBEXEC(self.host, self.smb_share_name, self.args.port, self.username, self.password, self.domain, self.kerberos, self.hash, self.args.share)
450+
exec_method = SMBEXEC(self.host, self.smb_share_name, self.args.port, self.username, self.password, self.domain, self.kerberos, self.aesKey, self.kdcHost, self.hash, self.args.share)
444451
logging.debug('Executed command via smbexec')
445452
break
446453
except:

cme/protocols/smb/atexec.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from gevent import sleep
88

99
class TSCH_EXEC:
10-
def __init__(self, target, share_name, username, password, domain, doKerberos=False, hashes=None):
10+
def __init__(self, target, share_name, username, password, domain, doKerberos=False, aesKey=None, kdcHost=None, hashes=None):
1111
self.__target = target
1212
self.__username = username
1313
self.__password = password
@@ -17,9 +17,9 @@ def __init__(self, target, share_name, username, password, domain, doKerberos=Fa
1717
self.__nthash = ''
1818
self.__outputBuffer = b''
1919
self.__retOutput = False
20-
# self.__aesKey = aesKey
20+
self.__aesKey = aesKey
2121
self.__doKerberos = doKerberos
22-
self.__kdcHost = None
22+
self.__kdcHost = kdcHost
2323

2424
if hashes is not None:
2525
#This checks to see if we didn't provide the LM Hash
@@ -36,7 +36,7 @@ def __init__(self, target, share_name, username, password, domain, doKerberos=Fa
3636

3737
if hasattr(self.__rpctransport, 'set_credentials'):
3838
# This method exists only for selected protocol sequences.
39-
self.__rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
39+
self.__rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)
4040
self.__rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost)
4141

4242
def execute(self, command, output=False):

cme/protocols/smb/smbexec.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class SMBEXEC:
1010

11-
def __init__(self, host, share_name, protocol, username = '', password = '', domain = '', doKerberos=False, hashes = None, share = None, port=445):
11+
def __init__(self, host, share_name, protocol, username = '', password = '', domain = '', doKerberos=False, aesKey=None, kdcHost=None, hashes = None, share = None, port=445):
1212
self.__host = host
1313
self.__share_name = share_name
1414
self.__port = port
@@ -28,9 +28,9 @@ def __init__(self, host, share_name, protocol, username = '', password = '', dom
2828
self.__scmr = None
2929
self.__conn = None
3030
# self.__mode = mode
31-
# self.__aesKey = aesKey
31+
self.__aesKey = aesKey
3232
self.__doKerberos = doKerberos
33-
self.__kdcHost = None
33+
self.__kdcHost = kdcHost
3434

3535
if hashes is not None:
3636
#This checks to see if we didn't provide the LM Hash
@@ -51,7 +51,7 @@ def __init__(self, host, share_name, protocol, username = '', password = '', dom
5151
self.__rpctransport.setRemoteHost(self.__host)
5252
if hasattr(self.__rpctransport, 'set_credentials'):
5353
# This method exists only for selected protocol sequences.
54-
self.__rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
54+
self.__rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,self.__aesKey)
5555
self.__rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost)
5656

5757
self.__scmr = self.__rpctransport.get_dce_rpc()

cme/protocols/smb/wmiexec.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from impacket.dcerpc.v5.dtypes import NULL
99

1010
class WMIEXEC:
11-
def __init__(self, target, share_name, username, password, domain, smbconnection, doKerberos=False, hashes=None, share=None):
11+
def __init__(self, target, share_name, username, password, domain, smbconnection, doKerberos=False, aesKey=None, kdcHost=None, hashes=None, share=None):
1212
self.__target = target
1313
self.__username = username
1414
self.__password = password
@@ -22,7 +22,8 @@ def __init__(self, target, share_name, username, password, domain, smbconnection
2222
self.__share_name = share_name
2323
self.__shell = 'cmd.exe /Q /c '
2424
self.__pwd = 'C:\\'
25-
self.__aesKey = None
25+
self.__aesKey = aesKey
26+
self.__kdcHost = kdcHost
2627
self.__doKerberos = doKerberos
2728
self.__retOutput = True
2829

@@ -35,7 +36,7 @@ def __init__(self, target, share_name, username, password, domain, smbconnection
3536

3637
if self.__password is None:
3738
self.__password = ''
38-
self.__dcom = DCOMConnection(self.__target, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos)
39+
self.__dcom = DCOMConnection(self.__target, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)
3940
iInterface = self.__dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login,wmi.IID_IWbemLevel1Login)
4041
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
4142
iWbemServices= iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)

0 commit comments

Comments
 (0)