Skip to content

Bash History Clearing

Attackers unset HISTFILE or shred .bash_history to hide commands, but the shell, kernel, and disk all retain copies the wipe never reaches.

Clearing the shell history is one of the first things a Linux intruder does after gaining a foothold. The goal is to remove the per-user record of typed commands — package installs, wget of a second-stage payload, credential dumping — that ~/.bash_history would otherwise hand the responder on a plate. The technique is trivial, scriptable, and built into the shell, which is exactly why crypto-mining and worm operators bake it into their installers.

It is also unreliable as a cover-up. The history file is only one of several places a command leaves a trace, and the most common clearing methods either fire too late, miss the in-memory copy, or leave a conspicuous gap that itself flags the session as hostile.

How it works

The usual moves disable logging for the current shell and erase the on-disk file:

bash
# Stop the current shell from ever writing history, then wipe the file
unset HISTFILE
history -c            # clear the in-memory list
shred -u ~/.bash_history   # overwrite and unlink the file

unset HISTFILE prevents the running shell from flushing its in-memory history on exit; history -c clears the current session buffer; shred -u overwrites and removes the file. Some actors instead export HISTSIZE=0 or symlink ~/.bash_history to /dev/null so nothing is ever recorded.

Detection & analysis

Static analysis:

  • Inspect ~/.bash_history for an abrupt end-of-file gap: a file that stops mid-session or is zero-length while the account clearly logged in (per wtmp/last) indicates clearing. A symlink to /dev/null or a file with HISTSIZE/HISTFILE overrides in .bashrc/.bash_profile is a planted indicator.
  • Carve unallocated space and the journal for recoverable history fragments. Because shred on a journaling or copy-on-write filesystem (ext4 with data journaling, btrfs, ZFS) does not reliably overwrite the original blocks, deleted history lines are frequently recoverable with photorec, ext4magic, or raw grep of the block device for known command strings.
  • Check shells beyond bash — ~/.zsh_history, ~/.python_history, ~/.mysql_history, ~/.lesshst — which attackers routinely forget.

Dynamic analysis:

  • Where auditd or the kernel execve audit rule is configured, every command ran as a process and is captured in /var/log/audit/audit.log independent of shell history. sysmon-for-linux (Event ID 1) and eBPF agents (Falco, auditbeat) provide the same execution record that no history -c can reach.
  • Correlate process accounting (/var/log/account/pacct via psacct/acct) and any sudo activity in /var/log/auth.log to reconstruct the command sequence the cleared history was meant to hide.

Detection rule hint: Alert when a session writes HISTFILE, HISTSIZE=0, history -c, shred, or ln -s /dev/null .bash_history, and treat any ~/.bash_history that is zero-length or symlinked for an account with recent interactive logins as compromised. Always rebuild the command timeline from auditd/eBPF execution logs and carve the filesystem journal for the deleted lines — the shell history is the least authoritative source.

Votes

Comments(0)