Linux log triage for incident response and forensic analysis. /var/log catalogue, auth.log patterns, systemd journalctl flag walk, offline image analysis, boot history, shell history. Verified against systemd 259 and Kali userland.
Side: blue
/var/log catalogue
| File | Contents |
|---|---|
/var/log/syslog (Debian/Ubuntu) | general system + service messages |
/var/log/messages (RHEL/CentOS) | same role on Red Hat-family |
/var/log/auth.log (Debian/Ubuntu) | logins, sudo, su, SSH, PAM |
/var/log/secure (RHEL/CentOS) | equivalent to auth.log |
/var/log/kern.log | kernel messages |
/var/log/apache2/access.log / error.log | Apache HTTP access + errors |
/var/log/nginx/access.log / error.log | Nginx HTTP access + errors |
/var/log/mysql/error.log | MySQL errors, slow query log when enabled |
/var/log/squid/access.log | Squid proxy traffic |
/var/log/audit/audit.log | auditd records (when configured) |
/var/log/wtmp / /var/log/btmp | binary login / failed-login records — read with last / lastb |
/var/log/utmp | currently logged-in users — read with who / w |
/var/log/journal/<machine-id>/ | systemd binary journal — read with journalctl |
On modern systemd hosts, journalctl is the primary interface. /var/log/syslog exists in parallel only when rsyslog is installed.
auth.log patterns
grep "Failed password" auth.log | wc -l # brute-force volume signal
grep "Failed password" auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr # rank attacker IPs
grep "Accepted " auth.log | tail -20 # last successful logins
grep "session opened" auth.log | tail # PAM sessions opened
grep "sudo:" auth.log | awk -F'COMMAND=' '{print $2}' | sort | uniq -c | sort -nr # sudo commands rankedLine patterns to recognise:
| Pattern | Means |
|---|---|
Failed password for <user> from <ip> | SSH auth failure (mass = brute force) |
Failed password for invalid user <x> | username does not exist on host |
Accepted password for <user> from <ip> | successful interactive login |
Accepted publickey for <user> from <ip> | SSH key-based login, no password prompt |
session opened for user <user> | PAM session granted (login or sudo) |
authentication failure ... rhost=<ip> | PAM failure from remote host |
sudo: <user> : TTY=... COMMAND=... | exact sudo invocation |
Brute force signature: many Failed password lines, single source IP, incrementing source ports, seconds-scale time gaps.
journalctl essentials
journalctl # full journal, oldest first, paged
journalctl -ax # show all fields + catalog explanations
journalctl -t sudo # SYSLOG_IDENTIFIER filter
journalctl SYSLOG_IDENTIFIER=sudo # field-equality form (multiple = AND, + = OR)
journalctl -u ssh.service # filter by systemd unit
journalctl --since '2026-04-15' --until '2026-04-16' # date window (also: '1 hour ago', 'yesterday')
journalctl -p err # by syslog priority (emerg/alert/crit/err/warning/notice/info/debug or 0..7)
journalctl -g 'pattern' # grep MESSAGE field (case-insensitive)
journalctl -k # kernel messages this boot (alias --dmesg)
journalctl -f # follow live, like tail -f
journalctl -o verbose # show all fields per entry
journalctl --disk-usage # how much history is preservedBoot history
journalctl --list-boots # IDX BOOT-ID FIRST-ENTRY LAST-ENTRY
journalctl -b # current boot only (= -b 0)
journalctl -b -1 # previous boot
journalctl -b <boot-id-32hex> # specific boot by IDForensic uses for --list-boots:
- given a known-bad timestamp, find the boot whose
FIRST..LASTcovers it, then readjournalctl -b <id>for that window - mismatched boot count vs uptime metadata = journal truncated,
Storage=volatilediscarded, or vacuumed - one boot over a wide range = adversary may have been resident across all uptime
Offline image analysis
journalctl --root=/mnt/image # operate on a mounted image as if it were /
journalctl --root=/mnt/image --list-boots
journalctl --root=/mnt/image -t sudo --since '2026-04-17'
journalctl --root=/mnt/image -b <boot-id> -k
journalctl --image=/path/to/image.dd # operate directly on disk image (no LVM/encrypted)--root= looks up <root>/etc/machine-id, finds the matching journal directory under <root>/var/log/journal/<machine-id>/, and reads from there. Equivalent to copying out individual *.journal files and using journalctl --file=... per file but vastly faster.
Verify the switch worked: journalctl --root=/mnt/image --list-boots should show the image’s boot history, not the analysis workstation’s.
Tampering detection
journalctl --verify # check journal file consistency (FSS seals)
journalctl --root=/mnt/image --verify # against an imageFailures indicate truncation, replacement, or seal break.
Tamper-aware reading
Storage=volatilein/etc/systemd/journald.confwrites only to/run/log/journal/— reboots wipe everything. Always check journald config before trusting the journal as a complete record.Storage=auto(default) is persistent if/var/log/journal/exists, volatile otherwise. An attacker who deletes the persistent dir causes silent fallback.journalctl --rotate --vacuum-time=1sdiscards everything older than one second. Requires root. Evidence-destruction pattern.- Per-user journals at
/var/log/journal/<machine-id>/user-<uid>.journalwhenStorage=persistentand the session was systemd-managed.
dmesg vs journalctl -k
| Aspect | dmesg | journalctl -k |
|---|---|---|
| Source | kernel ring buffer (in-memory) | journal files on disk |
| Persistence | wiped on reboot | survives reboots if Storage=persistent |
| Time format | seconds since boot (use dmesg -T for wall clock) | wall clock with TZ offset |
| Cross-boot | current boot only | -b -N or -b <id> for previous |
| On evidence image | n/a (kernel ring is volatile) | works via --root= |
For kernel events around an incident on a host that has rebooted since, the journal is the only source.
Login records (binary)
last # /var/log/wtmp - successful logins
last -f /mnt/image/var/log/wtmp # against an image
last -F # full date/time format
last -i # IPs, not hostnames
lastb # /var/log/btmp - failed logins (root only)
lastlog # last login per user (one row each)
who # currently logged-in users (utmp)
w # currently logged-in + activitylastlog “Never logged in” rows are normal for system accounts; investigate when an account that never logged in suddenly has a login.
Shell history
cat /home/<user>/.bash_history # bash, no timestamps unless HISTTIMEFORMAT set
cat /home/<user>/.zsh_history # zsh, ': <epoch>:<duration>;<cmd>' if EXTENDED_HISTORY
cat /home/<user>/.local/share/fish/fish_history # fish, YAML-ish blocks
cat /root/.bash_history # always check root
find /home -name '.*history' -o -name '*_history' 2>/dev/null # exhaustive sweep
stat /home/<user>/.bash_history # mtime = last clean shell exit, btime = file creationPatterns worth flagging:
wget/curlfrom suspicious URLs (initial staging)chmod +xagainst unusual paths- shell upgrades:
bash -i,python -c "import pty; pty.spawn('/bin/sh')",nc -e,socat ... EXEC - privilege probes:
sudo -l,sudo find ... -exec,sudo vim ... - history-cleanup:
history -c,history -d <N>,unset HISTFILE,export HISTFILE=/dev/null,kill -9 $$ - direct config edits:
vi /etc/sudoers,nano /etc/passwd,vim ~/.ssh/authorized_keys - staging into world-writable:
/tmp,/var/tmp,/dev/shm
Limitations to flag in reports
- History files are editable by the owning user.
- History flushes only at clean shell exit.
kill -9of the shell leaves recent commands in memory only. - Non-history shells (
dash,ash,sh, busybox-sh) leave nothing. - Empty
.bash_historyon a long-active account is itself a finding, not an absence of finding. - Cross-check intent against journal
sudolines,auth.logSSH source IPs, and cron logs. History alone is the weakest source.
Standard text-log idioms
grep -F 'pattern' file # fixed-string match (faster, no regex)
grep -E 'a|b|c' file # extended regex
grep -v 'pattern' file # invert match
awk -F: '$3>=1000 {print $1}' /etc/passwd # column-extract by delimiter
sort file | uniq -c | sort -nr # frequency rank
sort -u file # unique values
cut -d',' -f1,3 file.csv # CSV columns 1 and 3
journalctl -t sudo --since '2026-04-15' | grep -i 'COMMAND' | awk -F'COMMAND=' '{print $2}' | sort | uniq -c | sort -nr
grep "Failed password" auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nrlinks:
Field Manual | Linux Log Analysis | Linux Forensics | Mount Disk Images