Skip to content

Commit

Permalink
Added support for "export" hive format + compute bootkey from class n…
Browse files Browse the repository at this point in the history
…ames
  • Loading branch information
MaxToffy committed Oct 21, 2024
1 parent 65b774d commit 6c1c618
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 18 deletions.
5 changes: 4 additions & 1 deletion examples/registry-read.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,16 @@ def main():
walk_parser = subparsers.add_parser('walk', help='walks the registry from the name node down')
walk_parser.add_argument('-name', action='store', required=True, help='registry class name to start walking down from')

# Hive format
parser.add_argument('-format', action='store', choices=['save', 'export'], default='save',help="Hive format, either 'save' or 'export' (default: 'save')")

if len(sys.argv)==1:
parser.print_help()
sys.exit(1)

options = parser.parse_args()

reg = winregistry.Registry(options.hive)
reg = winregistry.Registry(options.hive,hiveFormat = options.format)

if options.action.upper() == 'ENUM_KEY':
print("[%s]" % options.name)
Expand Down
54 changes: 44 additions & 10 deletions examples/secretsdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,14 @@ def __init__(self, remoteName, username='', password='', domain='', options=None
self.__rodc = options.rodcNo
self.__systemHive = options.system
self.__bootkey = options.bootkey
self.__jdClass = options.lsa_jd
self.__skew1Class = options.lsa_skew1
self.__gbgClass = options.lsa_gbg
self.__dataClass = options.lsa_data
self.__securityHive = options.security
self.__securityHiveExport = options.security_export
self.__samHive = options.sam
self.__samHiveExport = options.sam_export
self.__ntdsFile = options.ntds
self.__skipSam = options.skip_sam
self.__skipSecurity = options.skip_security
Expand Down Expand Up @@ -170,6 +176,19 @@ def ldapConnect(self):
self.__aesKey, kdcHost=self.__kdcHost)
else:
raise

def getBootKey(self, jdClass, skew1Class, gbgClass, dataClass):
import binascii
bootKey = b''
tmpKey = jdClass.encode('utf-8') + skew1Class.encode('utf-8') + gbgClass.encode('utf-8') + dataClass.encode('utf-8')
transforms = [8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7]
tmpKey = binascii.unhexlify(tmpKey)
for i in range(len(tmpKey)):
bootKey += tmpKey[transforms[i]:transforms[i] + 1]

logging.info('Target system bootKey: 0x%s' % binascii.hexlify(bootKey).decode('utf-8'))

return bootKey

def dump(self):
try:
Expand Down Expand Up @@ -217,10 +236,11 @@ def dump(self):
if self.__ntdsFile is not None:
# Let's grab target's configuration about LM Hashes storage
self.__noLMHash = localOperations.checkNoLMHashPolicy()
else:
elif self.__bootkey:
import binascii
bootKey = binascii.unhexlify(self.__bootkey)

elif self.__jdClass and self.__skew1Class and self.__gbgClass and self.__dataClass:
bootKey = self.getBootKey(self.__jdClass, self.__skew1Class, self.__gbgClass, self.__dataClass)
else:
self.__isRemote = True
bootKey = None
Expand Down Expand Up @@ -274,10 +294,14 @@ def dump(self):
try:
if self.__isRemote is True:
SAMFileName = self.__remoteOps.saveSAM()
else:
elif self.__samHive:
SAMFileName = self.__samHive
samFormat = "save"
elif self.__samHiveExport:
SAMFileName = self.__samHiveExport
samFormat = "export"

self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote)
self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote, format = samFormat)
self.__SAMHashes.dump()
if self.__outputFileName is not None:
self.__SAMHashes.export(self.__outputFileName)
Expand All @@ -288,11 +312,15 @@ def dump(self):
try:
if self.__isRemote is True:
SECURITYFileName = self.__remoteOps.saveSECURITY()
else:
elif self.__securityHive:
SECURITYFileName = self.__securityHive
securityFormat = "save"
elif self.__securityHiveExport:
SECURITYFileName = self.__securityHiveExport
securityFormat = "export"

self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps,
isRemote=self.__isRemote, history=self.__history)
isRemote=self.__isRemote, history=self.__history, format = securityFormat)
self.__LSASecrets.dumpCachedHashes()
if self.__outputFileName is not None:
self.__LSASecrets.exportCached(self.__outputFileName)
Expand Down Expand Up @@ -400,8 +428,14 @@ def cleanup(self):
parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
parser.add_argument('-system', action='store', help='SYSTEM hive to parse')
parser.add_argument('-bootkey', action='store', help='bootkey for SYSTEM hive')
parser.add_argument('-security', action='store', help='SECURITY hive to parse')
parser.add_argument('-sam', action='store', help='SAM hive to parse')
parser.add_argument('-lsa-jd', action='store', help='Class name of HKLM\SYSTEM\CurrentControlSet\Control\Lsa\JD to compute the bootkey')
parser.add_argument('-lsa-skew1', action='store', help='Class name of HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Skew1 to compute the bootkey')
parser.add_argument('-lsa-gbg', action='store', help='Class name of HKLM\SYSTEM\CurrentControlSet\Control\Lsa\GBG to compute the bootkey')
parser.add_argument('-lsa-data', action='store', help='Class name of HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Data to compute the bootkey')
parser.add_argument('-security', action='store', help='SECURITY hive to parse in "save" format')
parser.add_argument('-security-export', action='store', help='SECURITY hive to parse in "export" format')
parser.add_argument('-sam', action='store', help='SAM hive to parse in "save" format')
parser.add_argument('-sam-export', action='store', help='SAM hive to parse in "export" format')
parser.add_argument('-ntds', action='store', help='NTDS.DIT file to parse')
parser.add_argument('-resumefile', action='store', help='resume file name to resume NTDS.DIT session dump (only '
'available to DRSUAPI approach). This file will also be used to keep updating the session\'s '
Expand Down Expand Up @@ -506,8 +540,8 @@ def cleanup(self):
sys.exit(1)

if remoteName.upper() == 'LOCAL' and username == '':
if options.system is None and options.bootkey is None:
logging.error('Either the SYSTEM hive or bootkey is required for local parsing, check help')
if options.system is None and options.bootkey is None and (options.lsa_jd is None or options.lsa_skew1 is None or options.lsa_gbg is None or options.lsa_data is None):
logging.error('Either the SYSTEM hive, bootkey or the LSA\'s class names is required for local parsing, check help')
sys.exit(1)
else:

Expand Down
12 changes: 6 additions & 6 deletions impacket/examples/secretsdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -1293,10 +1293,10 @@ def decryptAES(key, value, iv=b'\x00'*16):


class OfflineRegistry:
def __init__(self, hiveFile = None, isRemote = False):
def __init__(self, hiveFile = None, isRemote = False, format = "save"):
self.__hiveFile = hiveFile
if self.__hiveFile is not None:
self.__registryHive = winregistry.Registry(self.__hiveFile, isRemote)
self.__registryHive = winregistry.Registry(self.__hiveFile, isRemote, format)

def enumKey(self, searchKey):
parentKey = self.__registryHive.findKey(searchKey)
Expand Down Expand Up @@ -1340,8 +1340,8 @@ def finish(self):
self.__registryHive.close()

class SAMHashes(OfflineRegistry):
def __init__(self, samFile, bootKey, isRemote = False, perSecretCallback = lambda secret: _print_helper(secret)):
OfflineRegistry.__init__(self, samFile, isRemote)
def __init__(self, samFile, bootKey, isRemote = False, format = "save", perSecretCallback = lambda secret: _print_helper(secret)):
OfflineRegistry.__init__(self, samFile, isRemote, format)
self.__samFile = samFile
self.__hashedBootKey = b''
self.__bootKey = bootKey
Expand Down Expand Up @@ -1488,9 +1488,9 @@ class SECRET_TYPE:
LSA_RAW = 2
LSA_KERBEROS = 3

def __init__(self, securityFile, bootKey, remoteOps=None, isRemote=False, history=False,
def __init__(self, securityFile, bootKey, remoteOps=None, isRemote=False, history=False, format = "save",
perSecretCallback=lambda secretType, secret: _print_helper(secret)):
OfflineRegistry.__init__(self, securityFile, isRemote)
OfflineRegistry.__init__(self, securityFile, isRemote, format)
self.__hashedBootKey = b''
self.__bootKey = bootKey
self.__LSAKey = b''
Expand Down
Loading

0 comments on commit 6c1c618

Please sign in to comment.