Skip to content

Commit

Permalink
Merge pull request #157 from rtpt-romankarwacik/lsa_isolated_data
Browse files Browse the repository at this point in the history
Add ly4k's changes for detecting LSA Isolated Data
  • Loading branch information
skelsec authored Jul 21, 2024
2 parents 61b839b + 08fe0dc commit 1571892
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 29 deletions.
73 changes: 53 additions & 20 deletions pypykatz/lsadecryptor/packages/msv/decryptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import io
import json
import base64
import struct
from pypykatz.commons.common import WindowsBuild, WindowsMinBuild, KatzSystemArchitecture, GenericReader, UniversalEncoder, hexdump
from pypykatz.commons.filetime import filetime_to_dt
from pypykatz.commons.win_datatypes import PVOID
from pypykatz.lsadecryptor.packages.msv.templates import MSV1_0_PRIMARY_CREDENTIAL_STRANGE_DEC
from pypykatz.lsadecryptor.packages.credman.templates import KIWI_CREDMAN_LIST_STARTER, KIWI_CREDMAN_SET_LIST_ENTRY
from pypykatz.lsadecryptor.package_commons import PackageDecryptor
Expand Down Expand Up @@ -41,9 +43,16 @@ def __str__(self):
t = '\t== MSV ==\n'
t += '\t\tUsername: %s\n' % (self.username if self.username else 'NA')
t += '\t\tDomain: %s\n' % (self.domainname if self.domainname else 'NA')
t += '\t\tLM: %s\n' % (self.LMHash.hex() if self.LMHash else 'NA')
t += '\t\tNT: %s\n' % (self.NThash.hex() if self.NThash else 'NA')
t += '\t\tSHA1: %s\n' % (self.SHAHash.hex() if self.SHAHash else 'NA')
if self.isoProt:
t += '\t\t\t[LSA Isolated Data]\n'
t += '\t\t\tIs NT Present: %s\n' % (bool(self.isNtOwfPassword))
t += '\t\t\tContext Handle: %s\n' % (hex(self.contextHandle) if self.contextHandle else 'NA')
t += '\t\t\tProxy Info: %s\n' % (hex(self.proxyInfo) if self.proxyInfo else 'NA')
t += '\t\t\tEncrypted blob: %s\n' % (self.encryptedBlob.hex() if self.encryptedBlob else 'NA')
else:
t += '\t\tLM: %s\n' % (self.LMHash.hex() if self.LMHash else 'NA')
t += '\t\tNT: %s\n' % (self.NThash.hex() if self.NThash else 'NA')
t += '\t\tSHA1: %s\n' % (self.SHAHash.hex() if self.SHAHash else 'NA')
t += '\t\tDPAPI: %s\n' % (self.DPAPI.hex() if self.DPAPI else 'NA')
return t

Expand Down Expand Up @@ -358,6 +367,26 @@ def add_credman_credential(self, credman_credential_entry):

self.current_logonsession.credman_creds.append(c)

def get_proxy_info(self, msv1_0_module):
old_pos = self.reader.tell()

msv1_0_module = self.reader.reader.get_module_by_name("msv1_0.dll")
if msv1_0_module is None:
self.reader.move(old_pos)
return 0

try:
position = self.find_signature('msv1_0.dll', b'\xe0zRE}*\xecL\xb2\x14s\x9fAY\xc3\x92')
position = self.find_signature('msv1_0.dll', struct.pack('<Q', position - 4))
position = self.find_signature('msv1_0.dll', struct.pack('<Q', position))
except:
position = 0

msv1_0_module.proxyInfo = position

self.reader.move(old_pos)

return position

def add_primary_credentials(self, primary_credentials_entry):
encrypted_credential_data = primary_credentials_entry.encrypted_credentials.read_data(self.reader)
Expand Down Expand Up @@ -397,24 +426,28 @@ def add_primary_credentials(self, primary_credentials_entry):

if hasattr(creds_struct, 'isIso'):
cred.isoProt = bool(creds_struct.isIso[0])
#
# if cred.isoProt is True:
# cred.NThash = None
# cred.LMHash = None
# cred.SHAHash = None
#
#else:
# cred.NThash = creds_struct.NtOwfPassword
#
# if creds_struct.LmOwfPassword and creds_struct.LmOwfPassword != b'\x00'*16:
# cred.LMHash = creds_struct.LmOwfPassword
# cred.SHAHash = creds_struct.ShaOwPassword

cred.NThash = creds_struct.NtOwfPassword

if cred.isoProt is True and hasattr(creds_struct, 'encryptedBlob'):
if creds_struct.pNtlmCredIsoInProc:
old_pos = self.reader.tell()
self.reader.move(creds_struct.pNtlmCredIsoInProc + 0x10)
cred.contextHandle = PVOID(self.reader).value
self.reader.move(old_pos)

if creds_struct.LmOwfPassword and creds_struct.LmOwfPassword != b'\x00'*16:
cred.LMHash = creds_struct.LmOwfPassword
cred.SHAHash = creds_struct.ShaOwPassword
cred.encryptedBlob = creds_struct.encryptedBlob
cred.isNtOwfPassword = creds_struct.isNtOwfPassword

msv1_0_module = self.reader.reader.get_module_by_name("msv1_0.dll")
if hasattr(msv1_0_module, 'proxyInfo'):
cred.proxyInfo = msv1_0_module.proxyInfo
else:
cred.proxyInfo = self.get_proxy_info(msv1_0_module)
else:
cred.NThash = creds_struct.NtOwfPassword

if creds_struct.LmOwfPassword and creds_struct.LmOwfPassword != b'\x00'*16:
cred.LMHash = creds_struct.LmOwfPassword
cred.SHAHash = creds_struct.ShaOwPassword

self.current_logonsession.msv_creds.append(cred)

Expand Down
19 changes: 10 additions & 9 deletions pypykatz/lsadecryptor/packages/msv/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,16 @@ def __init__(self, reader):
self.align0 = BYTE(reader).value
self.align1 = BYTE(reader).value
self.align2 = BYTE(reader).value
self.unkD = DWORD(reader).value # // 1/2
# stuff to be done! #pragma pack(push, 2)
self.isoSize = WORD(reader).value #// 0000
self.DPAPIProtected = reader.read(16)
self.align3 = DWORD(reader).value #// 00000000
# stuff to be done! #pragma pack(pop)
self.NtOwfPassword = reader.read(16)
self.LmOwfPassword = reader.read(16)
self.ShaOwPassword = reader.read(20)
self.credKeyType = DWORD(reader).value
self.isoSize = WORD(reader).value
self.DPAPIProtected = reader.read(20)

if bool(self.isIso[0]):
self.encryptedBlob = reader.read(self.isoSize)
else:
self.NtOwfPassword = reader.read(16)
self.LmOwfPassword = reader.read(16)
self.ShaOwPassword = reader.read(20)

class KIWI_MSV1_0_PRIMARY_CREDENTIAL_ENC:
def __init__(self, reader):
Expand Down

0 comments on commit 1571892

Please sign in to comment.