Linux last命令完全指南:从登录查看到安全审计

Linux last命令完全指南:从登录查看到安全审计 last 命令是 Linux 运维里查登录记录的经典工具也是排查服务器异常登录、账号滥用、重启历史时绕不开的一把“考古铲”。很多人只会在终端敲一个last看到一堆用户名、日期、IP 就完事对这个命令背后的文件格式、日志轮转机制、字段含义却不太清楚。这篇博文我打算用大量实际可复现的示例把 last command 的常见用法、输出解读、故障排查和自动化审计思路一次讲透内容适合刚接触 Linux 的新手也适合希望补全登录审计细节的运维和开发同学。1. 项目概述一次登录一份日志一条命令1.1 last 命令是什么它到底在查什么last是 Linux 系统里用来查看用户登录历史的命令它本身不做记录而是读取系统维护的 wtmp 日志文件。大多数发行版把这个文件放在/var/log/wtmp文件里保存的是历史登录、退出、系统重启、时间变更等事件记录。可以说wtmp 是系统登录行为的“账本”而last是把这个二进制账本翻译成人话的查看器。我第一次接触 last 是在排查一台测试服务器的不明登录行为时当时/var/log/secure里没有异常但last一敲出来就发现有几条来自陌生 IP 的 root 登录记录。从那之后再接手新服务器我开完机第一件事就是跑一遍last -n 20看看这台机器此前被谁登录过、从哪登录的、有没有正常的重启周期。这个习惯一直保留到今天last 虽然简单但在系统安全巡检里确实是出镜率最高的命令之一。需要提醒的是last 和who、w不是同一类工具。who看的是当前谁在线w还能看出每个在线用户正在执行的命令而 last 看的是历史记录。三个命令各管一段配合起来才能还原一台机器的完整登录图景。1.2 数据来源与文件格式别把 wtmp 当文本文件读wtmp 是二进制文件不能用cat或vi直接查看。它的底层结构是一系列固定长度的记录每条记录对应一次登录会话的开始或结束字段包括用户名、登录终端、登录来源 IP、登录时间、退出时间等。具体字段定义在 Linux 源码的struct utmp结构里登录时写入一条注销时再写一条系统重启和关机也会生成对应记录。正因为它是二进制格式直接读取会看到乱码所以才需要 last 这类工具解析。换个角度看这其实是个优点文本日志容易被误编辑和篡改wtmp 的结构反而让手工改动更麻烦。但麻烦不代表不可能如果有人拿到 root 权限依然可以清空或伪造这个文件所以 last 的输出只能作为排查线索不能当作司法级别的证据。还有一个容易踩的坑某些最小化安装的 Linux 系统默认没有/var/log/wtmp。如果执行last提示文件不存在通常会伴随“wtmp begins 1970”之类的输出这是因为系统还没有记录过任何登录事件。遇到这种机器不用慌可以用touch /var/log/wtmp创建文件也可以安装sysstat等工具包时自动补齐。2. 核心场景与选项选型拿到 last 输出之后怎么看2.1 典型使用场景巡检、追踪、取证、审计last 命令最常见的应用场景有这么几类。第一类是日常巡检。登录一台主机后快速查看最近的登录记录确认没有陌生 IP 或陌生账号出现过。这个场景我习惯用last -n 10 -i-n 限制条数-i 把 IP 从域名反查结果转回原始数字格式避免 DNS 解析慢导致命令卡住。第二类是异常登录追踪。当你怀疑服务器被入侵或账号被共享时last 能帮你拉出某个用户在特定时间段的所有登录历史再配合lastb查看失败登录记录。安全审计里经常要求“还原攻击路径”last 的输出就是还原过程的第一块拼图。第三类是重启历史核查。系统无故重启或者运行时长异常时用last reboot能列出每次重启的时间。结合内核日志里的启动时间基本能判断重启是人为执行还是意外宕机。第四类是审计合规。等保、ISO 27001 等检查项通常要求记录并留存登录日志last 配合日志轮转、集中采集比如 rsyslog 转发或 ELK 采集能形成一份可追溯的登录行为时间线。2.2 常用选项对照与选型建议last 的选项不算多但每个选项解决一个特定问题我把高频选项整理成了一张表方便现场翻阅。选项作用使用建议-n 数字只显示最近 N 条记录巡检时用-n 10避免输出刷屏-i显示点分十进制 IP不做 DNS 反查服务器无内网 DNS 或反查慢时必须加-f 路径指定其他 wtmp 文件排查轮转后的旧日志wtmp.1时很常用-x显示系统关机、重启、运行级别变更记录配合reboot、shutdown参数看系统生命周期-R不显示主机名和 IP 字段只关心用户维度时可以让输出更干净-a将主机名/IP 显示在最后一列方便脚本按列切割也方便人眼对齐-d显示远程主机 IP某些系统上配合 -a 使用处理有代理或跳板机的登录场景-t 时间显示指定时间点之前的记录时间格式YYYYMMDDHHMMSS用于时间范围筛选-p 时间段显示指定时间段内的记录比 -t 更直观适合“查某一天”的需求-F显示完整登录和退出时间审计时需要精确到秒可以加-w不把域名截断为短名称有长域名环境建议开启选型上我的习惯是人性化查看用last -n 20 -i排查异常用last -F -i -n 50查轮转日志用last -f /var/log/wtmp.1。不要一上来就敲一个光秃秃的last输出几百行只会让人眼晕还容易错过真正有价值的异常记录。2.3 last 与 who、w、lastb、lastlog 的分工配合这几个命令经常被拎出来对比我直接说结论。who 查当前在线用户数据来源是/var/run/utmp是“此刻快照”w 在 who 的基础上多了终端号、登录时长和当前执行的命令是“实时监控”last 查 wtmp是“历史档案”lastb 查 btmp专记失败登录是“攻击告警”lastlog 查/var/log/lastlog记录每个用户最近一次登录时间是“全量用户概览”。实际排查时我通常是五连招先 last 看历史再 lastb 看爆破然后 who 看当前在线lastlog 看有没有用户首次登录最后 w 看在线用户在干什么。这一套下来一台机器的登录画像基本就清晰了。拿 last 单独使用没问题但和这几个命令组合才能覆盖完整链路。3. 实操过程与核心环节实现从示例到解读3.1 最基础的 last 输出怎么看懂直接执行last输出大概是这样的$ last -n 10 -i root pts/0 192.168.1.20 Thu Dec 12 09:15 still logged in zhangsan pts/1 10.0.0.8 Thu Dec 12 08:42 - 08:43 (00:01) reboot system boot 4.18.0-477.el8.x86_64 Thu Dec 12 08:40 still running root pts/0 192.168.1.20 Wed Dec 11 22:10 - 22:30 (00:20) root pts/0 192.168.1.20 Wed Dec 11 09:02 - 09:22 (00:20) wtmp begins Wed Dec 11 08:30:01 2024每一行从左到右依次是用户名、登录终端、登录来源IP 或主机名、登录开始时间、退出时间、会话时长。最后一行wtmp begins表示当前 wtmp 文件里的最早记录时间注意这不代表系统第一次安装时间而是这个日志文件开始记录的时间日志轮转后这个时间会被重置。几个特别值得注意的字段still logged in表示该会话当前仍在线对应到who就是还在系统里的用户still running表示系统从那个时间点启动后一直没关过机crash字样虽然不常见但出现时代表系统没有正常关机比如断电或内核崩溃。crash在部分系统上显示为gone - no logout含义一样。终端名也藏着信息tty开头表示本地终端登录物理终端或串口pts/N表示伪终端登录通常来自 SSH、SSH 跳板或终端工具。看到pts但来源 IP 很奇怪时就要重点排查。3.2 用 -x 还原系统重启和关机时间线last -x会把系统事件也输出出来最典型的是reboot和shutdown记录$ last -x -n 15 -i reboot system boot 4.18.0-477.el8.x86_64 Thu Dec 12 08:40 still running shutdown system down Thu Dec 11 21:30 - 21:33 (00:02) reboot system boot 4.18.0-477.el8.x86_64 Thu Dec 11 20:10 still running这里能看到系统每次开机、关机的时间点。配合uptime看当前运行时长配合/var/log/messages或journalctl看关机前后的系统日志就能判断是计划内维护还是异常掉电。我自己遇到过一台机器每隔两三天就自动重启last -x扫一遍发现每次重启前都有shutdown记录再翻系统日志找到是一条定时任务执行的shutdown -r问题当场定位比瞎猜高效得多。要注意的是shutdown记录行里的登录时间和退出时间分别代表“开始关机”和“关机流程结束”会话时长是关机过程耗时。这部分输出在不同发行版里字段对不齐也正常别死抠格式。3.3 用 -f 解析轮转后的历史日志默认情况下last 只读/var/log/wtmp。但生产环境大多配置了 logrotate日志会按天或按大小轮转生成wtmp.1、wtmp.2.gz之类的旧文件。查历史记录时就要手动指定文件$ last -f /var/log/wtmp.1 -n 20 -i如果旧日志被压缩成了.gzlast -f直接读不行先解压再读$ zcat /var/log/wtmp.2.gz /tmp/wtmp.2 $ last -f /tmp/wtmp.2 -n 20 -i注意这会把解压后的文件放到 /tmp敏感环境操作完记得删掉。生产环境更推荐的方式是把 wtmp 采集到日志中心在日志中心里按关键字检索而不是留一堆本地解压文件。logrotate 的配置通常在/etc/logrotate.d/wtmp默认策略可能是每个月轮转一次保留一定份数。为了避免 wtmp 无限增长占满磁盘这个配置不要随意删除。轮转文件的保留时长决定你能回溯多久的登录历史建议至少保留 180 天合规要求严格的可以保留更久。3.4 按用户、按重启、按 IP 定向查询last 支持将用户名或特殊关键字作为参数直接筛选。查某个用户$ last zhangsan -n 20 -i查所有重启记录$ last reboot查失败登录需要 btmp 文件存在且通常需要 root 权限$ sudo lastb -n 20 -i查某个 IP 的登录记录这个没有直接参数需要靠 grep 二次过滤$ last -n 200 -i | grep 192.168.1.20在实际安全排查中我常把 IP 筛选和 awk 结合快速统计某个 IP 的登录次数$ last -n 500 -i | awk $3 ~ /^192.168.1.20$/ {count} END {print count}这类组合写法看似基础但在应急响应时非常实用能在最短时间内回答“这个 IP 到底登过几次”这种审计问题。3.5 输出重定向与脚本化处理last 的输出可以重定向到文件也可以交给管道做进一步处理。生成当前在线会话快照$ last -F -i /tmp/login_history.txt用 cron 每天定时收集一份登录快照保留一年就是很多小型团队最朴素的登录审计方案0 2 * * * last -F -i /var/log/login_audit/$(date \%F).log 21注意 cron 里%需要转义成\%这个坑我踩过不止一次。写这种脚本时还要留个心眼last 输出里第一行的wtmp begins末尾不带 IP 字段如果脚本按第三列切 IP要先排除掉这类行或者用grep -v ^wtmp过滤。4. 常见问题与排查技巧实录4.1 “last: /var/log/wtmp: No such file or directory”这个问题我在刚装完最小化系统的 CentOS、Ubuntu 上都遇到过。原因很简单系统里压根没有 wtmp 文件。解决办法就是创建空文件并设置好权限$ sudo touch /var/log/wtmp $ sudo chown root:utmp /var/log/wtmp $ sudo chmod 664 /var/log/wtmp不同发行版对 utmp 组名可能有差异有的叫utmp有的直接归root。创建完文件之后等有人登录一次再试last输出就从wtmp begins变正常了。没配置 sysstat 的最小化系统尤其容易触发这个问题装完系统建议顺手把sysstat安装上它会把 wtmp、btmp 的 logrotate 配置一并处理好。4.2 last 输出变慢卡住不动按下last -n 10之后终端卡了好几秒才出结果这是最烦人的问题之一。主要原因在于 last 默认会对登录来源做 DNS 反查把 IP 解析成主机名。在内网环境 DNS 配置不正确或反查超时时命令就会卡在解析阶段。解决办法就是加-i强制以点分十进制 IP 显示不做反查。如果必须显示主机名可以检查/etc/hosts和/etc/resolv.conf保证 DNS 配置正常。这里我再多提一句生产环境中 last 查询尽量默认加-i一方面省时间另一方面很多审计系统只认原始 IP不需要主机名。4.3 wtmp 文件巨大查询慢且磁盘告警长时间不清理、logrotate 失效或异常写入都会导致 wtmp 文件膨胀。我曾经在一台长时间运行的机器上见过几十 GB 的 wtmp磁盘告警一查竟然是这个文件。处理办法分两步先确认哪个文件占用空间$ sudo du -sh /var/log/wtmp*然后按照既定策略清理。保留最近一个月、归档更早日志是常见做法$ sudo logrotate -f /etc/logrotate.d/wtmp也可以手动清零但清零前一定要先做好备份因为这是审计数据$ sudo cp /var/log/wtmp /var/log/wtmp.bak $ sudo truncate -s 0 /var/log/wtmp有强制合规要求的场景不要手动 truncate优先采用集中采集方案让日志实时上送后再做轮转既保证可追溯又不占本地磁盘。4.4 last 记录被清空如何应对恶意清理痕迹的第一个目标通常就是 wtmp 和 btmp。遇到last输出只剩几条或者wtmp begins时间非常近基本可以判断文件被动过手脚。此时立即把当前的 wtmp 文件做镜像备份$ sudo cp -a /var/log/wtmp /evidence/wtmp.bak $ sudo cp -a /var/log/btmp /evidence/btmp.bak然后检查是否有登录记录被定向到其他文件。部分攻击者会修改系统配置让 SSH 或登录程序把日志写到自定义路径需检查sshd_config的PAM相关配置以及/etc/rsyslog.conf里有没有奇怪的转发规则。还要注意一点光看 last 不够last 只覆盖登录会话攻击者的命令执行痕迹要配合history、auditd、shell history 文件共同排查。4.5 reboot 记录和系统实际启动时间对不上这通常是宿主机和虚拟机时间不一致、RTC 时间配置异常导致的。当你发现last reboot显示的时间和uptime、date对不上时先检查系统时区$ timedatectl再检查硬件时间$ sudo hwclock -r如果系统使用 UTC、硬件时间却是本地时间或反过来就会造成跨时区的偏差。解决方式推荐统一使用 UTC服务器不同时区协作时这一条非常重要。此外某些云平台自带 guest agent 会周期性同步时间大量登录记录上的时间偏移可能来自 NTP 同步跳变。排查时把 last 输出里的登录时间与 NTP 服务日志对照能分清是人为问题还是时间同步问题。5. 延伸实践把 last 从“查看命令”变成“审计工具”5.1 统计登录次数与去重分析把 last 的输出交给 awk、sort、uniq 处理能快速得出很多有价值的数据。统计每个用户登录次数$ last -i | awk {print $1} | sort | uniq -c | sort -nr这个命令会输出所有账号的登录次数reboot、wtmp这类非用户名行也在里面如果干扰视线可以用grep -Evi reboot|wtmp|shutdown过滤。统计来源 IP 次数同理$ last -i -n 1000 | awk {print $3} | grep -E ^[0-9]\.[0-9]\.[0-9]\.[0-9]$ | sort | uniq -c | sort -nr加了正则过滤是为了排除空字段和wtmp begins这种非 IP 行。这套组合是我排查暴力破解来源时的常备武器。5.2 检测非工作时间登录配合date命令和 shell 脚本还能找出凌晨等非常规时段的登录记录。简单思路是循环读取 last 输出的时间字段提取小时判断是否落在非工作时间段。比如查最近 100 条记录里凌晨 0 点到 5 点之间的登录$ last -i -n 100 -F | awk $5 00:00 $5 05:59 {print}这里依赖-F让时间输出更完整。要注意不同系统 last 输出的时间列位置略有差异写脚本前先跑一两条看列结构。非工作时间段登录未必是坏事但要重点核查尤其是 root 账号的深夜登录基本都是高危告警。5.3 与系统审计日志配合做闭环last 适合回答“谁登录过”但回答不了“登录后做了什么”。安全闭环操作中我会把 last 输出与 SSH 日志、sudo 日志、auditd 记录关联起来。典型场景是发现某个 IP 在凌晨登录先用last -i | grep IP确认会话时间再用journalctl -u sshd --since 2024-12-12 01:00 --until 2024-12-12 02:00查看该时段的 SSH 认证日志最后用ausearch查 auditd 里同一时段的命令执行记录形成一条完整行为链。这种多源关联的做法比单看 last 可靠得多因为 wtmp 可被篡改而内核审计日志和集中采集日志的篡改难度更高。生产环境里我建议把 last 输出纳管到日志平台做长期保存并配置关键账号登录告警。5.4 监控新账号与异常登录的实战小脚本这里分享一个我实际用过的巡检脚本片段每天跑一次检测当天新增的用户和当天 root 登录次数。新增用户检查用的是passwd文件比对root 登录次数用 last 统计#!/bin/bash TODAY$(date %b%e) ROOT_LOGIN_COUNT$(last -i -F | grep ^root | grep $TODAY | wc -l) echo [$(date %F %T)] root 今日登录次数: $ROOT_LOGIN_COUNT这只是一个雏形。如果要发给告警系统可以把结果转成 JSON 或直接调用 webhook。脚本的重要前提是服务器时间准确否则统计口径会乱。我在实际部署时常遇到 cron 时区与业务时区不一致的坑建议在脚本开头用export TZAsia/Shanghai之类的方式固定时区管理多地域服务器时尤为重要。5.5 数据可视化与长期留存建议last 输出本质是结构化文本非常适合导入 ClickHouse、Elasticsearch 或简单的 SQLite 做统计。最轻量方式是把 last 输出定期导入 SQLite$ last -F -i /tmp/last_output.txt $ sqlite3 login.db EOF CREATE TABLE IF NOT EXISTS login_logs ( user TEXT, tty TEXT, ip TEXT, login_time TEXT, logout_time TEXT ); EOF然后用 SQL 就能做复杂查询比如“每个 IP 的登录次数排名”“每个用户的平均会话时长”。这套方案比肉眼翻 last 输出可靠得多也方便日后写审计报告。中小型团队没有条件上 ELK 时用last SQLite 定时脚本就能搭出一套登录审计雏形。注意定期备份数据库文件并限制数据库文件的权限因为里面包含敏感登录信息。我在实际项目里还试过一种更轻量的方案把 last 输出接入到 Prometheus 的 textfile collector用 node_exporter 定时抓取登录次数指标再配 Grafana 展示。效果相当直观登录次数曲线异常上升时一眼就能发现问题而不用等人跑到机器上敲命令。5.6 使用 last 时最容易忽略的三个细节第一非 root 用户执行 last 也能看到大部分登录记录因为 wtmp 是 664 权限普通用户具有读权限。所以在多用户服务器上登录历史对全体用户可见。如果这一点违反公司内部信息隔离要求需要调整权限或改用其他审计方案。第二last 记录的是登录会话不一定等于实际的人。同一个人可能用不同账号、不同跳板机登录也可能多个人共享同一账号。做审计时要结合组织账号管理规定否则很容易误判。第三last 时间和当前时间不一致时先查时区和 NTP别急着怀疑系统被入侵。曾经有台机器所有用户登录时间都快了 8 小时排查到最后是系统时区被改成了 UTC虚惊一场。我个人在实际操作中的体会是last 命令学习成本低但用好它需要对 wtmp 机制、日志轮转、系统时间体系有足够理解。想真正搭建可靠的登录审计能力还要把 last 和 SSH 日志、sudo 日志、集中采集系统关联起来。遇到可疑记录多追问一句“这个时间段里系统还发生了什么”往往能找到比表面登录痕迹更重要的线索。最后再分享一个小技巧把alias lastlast -i -n 30写进/etc/profile.d/对新手更友好也能减少误判风险但注意部分审计场景需要完整历史别让 alias 挡住完整输出。