mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-07 02:07:39 +02:00
Windows: Improve hashdumping plugin errors
This commit is contained in:
@@ -1,20 +1,22 @@
|
||||
# This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
import logging
|
||||
from struct import unpack
|
||||
from typing import Tuple
|
||||
|
||||
from Crypto.Cipher import ARC4, AES
|
||||
from Crypto.Hash import HMAC
|
||||
|
||||
from volatility3.framework import interfaces, renderers, exceptions
|
||||
from volatility3.framework import interfaces, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.layers import registry
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
from volatility3.plugins.windows import hashdump, lsadump
|
||||
from volatility3.plugins.windows.registry import hivelist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Cachedump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps lsa secrets from memory"""
|
||||
@@ -30,7 +32,8 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0))
|
||||
requirements.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0)),
|
||||
requirements.PluginRequirement(name = 'hashdump', plugin = hashdump.Hashdump, version = (1, 1, 0))
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@@ -60,7 +63,7 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
(uname_len, domain_len) = unpack("<HH", cache_data[:4])
|
||||
if len(cache_data[60:62]) == 0:
|
||||
return (uname_len, domain_len, 0, b'', b'')
|
||||
(domain_name_len, ) = unpack("<H", cache_data[60:62])
|
||||
(domain_name_len,) = unpack("<H", cache_data[60:62])
|
||||
ch = cache_data[64:80]
|
||||
enc_data = cache_data[96:]
|
||||
return (uname_len, domain_len, domain_name_len, enc_data, ch)
|
||||
@@ -84,21 +87,25 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
def _generator(self, syshive, sechive):
|
||||
bootkey = hashdump.Hashdump.get_bootkey(syshive)
|
||||
if not bootkey:
|
||||
raise ValueError('Unable to find bootkey')
|
||||
vollog.warning('Unable to find bootkey')
|
||||
return
|
||||
|
||||
vista_or_later = versions.is_vista_or_later(context = self.context, symbol_table = self.config['nt_symbols'])
|
||||
|
||||
lsakey = lsadump.Lsadump.get_lsa_key(sechive, bootkey, vista_or_later)
|
||||
if not lsakey:
|
||||
raise ValueError('Unable to find lsa key')
|
||||
vollog.warning('Unable to find lsa key')
|
||||
return
|
||||
|
||||
nlkm = self.get_nlkm(sechive, lsakey, vista_or_later)
|
||||
if not nlkm:
|
||||
raise ValueError('Unable to find nlkma key')
|
||||
vollog.warning('Unable to find nlkma key')
|
||||
return
|
||||
|
||||
cache = sechive.get_key("Cache")
|
||||
cache = hashdump.Hashdump.get_hive_key(sechive, "Cache")
|
||||
if not cache:
|
||||
raise ValueError('Unable to find cache key')
|
||||
vollog.warning('Unable to find cache key')
|
||||
return
|
||||
|
||||
for cache_item in cache.get_values():
|
||||
if cache_item.Name == "NL$Control":
|
||||
@@ -133,10 +140,12 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SECURITY':
|
||||
sechive = hive
|
||||
|
||||
if syshive is None:
|
||||
raise exceptions.VolatilityException('Unable to locate SYSTEM hive')
|
||||
if sechive is None:
|
||||
raise exceptions.VolatilityException('Unable to locate SECURITY hive')
|
||||
if syshive is None or sechive is None:
|
||||
if syshive is None:
|
||||
vollog.warning('Unable to locate SYSTEM hive')
|
||||
if sechive is None:
|
||||
vollog.warning('Unable to locate SECURITY hive')
|
||||
return
|
||||
|
||||
return renderers.TreeGrid([("Username", str), ("Domain", str), ("Domain name", str), ('Hashh', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
|
||||
@@ -22,6 +22,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps user hashes from memory"""
|
||||
|
||||
_required_framework_version = (1, 0, 0)
|
||||
_version = (1, 1, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
@@ -60,11 +61,22 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
empty_lm = b"\xaa\xd3\xb4\x35\xb5\x14\x04\xee\xaa\xd3\xb4\x35\xb5\x14\x04\xee"
|
||||
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):
|
||||
result = None
|
||||
try:
|
||||
result = hive.get_key(key)
|
||||
except KeyError:
|
||||
vollog.info(
|
||||
"Unable to load the required registry key {}\\{} from this memory image".format(hive.get_name(), key))
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_user_keys(cls, samhive: registry.RegistryHive) -> List[interfaces.objects.ObjectInterface]:
|
||||
user_key_path = "SAM\\Domains\\Account\\Users"
|
||||
|
||||
user_key = samhive.get_key(user_key_path)
|
||||
user_key = cls.get_hive_key(samhive, user_key_path)
|
||||
|
||||
if not user_key:
|
||||
return []
|
||||
return [k for k in user_key.get_subkeys() if k.Name != "Names"]
|
||||
@@ -75,7 +87,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
lsa_base = "ControlSet{0:03}".format(cs) + "\\Control\\Lsa"
|
||||
lsa_keys = ["JD", "Skew1", "GBG", "Data"]
|
||||
|
||||
lsa = syshive.get_key(lsa_base)
|
||||
lsa = cls.get_hive_key(syshive, lsa_base)
|
||||
|
||||
if not lsa:
|
||||
return None
|
||||
@@ -83,9 +95,10 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
bootkey = ''
|
||||
|
||||
for lk in lsa_keys:
|
||||
key = syshive.get_key(lsa_base + '\\' + lk)
|
||||
|
||||
class_data = syshive.read(key.Class + 4, key.ClassLength)
|
||||
key = cls.get_hive_key(syshive, lsa_base + '\\' + lk)
|
||||
class_data = None
|
||||
if key:
|
||||
class_data = syshive.read(key.Class + 4, key.ClassLength)
|
||||
|
||||
if class_data is None:
|
||||
return None
|
||||
@@ -102,7 +115,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
if not bootkey:
|
||||
return None
|
||||
|
||||
sam_account_key = samhive.get_key(sam_account_path)
|
||||
sam_account_key = cls.get_hive_key(samhive, sam_account_path)
|
||||
if not sam_account_key:
|
||||
return None
|
||||
|
||||
@@ -270,7 +283,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
rid = int(str(user.get_name()), 16)
|
||||
yield (0, (name, rid, lmout, ntout))
|
||||
else:
|
||||
raise ValueError("Hbootkey is not valid")
|
||||
vollog.warning("Hbootkey is not valid")
|
||||
|
||||
def run(self):
|
||||
offset = self.config.get('offset', None)
|
||||
|
||||
@@ -31,7 +31,8 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
description = 'Memory layer for the kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
|
||||
requirements.VersionRequirement(name = 'hashdump', component = hashdump.Hashdump, version = (1, 1, 0)),
|
||||
requirements.VersionRequirement(name = 'hivelist', component = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -65,7 +66,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
else:
|
||||
policy_key = 'PolSecretEncryptionKey'
|
||||
|
||||
enc_reg_key = sechive.get_key("Policy\\" + policy_key)
|
||||
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())
|
||||
@@ -94,23 +95,21 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
|
||||
@classmethod
|
||||
def get_secret_by_name(cls, sechive: registry.RegistryHive, name: str, lsakey: bytes, is_vista_or_later: bool):
|
||||
try:
|
||||
enc_secret_key = sechive.get_key("Policy\\Secrets\\" + name + "\\CurrVal")
|
||||
except KeyError:
|
||||
raise ValueError("Unable to read cache from memory")
|
||||
enc_secret_key = hashdump.Hashdump.get_hive_key(sechive, "Policy\\Secrets\\" + name + "\\CurrVal")
|
||||
|
||||
enc_secret_value = next(enc_secret_key.get_values())
|
||||
if not enc_secret_value:
|
||||
return None
|
||||
secret = None
|
||||
if enc_secret_key:
|
||||
enc_secret_value = next(enc_secret_key.get_values())
|
||||
if enc_secret_value:
|
||||
|
||||
enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength)
|
||||
if not enc_secret:
|
||||
return None
|
||||
enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength)
|
||||
if enc_secret:
|
||||
|
||||
if not is_vista_or_later:
|
||||
secret = cls.decrypt_secret(enc_secret[0xC:], lsakey)
|
||||
else:
|
||||
secret = cls.decrypt_aes(enc_secret, lsakey)
|
||||
|
||||
if not is_vista_or_later:
|
||||
secret = cls.decrypt_secret(enc_secret[0xC:], lsakey)
|
||||
else:
|
||||
secret = cls.decrypt_aes(enc_secret, lsakey)
|
||||
return secret
|
||||
|
||||
@classmethod
|
||||
@@ -133,7 +132,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
if len(key[j:j + 7]) < 7:
|
||||
j = len(key[j:j + 7])
|
||||
|
||||
(dec_data_len, ) = unpack("<L", decrypted_data[:4])
|
||||
(dec_data_len,) = unpack("<L", decrypted_data[:4])
|
||||
|
||||
return decrypted_data[8:8 + dec_data_len]
|
||||
|
||||
@@ -144,18 +143,23 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
bootkey = hashdump.Hashdump.get_bootkey(syshive)
|
||||
lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later)
|
||||
if not bootkey:
|
||||
raise ValueError('Unable to find bootkey')
|
||||
vollog.warning("Unable to find bootkey")
|
||||
return
|
||||
|
||||
if not lsakey:
|
||||
raise ValueError('Unable to find lsa key')
|
||||
vollog.warning("Unable to find lsa key")
|
||||
return
|
||||
|
||||
secrets_key = sechive.get_key('Policy\\Secrets')
|
||||
secrets_key = hashdump.Hashdump.get_hive_key(sechive, 'Policy\\Secrets')
|
||||
if not secrets_key:
|
||||
raise ValueError('Unable to find secrets key')
|
||||
vollog.warning("Unable to find secrets key")
|
||||
return
|
||||
|
||||
for key in secrets_key.get_subkeys():
|
||||
|
||||
sec_val_key = sechive.get_key('Policy\\Secrets\\' + key.get_key_path().split('\\')[3] + '\\CurrVal')
|
||||
sec_val_key = hashdump.Hashdump.get_hive_key(sechive,
|
||||
'Policy\\Secrets\\' + key.get_key_path().split('\\')[
|
||||
3] + '\\CurrVal')
|
||||
if not sec_val_key:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user