mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-06 09:47:38 +02:00
Windows: Run yapf over recent lsadump/cachedump plugins
This commit is contained in:
@@ -2,36 +2,35 @@
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
from struct import unpack
|
||||
|
||||
from Crypto.Cipher import ARC4, AES
|
||||
from Crypto.Hash import HMAC
|
||||
|
||||
from volatility.framework import interfaces, renderers
|
||||
from volatility.framework.configuration import requirements
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.layers import intel
|
||||
from volatility.plugins.windows.registry import hivelist
|
||||
from volatility.plugins.windows import hashdump, lsadump, poolscanner
|
||||
from Crypto.Hash import HMAC
|
||||
from Crypto.Cipher import ARC4, AES
|
||||
from struct import unpack
|
||||
from volatility.plugins.windows.registry import hivelist
|
||||
|
||||
|
||||
class Cachedump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps lsa secrets from memory"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [requirements.TranslationLayerRequirement(name = 'primary',
|
||||
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.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0))
|
||||
]
|
||||
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.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0))
|
||||
]
|
||||
|
||||
def get_nlkm(self, sechive, lsakey, is_vista_or_later):
|
||||
return lsadump.Lsadump.get_secret_by_name(sechive, 'NL$KM', lsakey, is_vista_or_later)
|
||||
|
||||
|
||||
def decrypt_hash(self, edata, nlkm, ch, xp):
|
||||
if xp:
|
||||
@@ -44,12 +43,12 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch)
|
||||
data = ""
|
||||
for i in range(0, len(edata), 16):
|
||||
buf = edata[i : i + 16]
|
||||
buf = edata[i: i + 16]
|
||||
if len(buf) < 16:
|
||||
buf += (16 - len(buf)) * "\00"
|
||||
data += aes.decrypt(buf)
|
||||
return data
|
||||
|
||||
|
||||
def parse_cache_entry(self, cache_data):
|
||||
(uname_len, domain_len) = unpack("<HH", cache_data[:4])
|
||||
if len(cache_data[60:62]) == 0:
|
||||
@@ -59,21 +58,20 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
enc_data = cache_data[96:]
|
||||
return (uname_len, domain_len, domain_name_len, enc_data, ch)
|
||||
|
||||
|
||||
def parse_decrypted_cache(self, dec_data, uname_len,
|
||||
domain_len, domain_name_len):
|
||||
domain_len, domain_name_len):
|
||||
"""Get the data from the cache and separate it into the username, domain name, and hash data"""
|
||||
uname_offset= 72
|
||||
uname_offset = 72
|
||||
pad = 2 * ((uname_len / 2) % 2)
|
||||
domain_offset= int(uname_offset+ uname_len + pad)
|
||||
domain_offset = int(uname_offset + uname_len + pad)
|
||||
pad = 2 * ((domain_len / 2) % 2)
|
||||
domain_name_offset= int(domain_offset+ domain_len + pad)
|
||||
domain_name_offset = int(domain_offset + domain_len + pad)
|
||||
hashh = dec_data[:0x10]
|
||||
username = dec_data[uname_offset:uname_offset+ uname_len]
|
||||
username = dec_data[uname_offset:uname_offset + uname_len]
|
||||
username = username.decode('utf-16-le', 'replace')
|
||||
domain = dec_data[domain_offset:domain_offset+ domain_len]
|
||||
domain = dec_data[domain_offset:domain_offset + domain_len]
|
||||
domain = domain.decode('utf-16-le', 'replace')
|
||||
domain_name = dec_data[domain_name_offset:domain_name_offset+ domain_name_len]
|
||||
domain_name = dec_data[domain_name_offset:domain_name_offset + domain_name_len]
|
||||
domain_name = domain_name.decode('utf-16-le', 'replace')
|
||||
|
||||
return (username, domain, domain_name, hashh)
|
||||
@@ -82,57 +80,55 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
bootkey = hashdump.Hashdump.get_bootkey(syshive)
|
||||
if not bootkey:
|
||||
raise ValueError('Unable to find bootkey')
|
||||
|
||||
|
||||
is_vista_or_later = poolscanner.os_distinguisher(version_check = lambda x: x >= (6, 0),
|
||||
fallback_checks = [("KdCopyDataBlock", None, True)])
|
||||
fallback_checks = [("KdCopyDataBlock", None, True)])
|
||||
vista_or_later = 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')
|
||||
raise ValueError('Unable to find lsa key')
|
||||
|
||||
nlkm = self.get_nlkm(sechive, lsakey, vista_or_later)
|
||||
if not nlkm:
|
||||
raise ValueError('Unable to find nlkma key')
|
||||
raise ValueError('Unable to find nlkma key')
|
||||
|
||||
cache = sechive.get_key("Cache")
|
||||
if not cache:
|
||||
raise ValueError('Unable to find cache key')
|
||||
|
||||
raise ValueError('Unable to find cache key')
|
||||
|
||||
for cache_item in cache.get_values():
|
||||
if cache_item.Name == "NL$Control":
|
||||
continue
|
||||
|
||||
data = sechive.read(cache_item.Data+4, cache_item.DataLength)
|
||||
data = sechive.read(cache_item.Data + 4, cache_item.DataLength)
|
||||
if data == None:
|
||||
continue
|
||||
(uname_len, domain_len, domain_name_len,
|
||||
enc_data, ch) = self.parse_cache_entry(data)
|
||||
enc_data, ch) = self.parse_cache_entry(data)
|
||||
# Skip if nothing in this cache entry
|
||||
if uname_len == 0 or len(ch) == 0:
|
||||
continue
|
||||
dec_data = self.decrypt_hash(enc_data, nlkm, ch, not vista_or_later)
|
||||
|
||||
(username, domain, domain_name,
|
||||
hashh) = self.parse_decrypted_cache(dec_data, uname_len,
|
||||
domain_len, domain_name_len)
|
||||
yield (0,(username, domain, domain_name, hashh))
|
||||
hashh) = self.parse_decrypted_cache(dec_data, uname_len,
|
||||
domain_len, domain_name_len)
|
||||
yield (0, (username, domain, domain_name, hashh))
|
||||
|
||||
def run(self):
|
||||
offset = self.config.get('offset', None)
|
||||
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(self.context,
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SYSTEM':
|
||||
syshive=hive
|
||||
syshive = hive
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SECURITY':
|
||||
sechive=hive
|
||||
sechive = hive
|
||||
|
||||
return renderers.TreeGrid([("Username", str), ("Domain", str), ("Domain name", str), ('Hashh', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
return renderers.TreeGrid([("Username", str), ("Domain", str), ("Domain name", str), ('Hashh', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import logging
|
||||
from struct import unpack
|
||||
|
||||
from Crypto.Cipher import ARC4, DES, AES
|
||||
from Crypto.Hash import MD5, SHA256
|
||||
|
||||
from volatility.framework import interfaces, renderers
|
||||
from volatility.framework.configuration import requirements
|
||||
from volatility.framework.renderers import format_hints
|
||||
from volatility.framework.layers import intel
|
||||
from volatility.plugins.windows.registry import hivelist
|
||||
from volatility.plugins.windows import hashdump, poolscanner
|
||||
from Crypto.Hash import MD5, SHA256
|
||||
from Crypto.Cipher import ARC4, DES, AES
|
||||
from struct import unpack, pack
|
||||
import collections
|
||||
from volatility.plugins.windows.registry import hivelist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Lsadump(interfaces.plugins.PluginInterface):
|
||||
"""Dumps lsa secrets from memory"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [requirements.TranslationLayerRequirement(name = 'primary',
|
||||
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))
|
||||
]
|
||||
|
||||
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))
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def decrypt_aes(cls, secret, key):
|
||||
"""
|
||||
@@ -44,33 +44,32 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
data = b""
|
||||
for i in range(60, len(secret), 16):
|
||||
aes = AES.new(aeskey, AES.MODE_CBC, b'\x00' * 16)
|
||||
buf = secret[i : i + 16]
|
||||
buf = secret[i: i + 16]
|
||||
if len(buf) < 16:
|
||||
buf += (16 - len(buf)) * "\00"
|
||||
data += aes.decrypt(buf)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_lsa_key(cls, sechive, bootkey, vista_or_later):
|
||||
if not bootkey:
|
||||
return None
|
||||
|
||||
|
||||
if vista_or_later:
|
||||
policy_key = 'PolEKList'
|
||||
else:
|
||||
policy_key = 'PolSecretEncryptionKey'
|
||||
|
||||
enc_reg_key = sechive.get_key("Policy\\"+policy_key)
|
||||
enc_reg_key = sechive.get_key("Policy\\" + policy_key)
|
||||
if not enc_reg_key:
|
||||
return None
|
||||
enc_reg_value = next(enc_reg_key.get_values())
|
||||
|
||||
|
||||
if not enc_reg_value:
|
||||
return None
|
||||
|
||||
obf_lsa_key = sechive.read(enc_reg_value.Data+4, enc_reg_value.DataLength)
|
||||
|
||||
obf_lsa_key = sechive.read(enc_reg_value.Data + 4, enc_reg_value.DataLength)
|
||||
|
||||
if not obf_lsa_key:
|
||||
return None
|
||||
@@ -88,21 +87,20 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
lsa_key = cls.decrypt_aes(obf_lsa_key, bootkey)
|
||||
lsa_key = lsa_key[68:100]
|
||||
return lsa_key
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_secret_by_name(cls, sechive, name, lsakey, is_vista_or_later):
|
||||
try:
|
||||
enc_secret_key = sechive.get_key("Policy\\Secrets\\" + name + "\\CurrVal")
|
||||
except KeyError:
|
||||
raise ValueError("Unable to read cache from memory")
|
||||
|
||||
|
||||
enc_secret_value = next(enc_secret_key.get_values())
|
||||
if not enc_secret_value:
|
||||
return None
|
||||
|
||||
enc_secret = sechive.read(enc_secret_value.Data+4,
|
||||
enc_secret_value.DataLength)
|
||||
enc_secret = sechive.read(enc_secret_value.Data + 4,
|
||||
enc_secret_value.DataLength)
|
||||
if not enc_secret:
|
||||
return None
|
||||
|
||||
@@ -119,7 +117,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
Decrypts a block of data with DES using given key.
|
||||
Note that key can be longer than 7 bytes."""
|
||||
decrypted_data = b''
|
||||
j = 0 # key index
|
||||
j = 0 # key index
|
||||
|
||||
for i in range(0, len(secret), 8):
|
||||
enc_block = secret[i:i + 8]
|
||||
@@ -139,14 +137,14 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
def _generator(self, syshive, sechive):
|
||||
|
||||
is_vista_or_later = poolscanner.os_distinguisher(version_check = lambda x: x >= (6, 0),
|
||||
fallback_checks = [("KdCopyDataBlock", None, True)])
|
||||
fallback_checks = [("KdCopyDataBlock", None, True)])
|
||||
vista_or_later = is_vista_or_later(context = self.context, symbol_table = self.config['nt_symbols'])
|
||||
|
||||
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')
|
||||
|
||||
|
||||
if not lsakey:
|
||||
raise ValueError('Unable to find lsa key')
|
||||
|
||||
@@ -156,7 +154,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
|
||||
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 = sechive.get_key('Policy\\Secrets\\' + key.get_key_path().split('\\')[3] + '\\CurrVal')
|
||||
if not sec_val_key:
|
||||
continue
|
||||
|
||||
@@ -165,7 +163,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
continue
|
||||
|
||||
enc_secret = sechive.read(enc_secret_value.Data + 4,
|
||||
enc_secret_value.DataLength)
|
||||
enc_secret_value.DataLength)
|
||||
if not enc_secret:
|
||||
continue
|
||||
if not vista_or_later:
|
||||
@@ -173,30 +171,22 @@ class Lsadump(interfaces.plugins.PluginInterface):
|
||||
else:
|
||||
secret = self.decrypt_aes(enc_secret, lsakey)
|
||||
|
||||
|
||||
yield (0,(key.get_name(), secret.decode('latin1'), secret))
|
||||
|
||||
|
||||
yield (0, (key.get_name(), secret.decode('latin1'), secret))
|
||||
|
||||
def run(self):
|
||||
|
||||
offset = self.config.get('offset', None)
|
||||
|
||||
|
||||
for hive in hivelist.HiveList.list_hives(self.context,
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
self.config_path,
|
||||
self.config['primary'],
|
||||
self.config['nt_symbols'],
|
||||
hive_offsets = None if offset is None else [offset]):
|
||||
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SYSTEM':
|
||||
syshive=hive
|
||||
syshive = hive
|
||||
if hive.get_name().split('\\')[-1].upper() == 'SECURITY':
|
||||
sechive=hive
|
||||
sechive = hive
|
||||
|
||||
return renderers.TreeGrid([("Key", str), ("Secret", str), ('Hex', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
|
||||
|
||||
|
||||
|
||||
return renderers.TreeGrid([("Key", str), ("Secret", str), ('Hex', bytes)],
|
||||
self._generator(syshive, sechive))
|
||||
|
||||
Reference in New Issue
Block a user