Credential leak in PowerShell history
PowerShell, a través del módulo PSReadLine, guarda en disco un historial de todos los comandos que el usuario ha escrito en sus sesiones interactivas. Ese fichero persiste entre reinicios y, lo importante para nosotros, es legible por el propio usuario sin privilegios especiales. La ruta se confirma y se lee así:
(Get-PSReadLineOption).HistorySavePath
gc (Get-PSReadLineOption).HistorySavePath
type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt(equivalente a C:\Users\<user>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt).
Es uno de los primeros sitios que conviene mirar tras conseguir una shell en Windows, porque la gente escribe en la consola cosas que no debería: contraseñas pasadas como argumento, cadenas de conexión, comandos ConvertTo-SecureString '...' -AsPlainText -Force, llamadas a Invoke-Command o evil-winrm con la credencial en claro, etc. Una sola línea del historial puede contener la contraseña de otro usuario y abrir un pivote lateral.
Buscar en varios perfiles y por palabra clave
Con privilegios para leer otros perfiles, se barren todos los historiales y se filtra por términos jugosos:
Get-ChildItem C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -Force |
ForEach-Object { Select-String -Path $_ -Pattern 'password|secret|ConvertTo-SecureString|-p ' }El patrón clásico es encontrar un bloque como:
$p = ConvertTo-SecureString 'E3R$Q62^12p7PLlC%KWaxuaV' -AsPlainText -Force
$c = New-Object System.Management.Automation.PSCredential ('svc_deploy', $p)
Invoke-Command -ComputerName localhost -Credential $c ...De ahí se lee directamente la contraseña de svc_deploy y se reutiliza para autenticarse como ese usuario. Vale la pena revisar de paso otros almacenes en claro: cmdkey /list lista credenciales guardadas (reutilizables con runas /savecred), y los web.config, unattend.xml o el autologon del registro (Winlogon) guardan secretos del mismo tipo. No es una vulnerabilidad de software, sino una mala práctica operativa: dejar secretos en texto plano en la línea de comandos.
Requisitos
Una shell en el host y permiso de lectura sobre el fichero de historial (el propio, siempre; los de otros usuarios, solo con privilegios). El valor depende por completo de que alguien haya tecleado un secreto en la consola.
Cómo detectarlo. La lectura del fichero deja poco rastro por sí sola, pero hay dos ángulos. El primero, y más potente, es la fuente: si está activado el Script Block Logging de PowerShell (Event ID 4104), el propio comando que dejó la credencial en el historial quedó registrado en su día, así que el defensor puede cazar en los 4104 los ConvertTo-SecureString ... -AsPlainText con secretos en claro antes de que un atacante los encuentre. El segundo es el acceso: leer el ConsoleHost_history.txt aparece como un 4688 (type/Get-Content sobre esa ruta) o, con SACL sobre el fichero, un 4663. La reutilización posterior de la credencial filtrada (un 4624 de svc_deploy desde un host inusual) cierra la cadena.
Defensa. No introducir credenciales como texto plano en la consola (usar Get-Credential interactivo, gestores de secretos o cuentas gestionadas), y limpiar o deshabilitar el historial de PSReadLine en cuentas sensibles (Set-PSReadLineOption -HistorySaveStyle SaveNothing). Es una forma concreta de caza de credenciales y suele encadenarse con la lectura de laps cuando el usuario filtrado pertenece a un grupo con permisos interesantes.
Máquinas donde se aplica
- TimelapseHackTheBox