Merge pull request #1682 from volatilityfoundation/fix_secrets_dumping_plugins

Bring hash dumping plugins up to current coding standards and error c…
This commit is contained in:
ikelos
2025-03-08 00:31:07 +00:00
committed by GitHub
3 changed files with 48 additions and 23 deletions
@@ -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):
@@ -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 = (1, 1, 1)
@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
@@ -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):
@@ -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: