Shell history is a convenience that doubles as a record of everything typed, including secrets. MITRE tracks the abuse as T1552.003, Shell History, a credential access technique under Unsecured Credentials for Linux, macOS and Windows.
How attackers use it
On Linux and macOS, shells such as Bash and Zsh track commands with the history utility. When a user logs out, the history is flushed to a file in their home directory, for example ~/.bash_history or ~/.zsh_history. MITRE notes these files typically hold the last 1000 commands.
On Windows, PowerShell has two histories: one that is wiped when the session ends, and a persistent one that covers all sessions. The default location of the persistent file is %userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt. Command history is also reachable with Get-History. MITRE points out that Command Prompt has no persistent history.
Users often type usernames and passwords as command-line parameters. Those end up in the history file, and an adversary who reads the file can search it for credentials.
How to detect it
MITRE's detection strategy watches for a process outside the normal interactive shell reading ~/.bash_history directly, for example with cat, less or grep. This often comes shortly after a privilege escalation or user switch with su or sudo, and may be followed by credential scanning or file writes to new places.
On macOS, MITRE suggests unified logs or telemetry such as Endpoint Security to observe file reads and terminal process lineage that shows access the user did not start.
How to reduce the risk
MITRE's mitigation is Operating System Configuration, with several options.
- Bash:
set +o historystops recording (andset -o historystarts it again),unset HISTFILEcan be added to the shell startup file, or the history file can be pointed to/dev/nullwith a symbolic link. - Zsh:
fc -pstarts a private history session, though earlier history is unavailable to the user until it ends.unset HISTFILEand/dev/nullwork here too. - PowerShell:
Set-PSReadLineOption -HistorySaveStyle SaveNothingprevents saving. Switching back toSaveIncrementallyin the same session saves everything from that session.-AddToHistoryHandlercan filter specific commands out.
The better fix is upstream. Do not pass secrets on the command line at all. Use a prompt, a credential helper or an environment source that does not write to history.
Check your own environment
Read-only checks. The first two are for a Bash shell, the third for PowerShell.
echo $HISTFILE
ls -l ~/.bash_history
(Get-PSReadLineOption).HistorySavePath
Check that those files are readable only by their owner, and search your own histories for obvious secrets using a pattern you are comfortable with. If you find some, rotate them.
Quick check
Where does PowerShell keep persistent history by default?
In ConsoleHost_history.txt under AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline in the user profile.
Sources
- MITRE ATT&CK, Unsecured Credentials: Shell History: https://attack.mitre.org/techniques/T1552/003