Skip to content
Merged
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions nxc/protocols/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from dns import resolver
from dateutil.relativedelta import relativedelta as rd

from Cryptodome.Hash import MD4
from OpenSSL.SSL import SysCallError
from bloodhound.ad.authentication import ADAuthentication
from bloodhound.ad.domain import AD
Expand All @@ -28,6 +27,7 @@
SAM_MACHINE_ACCOUNT,
)
from impacket.krb5 import constants
from impacket.krb5.crypto import generate_kerberos_keys
from impacket.krb5.kerberosv5 import getKerberosTGS, SessionKeyDecryptionError
from impacket.krb5.ccache import CCache
from impacket.krb5.types import Principal, KerberosException
Expand Down Expand Up @@ -1329,16 +1329,26 @@ def gmsa(self):
principal_with_read = resp_parsed[0]["sAMAccountName"]

# Get the password
passwd = "<no read permissions>"
rc4 = "<no read permissions>"
aes128 = aes256 = ""
if "msDS-ManagedPassword" in acc:
blob = MSDS_MANAGEDPASSWORD_BLOB()
blob.fromString(acc["msDS-ManagedPassword"])
currentPassword = blob["CurrentPassword"][:-2]
ntlm_hash = MD4.new()
ntlm_hash.update(currentPassword)
passwd = hexlify(ntlm_hash.digest()).decode("utf-8")
self.logger.highlight(f"Account: {acc['sAMAccountName']:<20} NTLM: {passwd:<36} PrincipalsAllowedToReadPassword: {principal_with_read}")
return True
rc4, aes128, aes256 = self.gmsa_compute_secrets(acc["msDS-ManagedPassword"], acc["sAMAccountName"])
self.logger.highlight(f"Account: {acc['sAMAccountName']:<20} NTLM: {rc4:<36} PrincipalsAllowedToReadPassword: {principal_with_read}")
if aes128 and aes256:
self.logger.highlight(f"Account: {acc['sAMAccountName']:<20} aes128-cts-hmac-sha1-96: {aes128}")
self.logger.highlight(f"Account: {acc['sAMAccountName']:<20} aes256-cts-hmac-sha1-96: {aes256}")

def gmsa_compute_secrets(self, password_data: bytes, sAMAccountName: str):
"""Generate RC4, AES128, and AES256 keys for a GMSA account based on the provided password data and username."""
blob = MSDS_MANAGEDPASSWORD_BLOB()
blob.fromString(password_data)
currentPassword = hexlify(blob["CurrentPassword"].rstrip(b"\x00")).decode()
Comment thread
Marshall-Hallenbeck marked this conversation as resolved.
Outdated

keys = generate_kerberos_keys(hex_pass=currentPassword, user=sAMAccountName, domain=self.targetDomain)
Comment thread
NeffIsBack marked this conversation as resolved.
Outdated
rc4 = hexlify(keys[constants.EncryptionTypes.rc4_hmac.value].contents).decode()
aes128 = hexlify(keys[constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value].contents).decode()
aes256 = hexlify(keys[constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value].contents).decode()
return rc4, aes128, aes256

def decipher_gmsa_name(self, domain_name=None, account_name=None):
# https://aadinternals.com/post/gmsa/
Expand Down Expand Up @@ -1383,12 +1393,10 @@ def gmsa_decrypt_lsa(self):
if "_SC_GMSA_{84A78B8C" in self.args.gmsa_decrypt_lsa:
gmsa_id, gmsa_pass = self.args.gmsa_decrypt_lsa.split("_")[4].split(":")
# getting the gmsa account
search_filter = "(objectClass=msDS-GroupManagedServiceAccount)"
gmsa_accounts = self.ldap_connection.search(
gmsa_accounts = self.search(
searchBase=self.baseDN,
searchFilter=search_filter,
searchFilter="(objectClass=msDS-GroupManagedServiceAccount)",
attributes=["sAMAccountName"],
sizeLimit=0,
)
gmsa_accounts_parsed = parse_result_attributes(gmsa_accounts)
if gmsa_accounts_parsed:
Expand All @@ -1398,15 +1406,12 @@ def gmsa_decrypt_lsa(self):
if self.decipher_gmsa_name(self.domain.split(".")[0], acc["sAMAccountName"][:-1]) == gmsa_id:
gmsa_id = acc["sAMAccountName"]
break
# convert to ntlm
# Compute the password and keys
data = bytes.fromhex(gmsa_pass)
blob = MSDS_MANAGEDPASSWORD_BLOB()
blob.fromString(data)
currentPassword = blob["CurrentPassword"][:-2]
ntlm_hash = MD4.new()
ntlm_hash.update(currentPassword)
passwd = hexlify(ntlm_hash.digest()).decode("utf-8")
self.logger.highlight(f"Account: {gmsa_id:<20} NTLM: {passwd}")
rc4, aes128, aes256 = self.gmsa_compute_secrets(data, gmsa_id)
self.logger.highlight(f"Account: {gmsa_id:<20} NTLM: {rc4}")
Comment thread
NeffIsBack marked this conversation as resolved.
Outdated
self.logger.highlight(f"Account: {gmsa_id:<20} aes256-cts-hmac-sha1-96: {aes256}")
self.logger.highlight(f"Account: {gmsa_id:<20} aes128-cts-hmac-sha1-96: {aes128}")
Comment thread
NeffIsBack marked this conversation as resolved.
Outdated
else:
self.logger.fail("No string provided :'(")

Expand Down
Loading