Skip to content

User activityLogsNetwork

wtmp, btmp, utmp and lastlog: Linux Login Records

Binary Linux login records: wtmp session history, btmp failed logins, utmp live sessions, lastlog per-UID last login, and their wtmpdb/lastlog2 successors.

Location
/var/log/wtmp
Proves
Who logged in, on which terminal, from which host, when the session ended, and when the system rebooted
Timestamps
utmp records: Unix epoch seconds + microseconds (32-bit fields), UTC. wtmpdb: microseconds since epoch
Access
Readable by all for wtmp/utmp/lastlog; root (or utmp group) for btmp
Retention
logrotate: monthly, 1 old generation for wtmp and btmp; lastlog until overwritten
Collection
UAC, Velociraptor, cp -a

What it is

Linux keeps login accounting in a family of binary files that share one record layout, struct utmp (see wtmp and btmp). wtmp is an append-only history of logins, logouts, boots and shutdowns; btmp records failed logins; utmp holds only the sessions open right now. lastlog is a different format: one fixed-size slot per UID with that account's most recent login.

These files are written by login, sshd, display managers and PAM modules, independently of syslog. That independence is their forensic value: they often survive when text logs are edited, and they disagree with them when only one source was tampered with.

Because the classic record uses 32-bit time fields, recent distributions replace them with SQLite databases: wtmpdb for wtmp and lastlog2 (part of util-linux since 2.40) for lastlog.

Where it lives

FilePathReaderNotes
wtmp/var/log/wtmp, /var/log/wtmp.1lastHistory of sessions, reboots, shutdowns
btmp/var/log/btmp, /var/log/btmp.1lastbFailed logins, mode 0600/0660
utmp/run/utmp (/var/run/utmp)who, wtmpfs: current sessions only, gone after reboot
lastlog/var/log/lastloglastlogSparse file indexed by UID
wtmpdb (openSUSE, upstream default)/var/lib/wtmpdb/wtmp.dbwtmpdb lastSQLite, Y2038 safe
wtmpdb (Debian 13)/var/log/wtmp.dbwtmpdb lastDebian keeps a link at /var/lib/wtmpdb/wtmp.db
lastlog2/var/lib/lastlog/lastlog2.dblastlog2SQLite, Y2038 safe

Distribution notes: openSUSE Tumbleweed and MicroOS dropped /run/utmp, /var/log/wtmp and /var/log/lastlog in favour of systemd-logind, wtmpdb and lastlog2. Debian 13 (trixie) removed last, lastb and lastlog; the replacements wtmpdb and lastlog2 (with their PAM modules) must be installed separately after an upgrade (lslogins still ships with util-linux), so a trixie host may have no login database at all. RHEL/Fedora and Ubuntu LTS releases still commonly use the classic files; check what exists on the image.

What it proves

  • Interactive logins with user, terminal (pts/N, tty1, :0), remote host or IP, start and end time.
  • Reboots and shutdowns (reboot and shutdown pseudo-users on terminal ~), including abrupt ends where a session has no logout (crash or gone - no logout in last).
  • Failed logins with the attempted user name, which may include passwords typed into the user field by mistake. Handle btmp as sensitive.
  • The last login of each account from lastlog, even after wtmp rotated away.
  • It does not show non-interactive activity: ssh host command, scp/sftp and many automated logins do not allocate a tty and are often absent. Use auth.log/secure and the journal for those.

Key fields

struct utmp (384 bytes per record on common 64-bit glibc systems):

FieldMeaning
ut_type1 RUN_LVL, 2 BOOT_TIME, 5 INIT_PROCESS, 6 LOGIN_PROCESS, 7 USER_PROCESS (login), 8 DEAD_PROCESS (logout)
ut_pidPID of the login process
ut_lineTerminal (pts/0), max 32 bytes
ut_idTerminal suffix or inittab ID
ut_userUser name, max 32 bytes; empty on logout records in wtmp
ut_hostRemote host, or kernel version for boot records, max 256 bytes
ut_sessionSession ID
ut_tvtv_sec and tv_usec, both 32-bit on biarch platforms
ut_addr_v6Remote IP (IPv4 in the first word)

struct lastlog: ll_time (32-bit epoch), ll_line (32 bytes), ll_host (256 bytes), 292 bytes per slot at offset UID x 292. wtmpdb stores Type, User, Login, Logout, TTY, RemoteHost and Service (the PAM service) per row.

Timestamps

Classic records store Unix epoch seconds plus microseconds, UTC. last prints in the analysis host's local zone, so set TZ=UTC. The 32-bit fields overflow in January 2038. wtmpdb stores Login and Logout as microseconds since the epoch.

TZ=UTC last -F -i -x -f /mnt/evidence/var/log/wtmp
sqlite3 wtmp.db "SELECT User, TTY, RemoteHost, Service,
  datetime(Login/1000000,'unixepoch'), datetime(Logout/1000000,'unixepoch') FROM wtmp;"

Retention

logrotate's standard stanzas rotate wtmp and btmp monthly and keep one old generation (wtmp.1, btmp.1), so expect one to two months of history. The stanzas live in /etc/logrotate.conf or /etc/logrotate.d/wtmp and btmp depending on distribution. utmp is cleared at every boot. lastlog keeps one record per UID forever, overwritten at each login. wtmpdb rotate moves old entries into dated wtmp_<date>.db files next to the database (/var/lib/wtmpdb/ upstream, /var/log/ on Debian).

Collection

Copy the files with metadata. Size matters: a wtmp that is not a multiple of the record size, or much smaller than expected, is a finding.

cp -a /mnt/evidence/var/log/{wtmp,wtmp.1,btmp,btmp.1,lastlog} /cases/2026-017/ 2>/dev/null
cp -a /mnt/evidence/var/lib/wtmpdb /mnt/evidence/var/lib/lastlog /cases/2026-017/ 2>/dev/null
cp -a /mnt/evidence/var/log/wtmp.db /cases/2026-017/ 2>/dev/null
# Live only: current sessions
cp -a /run/utmp /media/ir/ && who -a > /media/ir/who.txt

UAC collects /var/log and /var/run/utmp and runs last, lastb, lastlog and utmpdump in live response. Velociraptor's Linux.Sys.LastUserLogin parses wtmp* files on the endpoint.

Parsing

last -F -i -x -f wtmp            # full dates, IPs, system events
lastb -F -i -f btmp              # failed logins
utmpdump wtmp > wtmp.txt         # every record and field, text
wtmpdb last -F -f wtmp.db        # wtmpdb databases
lastlog2 -d lastlog2.db          # lastlog2 databases

The classic lastlog command reads the live system's file, so for an image copy read the 292-byte slots with a short script (slot number = UID, skip all-zero slots). Plaso's utmp parser handles wtmp, btmp and utmp for super timelines. Linux Log Parser reads auth.log / secure, syslog, journal files, audit.log and wtmp / btmp / lastlog in the browser and merges them into one timeline with rebuilt login sessions; nothing is uploaded.

Investigator tips

  • Run on an analysis host whose last matches the record layout (64-bit glibc). Debian 13 no longer ships last; use a util-linux build from another distribution, or Plaso.
  • In utmpdump output, look for zeroed records, timestamps that go backwards, and logins with no logout. utmpdump -r converts edited text back to binary, so tampering is easy for root: prove it through disagreement with auth.log, the journal and audit.log USER_LOGIN.
  • A burst of btmp entries from one IP followed by a wtmp login from the same IP is the classic brute-force success pattern.
  • A lastlog time newer than the last matching wtmp record means wtmp lost entries (rotation or deletion).
  • Compare the ut_host kernel version on reboot records with the installed kernels to spot boots into an unexpected kernel.
  • Zero-byte wtmp or btmp with an old mtime on an active server is a common anti-forensics sign (> /var/log/wtmp).

See also