Chapter 23

Credential Artifacts in Memory

LSASS memory contains NTLM hashes, Kerberos tickets, and (if WDigest is enabled) cleartext passwords for every user who has authenticated on the system. Understanding what's in LSASS memory and how to extract it forensically is essential — it tells you what the attacker stole and helps scope the blast radius.

Scenario

After confirming Cobalt Strike beacon activity in a server, you capture the memory image. The attacker ran Mimikatz against LSASS earlier in the session — you can tell from the malfind hit showing Mimikatz's sekurlsa module injected into LSASS. The memory image was taken after Mimikatz ran. You now need to answer: what credentials did the attacker steal? Were domain admin credentials available in LSASS at the time of the attack? The forensic analysis of LSASS memory answers these questions — and the answer informs whether this is a workstation-level compromise or a full domain compromise.

What LSASS Memory Contains

  LSASS Memory: Credential Storage Architecture
  ═══════════════════════════════════════════════════════════════════

  LSASS (Local Security Authority Subsystem Service) manages:
  ├── NTLM Authentication Package:
  │   └── NTLM password hashes for currently-logged-on users
  │       (used for Pass-the-Hash attacks)
  │
  ├── Kerberos Authentication Package:
  │   ├── TGTs (Ticket Granting Tickets) — valid for 10 hours by default
  │   ├── Service Tickets — for specific services the user has accessed
  │   └── Kerberos session keys
  │
  ├── WDigest Authentication Package (if enabled):
  │   └── CLEARTEXT PASSWORDS for logged-on users
  │       (disabled by default on modern Windows — but attackers enable it,
  │       wait for logon, then dump)
  │
  ├── Security Support Provider (SSP):
  │   └── Application-specific SSP credentials
  │
  └── Credential Manager:
      └── Saved web credentials, network credentials

  Who's in LSASS:
    Any user currently logged on (interactive session, RDP, service, etc.)
    Recent logons may have cached credentials even after logoff
    Service accounts (running services authenticate against LSASS)
    → Domain Admin currently logged on = DA hash in LSASS = full compromise

Extracting Hashes with Volatility

Bashvol3-credentials.sh
RAM="/cases/CASE001/RAM.raw"
OUT="/cases/CASE001/memory"

# Extract NTLM hashes from SAM (local accounts)
vol -f $RAM windows.hashdump > $OUT/hashes-sam.txt
# Output format: username:RID:LM_hash:NTLM_hash:::

# Extract cached domain credentials (DCC2 hashes - from SECURITY hive in memory)
vol -f $RAM windows.cachedump > $OUT/hashes-cached.txt
# Cached domain credentials — hashcat mode 2100 (-m 2100)

# Extract LSA secrets (service account passwords, stored credentials)
vol -f $RAM windows.lsadump > $OUT/lsa-secrets.txt

# List registry hives in memory (to confirm SYSTEM/SAM/SECURITY are loaded)
vol -f $RAM windows.registry.hivelist

LSASS Process Dump Analysis

The most complete credential extraction comes from dumping the LSASS process's memory and analyzing it with Mimikatz offline (in your forensic lab, on your analysis workstation).

Bashlsass-dump-analysis.sh
RAM="/cases/CASE001/RAM.raw"
OUT="/cases/CASE001/memory"

# Step 1: Find LSASS PID in the memory image
vol -f $RAM windows.pslist | grep -i lsass

# Step 2: Dump LSASS process memory to a .dmp file
vol -f $RAM windows.dumpfiles --pid  --output-dir $OUT/lsass-dump/

# Step 3: Analyze the LSASS dump with Mimikatz (offline, on your analysis machine)
# This does NOT run on the target — you're analyzing the dump, not the live system
# Run on an isolated analysis VM:
#   mimikatz.exe
#   sekurlsa::minidump lsass.DMP
#   sekurlsa::logonpasswords
#   sekurlsa::tickets /export     (export Kerberos tickets as .kirbi files)

# Alternative: pypykatz (Python reimplementation, runs on Linux/SIFT)
pip3 install pypykatz
pypykatz lsa minidump $OUT/lsass-dump/*.dmp > $OUT/credentials.txt
Bashpypykatz-analysis.sh
# pypykatz: analyze LSASS dump for credentials
# pypykatz runs on Linux — perfect for SIFT Workstation analysis

LSASS_DUMP="/cases/CASE001/memory/lsass-dump/pid.xyz.lsass.dmp"

# Parse all credential types
pypykatz lsa minidump $LSASS_DUMP

# Output includes per-session entries:
#   == MSV ==        — NTLM hashes
#     Username: jdoe
#     Domain: CORP
#     NT: aad3b435b51404eeaad3b435b51404ee  (empty password)
#     NT: a87f3a337d73085c45f9416be5787d86  (actual hash)
#
#   == WDIGEST ==     — cleartext passwords (if WDigest enabled)
#     Username: jdoe
#     Password: P@ssw0rd2024!
#
#   == Kerberos ==    — Kerberos tickets
#     Username: jdoe
#     Domain: CORP.LOCAL
#     Password: (null)  ← normal unless krb5 longterm key is cached
#
#   == SSP ==         — custom SSP credentials

# Export in JSON for scripting
pypykatz lsa minidump $LSASS_DUMP --json > $LSASS_DUMP.json

Using Credential Analysis to Scope Blast Radius

What was in LSASSBlast radius implication
Only the local user's NTLM hash (standard user)Limited. Attacker can pass-the-hash locally but not to domain resources unless that user has domain access.
Domain user's NTLM hash with no elevated domain privilegesMedium. Attacker can authenticate as that user to any domain resource the user has access to — email, file shares, internal apps.
Domain Admin or Enterprise Admin NTLM hash or TGTFull domain compromise. Attacker can authenticate as DA to any domain system. Entire domain must be treated as compromised.
Service account hashes (running services)Depends on service account privileges — if it's an MSA or has rights to other systems, scope expands to those systems.
Kerberos TGT (golden ticket potential)TGT can be used to request tickets for any service in the domain. Scope: entire Kerberos realm. krbtgt double-reset required.
Common mistake: not checking who was logged on at time of compromise

LSASS credential scope depends entirely on who was authenticated on the system when the attacker dumped it. If a domain admin happened to be RDP'd in at that moment, their credentials are in LSASS — even if they logged off minutes before you imaged memory (credentials can persist for a few minutes post-logoff). Always check: Event 4624 logon events in the time window surrounding the compromise, and Event 4634 logoff events. Cross-reference with LSASS memory analysis. The question is not just "what was in LSASS when we imaged it" but "what was in LSASS when the attacker dumped it" — and those are different timestamps.

Q & A

Q: Can you determine if the attacker already ran Mimikatz or a credential dumper before you captured the memory image?

Several indicators suggest prior credential dumping: (1) malfind hits showing Mimikatz modules (sekurlsa.dll) previously injected into LSASS. (2) Event 4656 and 4663 with LSASS as the target object — LSASS access with PROCESS_VM_READ access right is the signature of Mimikatz-style credential dumping. If these events fired but you didn't catch them in the SIEM (maybe they were cleared), the SRUM network usage data for the dumping session may show anomalous outbound traffic shortly after. (3) The SAM hive in memory: if hashes are present and the LSASS structure shows they were recently accessed. (4) Windows Defender/EDR logs: if credential-dumping was attempted but partially blocked, EDR logs often record LSASS access attempts even when credential dumping failed. (5) TGT age: if the TGTs in LSASS are very new (issued within the last few minutes), the attacker may have requested new TGTs after obtaining credentials.