Add new Windows LAPS
parent
295a1edd15
commit
95da356e3b
|
@ -11,9 +11,7 @@ class CMEModule:
|
|||
Initial module:
|
||||
@T3KX: https://github.com/T3KX/Crackmapexec-LAPS
|
||||
|
||||
Credit: @n00py1
|
||||
Reference: https://www.n00py.io/2020/12/dumping-laps-passwords-from-linux/
|
||||
https://github.com/n00py/LAPSDumper
|
||||
Credit: @mpgn_x64, @n00py1
|
||||
'''
|
||||
|
||||
name = 'laps'
|
||||
|
@ -34,20 +32,30 @@ class CMEModule:
|
|||
def on_login(self, context, connection):
|
||||
context.log.info('Getting LAPS Passwords')
|
||||
if self.computer is not None:
|
||||
searchFilter = '(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name=' + self.computer + '))'
|
||||
searchFilter = '(&(objectCategory=computer)(|(msLAPS-EncryptedPassword=*)(ms-MCS-AdmPwd=*)(msLAPS-Password=*))(name=' + self.computer + '))'
|
||||
else:
|
||||
searchFilter = '(&(objectCategory=computer)(ms-MCS-AdmPwd=*))'
|
||||
attributes = ['ms-MCS-AdmPwd', 'sAMAccountName']
|
||||
results = connection.search(searchFilter, attributes, 10000)
|
||||
searchFilter = '(&(objectCategory=computer)(|(msLAPS-EncryptedPassword=*)(ms-MCS-AdmPwd=*)(msLAPS-Password=*)))'
|
||||
attributes = ['msLAPS-EncryptedPassword', 'msLAPS-Password', 'ms-MCS-AdmPwd', 'sAMAccountName']
|
||||
results = connection.search(searchFilter, attributes, 0)
|
||||
results = [r for r in results if isinstance(r, ldapasn1_impacket.SearchResultEntry)]
|
||||
|
||||
laps_computers = []
|
||||
for computer in results:
|
||||
msMCSAdmPwd = ''
|
||||
sAMAccountName = ''
|
||||
values = {str(attr['type']).lower(): str(attr['vals'][0]) for attr in computer['attributes']}
|
||||
laps_computers.append((values['samaccountname'], values['ms-mcs-admpwd']))
|
||||
|
||||
laps_computers = sorted(laps_computers, key=lambda x: x[0])
|
||||
for sAMAccountName, msMCSAdmPwd in laps_computers:
|
||||
context.log.highlight("Computer: {:<20} Password: {}".format(sAMAccountName, msMCSAdmPwd))
|
||||
if len(results) != 0:
|
||||
laps_computers = []
|
||||
for computer in results:
|
||||
msMCSAdmPwd = ''
|
||||
sAMAccountName = ''
|
||||
values = {str(attr['type']).lower(): str(attr['vals'][0]) for attr in computer['attributes']}
|
||||
if "mslaps-encryptedpassword" in values:
|
||||
context.log.error("LAPS password is encrypted and currently CrackMapExec doesn't support the decryption...")
|
||||
return
|
||||
elif "mslaps-password" in values:
|
||||
r = json.loads(values['mslaps-password'])
|
||||
laps_computers.append((values['samaccountname'], r['n'], r['p']))
|
||||
elif "ms-mcs-admpwd" in values:
|
||||
laps_computers.append((values['samaccountname'], '', values['ms-mcs-admpwd']))
|
||||
else:
|
||||
context.log.error("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password")
|
||||
laps_computers = sorted(laps_computers, key=lambda x: x[0])
|
||||
for sAMAccountName, user, msMCSAdmPwd in laps_computers:
|
||||
context.log.highlight("Computer: {:<20} User: {:<15} Password: {}".format(sAMAccountName, user, msMCSAdmPwd))
|
||||
else:
|
||||
context.log.error("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password !")
|
||||
|
|
|
@ -347,6 +347,7 @@ class smb(connection):
|
|||
self.domain = self.hostname
|
||||
|
||||
def laps_search(self, username, password, ntlm_hash, domain):
|
||||
|
||||
self.logger.extra['protocol'] = "LDAP"
|
||||
self.logger.extra['port'] = "389"
|
||||
ldapco = LDAPConnect(self.domain, "389", self.domain)
|
||||
|
@ -371,12 +372,12 @@ class smb(connection):
|
|||
ntlm_hash[0] if ntlm_hash else ''
|
||||
)
|
||||
if not connection:
|
||||
logging.debug('LAPS connection failed with account {}'.format(username))
|
||||
self.logger.error('LDAP connection failed with account {}'.format(username))
|
||||
return False
|
||||
|
||||
search_filter = '(&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name=' + self.hostname + '))'
|
||||
attributes = ['ms-MCS-AdmPwd', 'samAccountname']
|
||||
result = connection.search(
|
||||
search_filter = '(&(objectCategory=computer)(|(msLAPS-EncryptedPassword=*)(ms-MCS-AdmPwd=*)(msLAPS-Password=*))(name=' + self.hostname + '))'
|
||||
attributes = ['msLAPS-EncryptedPassword', 'msLAPS-Password', 'ms-MCS-AdmPwd', 'sAMAccountName']
|
||||
results = connection.search(
|
||||
searchFilter=search_filter,
|
||||
attributes=attributes,
|
||||
sizeLimit=0
|
||||
|
@ -384,21 +385,35 @@ class smb(connection):
|
|||
|
||||
msMCSAdmPwd = ''
|
||||
sAMAccountName = ''
|
||||
for item in result:
|
||||
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
|
||||
continue
|
||||
for host in item['attributes']:
|
||||
if str(host['type']) == "sAMAccountName":
|
||||
sAMAccountName = str(host['vals'][0])
|
||||
else:
|
||||
msMCSAdmPwd = str(host['vals'][0])
|
||||
logging.debug("Host: {:<20} Password: {} {}".format(sAMAccountName, msMCSAdmPwd, self.hostname))
|
||||
username = ''
|
||||
|
||||
self.username = self.args.laps
|
||||
from impacket.ldap import ldapasn1 as ldapasn1_impacket
|
||||
results = [r for r in results if isinstance(r, ldapasn1_impacket.SearchResultEntry)]
|
||||
if len(results) != 0:
|
||||
for host in results:
|
||||
values = {str(attr['type']).lower(): str(attr['vals'][0]) for attr in host['attributes']}
|
||||
if "mslaps-encryptedpassword" in values:
|
||||
self.logger.error("LAPS password is encrypted and currently CrackMapExec doesn't support the decryption...")
|
||||
return False
|
||||
elif "mslaps-password" in values:
|
||||
from json import loads
|
||||
r = loads(values['mslaps-password'])
|
||||
msMCSAdmPwd = r['p']
|
||||
username = r['n']
|
||||
elif "ms-mcs-admpwd" in values:
|
||||
msMCSAdmPwd = values['ms-mcs-admpwd']
|
||||
else:
|
||||
self.logger.error("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password")
|
||||
logging.debug("Host: {:<20} Password: {} {}".format(sAMAccountName, msMCSAdmPwd, self.hostname))
|
||||
else:
|
||||
self.logger.error('msMCSAdmPwd or msLAPS-Password is empty or account cannot read LAPS property for {}'.format(self.hostname))
|
||||
return False
|
||||
|
||||
self.username = self.args.laps if not username else username
|
||||
self.password = msMCSAdmPwd
|
||||
|
||||
if msMCSAdmPwd == '':
|
||||
self.logger.error('msMCSAdmPwd is empty or account cannot read LAPS property for {}'.format(self.hostname))
|
||||
self.logger.error('msMCSAdmPwd or msLAPS-Password is empty or account cannot read LAPS property for {}'.format(self.hostname))
|
||||
return False
|
||||
if ntlm_hash:
|
||||
hash_ntlm = hashlib.new('md4', msMCSAdmPwd.encode('utf-16le')).digest()
|
||||
|
|
Loading…
Reference in New Issue