From 4f946156448f4cc8427c44e47e57ffb218575c35 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Fri, 7 Mar 2025 22:42:58 +0000 Subject: [PATCH 1/6] Bring hash dumping plugins up to current coding standards and error checking patterns. Fix bugs and typing --- .../framework/plugins/windows/cachedump.py | 6 +-- .../framework/plugins/windows/hashdump.py | 34 +++++++++++++---- .../framework/plugins/windows/lsadump.py | 37 +++++++++++-------- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/volatility3/framework/plugins/windows/cachedump.py b/volatility3/framework/plugins/windows/cachedump.py index ef4096b42..bcc1fac7f 100644 --- a/volatility3/framework/plugins/windows/cachedump.py +++ b/volatility3/framework/plugins/windows/cachedump.py @@ -22,7 +22,7 @@ class Cachedump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 0, 1) + _version = (2, 0, 0) @classmethod def get_requirements(cls): @@ -36,10 +36,10 @@ class Cachedump(interfaces.plugins.PluginInterface): name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0) ), requirements.PluginRequirement( - name="lsadump", plugin=lsadump.Lsadump, version=(1, 0, 0) + name="lsadump", plugin=lsadump.Lsadump, version=(2, 0, 0) ), requirements.PluginRequirement( - name="hashdump", plugin=hashdump.Hashdump, version=(1, 1, 0) + name="hashdump", plugin=hashdump.Hashdump, version=(2, 0, 0) ), ] diff --git a/volatility3/framework/plugins/windows/hashdump.py b/volatility3/framework/plugins/windows/hashdump.py index fa4081366..9577326ae 100644 --- a/volatility3/framework/plugins/windows/hashdump.py +++ b/volatility3/framework/plugins/windows/hashdump.py @@ -9,7 +9,7 @@ from typing import List, Optional, Tuple from Crypto.Cipher import AES, ARC4, DES -from volatility3.framework import interfaces, renderers +from volatility3.framework import interfaces, renderers, exceptions from volatility3.framework.configuration import requirements from volatility3.framework.symbols.windows.extensions import registry from volatility3.plugins.windows.registry import hivelist @@ -21,7 +21,7 @@ class Hashdump(interfaces.plugins.PluginInterface): """Dumps user hashes from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 1, 0) + _version = (2, 0, 0) @classmethod def get_requirements(cls): @@ -326,7 +326,9 @@ class Hashdump(interfaces.plugins.PluginInterface): empty_nt = b"\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0" @classmethod - def get_hive_key(cls, hive: registry.RegistryHive, key: str): + def get_hive_key( + cls, hive: registry.RegistryHive, key: str + ) -> Optional["registry.CM_KEY_NODE"]: result = None try: if hive: @@ -351,6 +353,9 @@ class Hashdump(interfaces.plugins.PluginInterface): @classmethod def get_bootkey(cls, syshive: registry.RegistryHive) -> Optional[bytes]: + """ + Returns the scrambled bootkey necesary to decrypt hashes + """ cs = 1 lsa_base = f"ControlSet{cs:03}" + "\\Control\\Lsa" lsa_keys = ["JD", "Skew1", "GBG", "Data"] @@ -366,7 +371,10 @@ class Hashdump(interfaces.plugins.PluginInterface): key = cls.get_hive_key(syshive, lsa_base + "\\" + lk) class_data = None if key: - class_data = syshive.read(key.Class + 4, key.ClassLength) + try: + class_data = syshive.read(key.Class + 4, key.ClassLength) + except exceptions.InvalidAddressException: + return None if class_data is None: return None @@ -394,7 +402,11 @@ class Hashdump(interfaces.plugins.PluginInterface): sam_data = None for v in sam_account_key.get_values(): if v.get_name() == "F": - sam_data = samhive.read(v.Data + 4, v.DataLength) + try: + sam_data = samhive.read(v.Data + 4, v.DataLength) + except exceptions.InvalidAddressException: + return None + if not sam_data: return None @@ -444,7 +456,11 @@ class Hashdump(interfaces.plugins.PluginInterface): sam_data = None for v in user.get_values(): if v.get_name() == "V": - sam_data = samhive.read(v.Data + 4, v.DataLength) + try: + sam_data = samhive.read(v.Data + 4, v.DataLength) + except exceptions.InvalidAddressException: + return None + if not sam_data: return None @@ -546,7 +562,11 @@ class Hashdump(interfaces.plugins.PluginInterface): value = None for v in user.get_values(): if v.get_name() == "V": - value = samhive.read(v.Data + 4, v.DataLength) + try: + value = samhive.read(v.Data + 4, v.DataLength) + except exceptions.InvalidAddressException: + return None + if not value: return None diff --git a/volatility3/framework/plugins/windows/lsadump.py b/volatility3/framework/plugins/windows/lsadump.py index ac2b678f6..0d23dda0a 100644 --- a/volatility3/framework/plugins/windows/lsadump.py +++ b/volatility3/framework/plugins/windows/lsadump.py @@ -22,7 +22,7 @@ class Lsadump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 0, 0) + _version = (2, 0, 0) @classmethod def get_requirements(cls): @@ -33,7 +33,7 @@ class Lsadump(interfaces.plugins.PluginInterface): architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( - name="hashdump", component=hashdump.Hashdump, version=(1, 1, 0) + name="hashdump", component=hashdump.Hashdump, version=(2, 0, 0) ), requirements.VersionRequirement( name="hivelist", component=hivelist.HiveList, version=(2, 0, 0) @@ -76,8 +76,7 @@ class Lsadump(interfaces.plugins.PluginInterface): enc_reg_key = hashdump.Hashdump.get_hive_key(sechive, "Policy\\" + policy_key) if not enc_reg_key: return None - enc_reg_value = next(enc_reg_key.get_values()) - + enc_reg_value = next(enc_reg_key.get_values(), None) if not enc_reg_value: return None @@ -112,18 +111,22 @@ class Lsadump(interfaces.plugins.PluginInterface): name: str, lsakey: bytes, is_vista_or_later: bool, - ): + ) -> Optional[bytes]: enc_secret_key = hashdump.Hashdump.get_hive_key( sechive, "Policy\\Secrets\\" + name + "\\CurrVal" ) secret = None if enc_secret_key: - enc_secret_value = next(enc_secret_key.get_values()) + enc_secret_value = next(enc_secret_key.get_values(), None) if enc_secret_value: - enc_secret = sechive.read( - enc_secret_value.Data + 4, enc_secret_value.DataLength - ) + try: + enc_secret = sechive.read( + enc_secret_value.Data + 4, enc_secret_value.DataLength + ) + except exceptions.InvalidAddressExceptions: + return None + if enc_secret: if not is_vista_or_later: secret = cls.decrypt_secret(enc_secret[0xC:], lsakey) @@ -133,7 +136,7 @@ class Lsadump(interfaces.plugins.PluginInterface): return secret @classmethod - def decrypt_secret(cls, secret: bytes, key: bytes): + def decrypt_secret(cls, secret: bytes, key: bytes) -> bytes: """Python implementation of SystemFunction005. Decrypts a block of data with DES using given key. @@ -168,11 +171,11 @@ class Lsadump(interfaces.plugins.PluginInterface): ) bootkey = hashdump.Hashdump.get_bootkey(syshive) - lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later) if not bootkey: vollog.warning("Unable to find bootkey") return None + lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later) if not lsakey: vollog.warning("Unable to find lsa key") return None @@ -190,15 +193,17 @@ class Lsadump(interfaces.plugins.PluginInterface): if not sec_val_key: continue - enc_secret_value = next(sec_val_key.get_values()) + enc_secret_value = next(sec_val_key.get_values(), None) if not enc_secret_value: continue - enc_secret = sechive.read( - enc_secret_value.Data + 4, enc_secret_value.DataLength - ) - if not enc_secret: + try: + enc_secret = sechive.read( + enc_secret_value.Data + 4, enc_secret_value.DataLength + ) + except exceptions.InvalidAddressExceptions: continue + if not vista_or_later: secret = self.decrypt_secret(enc_secret[0xC:], lsakey) else: From 74df8dc1ee87afe07d7ccee89097af3bd8fcb2f3 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Fri, 7 Mar 2025 23:36:45 +0000 Subject: [PATCH 2/6] Fix version changes --- volatility3/framework/plugins/windows/cachedump.py | 4 ++-- volatility3/framework/plugins/windows/lsadump.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/plugins/windows/cachedump.py b/volatility3/framework/plugins/windows/cachedump.py index bcc1fac7f..745fb8be4 100644 --- a/volatility3/framework/plugins/windows/cachedump.py +++ b/volatility3/framework/plugins/windows/cachedump.py @@ -22,7 +22,7 @@ class Cachedump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (2, 0, 0) + _version = (1, 0, 1) @classmethod def get_requirements(cls): @@ -36,7 +36,7 @@ class Cachedump(interfaces.plugins.PluginInterface): name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0) ), requirements.PluginRequirement( - name="lsadump", plugin=lsadump.Lsadump, version=(2, 0, 0) + name="lsadump", plugin=lsadump.Lsadump, version=(1, 0, 0) ), requirements.PluginRequirement( name="hashdump", plugin=hashdump.Hashdump, version=(2, 0, 0) diff --git a/volatility3/framework/plugins/windows/lsadump.py b/volatility3/framework/plugins/windows/lsadump.py index 0d23dda0a..afae77e0d 100644 --- a/volatility3/framework/plugins/windows/lsadump.py +++ b/volatility3/framework/plugins/windows/lsadump.py @@ -22,7 +22,7 @@ class Lsadump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (2, 0, 0) + _version = (1, 0, 0) @classmethod def get_requirements(cls): From bcf038bfd5ff981f673e23426b96ec79d3d8c19c Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Sat, 8 Mar 2025 00:30:06 +0000 Subject: [PATCH 3/6] Fix versioning again --- volatility3/framework/plugins/windows/cachedump.py | 4 ++-- volatility3/framework/plugins/windows/hashdump.py | 2 +- volatility3/framework/plugins/windows/lsadump.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/volatility3/framework/plugins/windows/cachedump.py b/volatility3/framework/plugins/windows/cachedump.py index 745fb8be4..cdb1d3c91 100644 --- a/volatility3/framework/plugins/windows/cachedump.py +++ b/volatility3/framework/plugins/windows/cachedump.py @@ -22,7 +22,7 @@ class Cachedump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 0, 1) + _version = (1, 1, 1) @classmethod def get_requirements(cls): @@ -39,7 +39,7 @@ class Cachedump(interfaces.plugins.PluginInterface): name="lsadump", plugin=lsadump.Lsadump, version=(1, 0, 0) ), requirements.PluginRequirement( - name="hashdump", plugin=hashdump.Hashdump, version=(2, 0, 0) + name="hashdump", plugin=hashdump.Hashdump, version=(1, 1, 0) ), ] diff --git a/volatility3/framework/plugins/windows/hashdump.py b/volatility3/framework/plugins/windows/hashdump.py index 9577326ae..3346807d6 100644 --- a/volatility3/framework/plugins/windows/hashdump.py +++ b/volatility3/framework/plugins/windows/hashdump.py @@ -21,7 +21,7 @@ class Hashdump(interfaces.plugins.PluginInterface): """Dumps user hashes from memory""" _required_framework_version = (2, 0, 0) - _version = (2, 0, 0) + _version = (1, 1, 1) @classmethod def get_requirements(cls): diff --git a/volatility3/framework/plugins/windows/lsadump.py b/volatility3/framework/plugins/windows/lsadump.py index afae77e0d..325c8e381 100644 --- a/volatility3/framework/plugins/windows/lsadump.py +++ b/volatility3/framework/plugins/windows/lsadump.py @@ -33,7 +33,7 @@ class Lsadump(interfaces.plugins.PluginInterface): architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( - name="hashdump", component=hashdump.Hashdump, version=(2, 0, 0) + name="hashdump", component=hashdump.Hashdump, version=(1, 1, 0) ), requirements.VersionRequirement( name="hivelist", component=hivelist.HiveList, version=(2, 0, 0) From 9e7ac650deeb26bf2382446a59814dec9433db0b Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Sat, 8 Mar 2025 00:30:53 +0000 Subject: [PATCH 4/6] Fix versioning again --- volatility3/framework/plugins/windows/cachedump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/cachedump.py b/volatility3/framework/plugins/windows/cachedump.py index cdb1d3c91..ef4096b42 100644 --- a/volatility3/framework/plugins/windows/cachedump.py +++ b/volatility3/framework/plugins/windows/cachedump.py @@ -22,7 +22,7 @@ class Cachedump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 1, 1) + _version = (1, 0, 1) @classmethod def get_requirements(cls): From f85c3a2d97136ea2acbc438c03120eda202ebee7 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Sat, 8 Mar 2025 00:31:57 +0000 Subject: [PATCH 5/6] Fix versioning again --- volatility3/framework/plugins/windows/lsadump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/lsadump.py b/volatility3/framework/plugins/windows/lsadump.py index 325c8e381..041a653f4 100644 --- a/volatility3/framework/plugins/windows/lsadump.py +++ b/volatility3/framework/plugins/windows/lsadump.py @@ -22,7 +22,7 @@ class Lsadump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 0, 0) + _version = (1, 0, 1) @classmethod def get_requirements(cls): From 3800ef37c7a29d9af6338b0dada091afc58a53c6 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Sat, 8 Mar 2025 00:32:47 +0000 Subject: [PATCH 6/6] Fix versioning again --- volatility3/framework/plugins/windows/cachedump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/cachedump.py b/volatility3/framework/plugins/windows/cachedump.py index ef4096b42..7bc35945a 100644 --- a/volatility3/framework/plugins/windows/cachedump.py +++ b/volatility3/framework/plugins/windows/cachedump.py @@ -22,7 +22,7 @@ class Cachedump(interfaces.plugins.PluginInterface): """Dumps lsa secrets from memory""" _required_framework_version = (2, 0, 0) - _version = (1, 0, 1) + _version = (1, 0, 2) @classmethod def get_requirements(cls):