Skip to content

Instantly share code, notes, and snippets.

@Margaruga
Created February 9, 2023 12:27
Show Gist options
  • Save Margaruga/a37abb82935b094e1c6ea47fb8bc9a3a to your computer and use it in GitHub Desktop.
Save Margaruga/a37abb82935b094e1c6ea47fb8bc9a3a to your computer and use it in GitHub Desktop.
# 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