Created
February 9, 2023 12:27
-
-
Save Margaruga/a37abb82935b094e1c6ea47fb8bc9a3a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Transform a msDS-ManagedPassword blob into keys | |
# Copy paste from different scripts | |
import base64 | |
from binascii import hexlify, unhexlify | |
from Cryptodome.Hash import MD4 | |
from impacket.ldap.ldaptypes import ACE, ACCESS_ALLOWED_OBJECT_ACE, ACCESS_MASK, LDAP_SID, SR_SECURITY_DESCRIPTOR | |
from impacket.structure import Structure | |
from impacket.krb5 import constants | |
from impacket.krb5.crypto import string_to_key, Key | |
from Cryptodome.Hash import MD4 | |
class MSDS_MANAGEDPASSWORD_BLOB(Structure): | |
structure = ( | |
('Version','<H'), | |
('Reserved','<H'), | |
('Length','<L'), | |
('CurrentPasswordOffset','<H'), | |
('PreviousPasswordOffset','<H'), | |
('QueryPasswordIntervalOffset','<H'), | |
('UnchangedPasswordIntervalOffset','<H'), | |
('CurrentPassword',':'), | |
('PreviousPassword',':'), | |
#('AlignmentPadding',':'), | |
('QueryPasswordInterval',':'), | |
('UnchangedPasswordInterval',':'), | |
) | |
def __init__(self, data = None): | |
Structure.__init__(self, data = data) | |
def fromString(self, data): | |
Structure.fromString(self,data) | |
if self['PreviousPasswordOffset'] == 0: | |
endData = self['QueryPasswordIntervalOffset'] | |
else: | |
endData = self['PreviousPasswordOffset'] | |
self['CurrentPassword'] = self.rawData[self['CurrentPasswordOffset']:][:endData - self['CurrentPasswordOffset']] | |
if self['PreviousPasswordOffset'] != 0: | |
self['PreviousPassword'] = self.rawData[self['PreviousPasswordOffset']:][:self['QueryPasswordIntervalOffset']-self['PreviousPasswordOffset']] | |
self['QueryPasswordInterval'] = self.rawData[self['QueryPasswordIntervalOffset']:][:self['UnchangedPasswordIntervalOffset']-self['QueryPasswordIntervalOffset']] | |
self['UnchangedPasswordInterval'] = self.rawData[self['UnchangedPasswordIntervalOffset']:] | |
allciphers = { | |
'rc4_hmac_nt': int(constants.EncryptionTypes.rc4_hmac.value), | |
'aes128_hmac': int(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value), | |
'aes256_hmac': int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value) | |
} | |
def printKerberosKeys(password, salt): | |
for name, cipher in allciphers.items(): | |
if cipher == 23: | |
md4 = MD4.new() | |
md4.update(password) | |
key = Key(cipher, md4.digest()) | |
else: | |
fixedPassword = password.decode('utf-16-le', 'replace').encode('utf-8', 'replace') | |
key = string_to_key(cipher, fixedPassword, salt) | |
print(f' * {name}: {hexlify(key.contents).decode("utf-8")}') | |
def printMachineKerberosKeys(domain, hostname, hexpassword): | |
salt = b'%shost%s.%s' % (domain.upper().encode('utf-8'), hostname.lower().encode('utf-8'), domain.lower().encode('utf-8')) | |
rawpassword = unhexlify(hexpassword) | |
print(f'{domain.upper()}\\{hostname.upper()}$') | |
print(f' * Salt: {salt.decode("utf-8")}') | |
printKerberosKeys(rawpassword, salt) | |
def printUserKerberosKeys(domain, username, rawpassword): | |
salt = b'%s%s' % (domain.upper().encode('utf-8'), username.encode('utf-8')) | |
rawpassword = rawpassword.encode('utf-16-le') | |
print(f'{domain.upper()}\\{username}') | |
print(f' * Salt: {salt.decode("utf-8")}') | |
printKerberosKeys(rawpassword, salt) | |
data = "" # Base64 blob | |
data = base64.b64decode(data) | |
blob = MSDS_MANAGEDPASSWORD_BLOB() | |
blob.fromString(data) | |
currentPassword = blob['CurrentPassword'][:-2] | |
printMachineKerberosKeys( | |
domain='contoso.local', | |
hostname='gMSA-SVC-1', | |
hexpassword=hexlify(currentPassword) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment