Linux登录审计实战:last、lastlog与wtmp解析
排查服务器异常登录时last和lastlog这两个命令经常被一起提起但很多同学对它们的理解只停留在“敲一下看看谁登录过”。真正遇到问题就会发现为什么cat /var/log/wtmp全是乱码为什么有的机器last只有一行wtmp begins ...为什么lastlog里一片**Never logged in**为什么同样的命令换个发行版参数就不认识了本文围绕 Linux 用户管理中的登录信息审计展开把last、lastlog、lastb、who这几个命令串成一条完整链路先讲清楚记录文件之间的关系再逐条拆解参数最后给出一个可以直接落地的登录审计脚本和定时任务配置。运维同学可以拿来做巡检后端和测试同学可以拿来做环境排障刚接触 Linux 的同学也能顺着示例一步步跑通。1. 背景与核心概念1.1 登录信息从哪里来Linux 是一个多用户操作系统任何一个用户登录、登出、系统重启、运行级别切换都会在内核之上的用户态留下痕迹。这些痕迹不是普通日志文本而是被写入到一组专用的二进制数据库文件里最常见的就是wtmp、btmp、utmp和lastlog。可以把这几个文件理解成“登录事件的不同切片”utmp记录的是当前登录的用户是实时状态表。wtmp记录的是历史登录、登出、重启事件是流水账。btmp记录的是失败的登录尝试。lastlog记录的是每个用户最近一次登录的时间、来源地址和终端。last命令本质上是wtmp的解析器lastb是btmp的解析器lastlog是lastlog文件的解析器who和w则是utmp的解析器。理解了这一点后面所有的现象都能解释得通。1.2 last 与 lastlog 的区别很多新手会把这两个命令混为一谈实际上它们的职责完全不同。last回答的是“最近发生过哪些登录行为”它是一次事件流同一个人登录五次就会出现五行中间还夹杂reboot系统启动记录。你可以用它回溯某个时间点是谁登录了机器、从哪个 IP 登录、在线了多久。lastlog回答的是“每个用户最后一次登录是什么时候”它是一张快照表一个用户在输出里最多只占一行。它更适合做“长期未登录账号”的盘点比如排查离职人员遗留账号、检查系统内置账户是否被使用过。一个看过程一个看结果配合使用才能覆盖完整的审计场景。1.3 为什么不能直接用 cat 查看/var/log/wtmp这类文件采用固定的二进制结构存储每条记录包含类型、PID、终端名、用户名、主机名、时间戳等字段字段之间是紧凑排列的字节而不是换行分隔的文本。直接用cat打开终端会把不可打印字符原样吐出来屏幕上就会出现一堆奇怪的符号甚至把当前终端状态搞乱比如字符集错乱。正确的打开方式是使用专门的解析工具。除了last系列命令utmpdump也是一个很有用的工具它能把二进制记录转换成可读的文本格式方便做字段级分析# 以文本形式导出 wtmp 记录只读不会修改文件 utmpdump /var/log/wtmp | head -20需要提醒的是utmpdump支持用-r参数把文本反向导入回二进制格式这个操作具有破坏性会覆盖目标文件内容。生产环境上只建议用它的只读能力任何写入类操作都必须先在测试机验证并做好文件备份。2. 环境准备与版本说明2.1 测试环境与版本约定本文示例在常见的 x86_64 Linux 发行版上验证思路通用不同发行版的命令来自不同的软件包具体版本请以你机器上的--version输出为准# 查看 last / lastlog 所属软件包与版本 last --version lastlog --version # 确认命令来自哪个包RHEL/CentOS 系 rpm -qf $(command -v last) rpm -qf $(command -v lastlog) # 确认命令来自哪个包Debian/Ubuntu 系 dpkg -S $(command -v last) dpkg -S $(command -v lastlog)在多数发行版中last、lastb、lastlog都来自util-linux软件包。util-linux版本差异会直接影响参数支持情况比如-ssince、-ppresent、--time-format这些选项在老版本上可能不存在。如果你的机器提示last: invalid option -- s先确认版本不要急着怀疑系统坏了。本文不绑定具体版本号示例中出现的参数如果在你机器上不被识别请以man last的本地手册为准这是最可靠的做法。2.2 检查记录文件是否存在在开始之前先确认四个关键文件的状态。部分精简系统、容器镜像、嵌入式系统中这些文件可能根本不存在或者存在但从未被写入# 查看登录记录相关文件 ls -lh /var/log/wtmp /var/log/btmp /var/log/lastlog /run/utmp 21 # 查看文件权限与所属组 stat -c %n %A %U:%G %s /var/log/wtmp /var/log/btmp /var/log/lastlog /run/utmp正常输出中wtmp和btmp的所有者通常是root所属组是utmp权限位一般是0664或0644。lastlog是稀疏文件ls -lh显示的大小可能远小于du统计的实际占用这是正常现象因为它按 UID 作为下标直接定位记录中间大量空洞不占磁盘块。如果文件不存在用下面的方式创建注意不要在生产环境随意清空已有文件# 创建空的 wtmp 记录文件仅在文件缺失时使用 sudo touch /var/log/wtmp sudo chown root:utmp /var/log/wtmp sudo chmod 0664 /var/log/wtmp2.3 准备用于测试的登录记录为了演示效果建议在测试机上准备几条真实的登录记录。最直接的方式是通过 SSH 本机登录几次或者用su -切换用户这两种方式都会通过 PAM 模块写入wtmp# 查看当前系统已有用户 cut -d: -f1,3 /etc/passwd | tail -10 # 通过 su 产生一条登录记录需要知道目标用户密码 su - testuser # 退出后立刻查看记录 exit last -n 5如果测试环境是 Docker 容器很可能看不到任何记录。原因在于容器默认不挂载/run/utmp而且很多精简镜像没有运行完整的 PAM session 流程。这种情况下不要怀疑命令有问题换一台物理机或完整虚拟机验证即可后文第 7 章会专门说明容器环境的处理方式。3. last 命令核心用法拆解3.1 默认输出逐列解释先看一个最基础的调用last不带任何参数时默认读取/var/log/wtmp按时间倒序输出最近的登录记录last输出格式类似下面这样字段含义比具体数值更重要root pts/0 192.168.10.21 Mon Mar 10 09:12:33 2025 - Mon Mar 10 11:30:02 2025 (02:17) testuser pts/1 192.168.10.35 Mon Mar 10 08:45:10 2025 - still logged in root tty1 Mon Mar 10 08:30:00 2025 - down (00:05) reboot system boot 5.15.0-91-generic Mon Mar 10 08:20:11 2025 - Mon Mar 10 18:02:44 2025 (09:42) root pts/0 192.168.10.21 Sun Mar 9 20:11:40 2025 - Sun Mar 9 22:03:19 2025 (01:51) wtmp begins Sun Mar 2 03:14:07 2025逐列来看第一列是用户名如果记录的是系统事件这里会出现reboot、shutdown、runlevel等特殊标识。第二列是终端名pts/0表示伪终端通常来自 SSH 或图形终端tty1表示本地控制台。第三列是登录来源本地登录这一列通常为空远程登录会显示 IP 或主机名system boot行的这一列显示的是内核版本。第四列开始是时间区间格式为“登录时间 - 登出时间”如果用户当前还在线会显示still logged in如果记录被系统非正常终止可能显示- crash或- down。最后一列括号内是本次登录的持续时长格式为(HH:MM)或(DHH:MM)超过一天会带上天数前缀。最后一行wtmp begins ...是文件最早一条记录的时间它同时可以作为“这台机器的登录审计能回溯到多久以前”的判断依据。如果这一行显示的时间非常近说明wtmp刚被轮转或重建过历史记录已经不可查。3.2 高频参数与使用场景last的参数不算多但每一个都对应明确场景。下面这张表按使用频率排序建议先记住前四个参数作用典型场景-n 数量只显示最近 N 条记录快速看最近几次登录-i来源列显示 IP 而非主机名避免 DNS 反解拖慢速度-F显示完整时间含年份、秒跨年审计、精确对时-x同时显示关机、运行级别切换记录排查非计划重启-a把主机名放到最后一列终端列对齐便于阅读-d对来源 IP 做反向解析需要看域名时使用-w不截断用户名和域名长用户名场景-f 文件指定记录文件读取轮转后的历史文件-t 时间只看指定时间之前的记录复盘某个事故时间点-b显示系统最近一次启动时间快速判断开机时间几个典型组合# 看最近 10 条来源显示 IP时间显示完整 last -n 10 -i -F # 看最近 3 次系统启动时间 last -x reboot -n 3 # 读取轮转后的历史文件注意文件名按实际轮转结果调整 last -f /var/log/wtmp.1 -n 20-i这个参数在实际运维中很关键。默认情况下last会对来源 IP 尝试反向 DNS 解析如果机器所在网络的 DNS 响应慢last可能会卡住十几秒甚至更久。在跳板机或内网环境执行审计脚本时务必加上-i否则定时任务里很容易出现超时堆积。3.3 关机、重启与运行级别记录last默认只显示用户登录事件但wtmp里其实还记录了系统级事件。加-x就能把它们一起展示出来last -x -n 20输出中会出现shutdown、runlevel、reboot这几类条目。其中runlevel行的格式比较特殊通常形如runlevel (to lvl 5)表示系统运行级别发生了变化这一列在不同发行版的展示略有差异不必强记格式关注时间点即可。排查“服务器为什么半夜重启了”这类问题时这个组合非常有用。你可以先用last -x reboot定位重启时间再去/var/log/messages或journalctl -b -1里查对应时间点的日志。需要注意的是某些发行版在正常关机时会写入shutdown记录但如果服务器是断电、内核 panic 或强制 resetwtmp里可能只有下一次的reboot记录中间会缺失关机事件。所以“没有 shutdown 记录”不等于“没有关机”只能作为辅助判断。3.4 时间过滤与事故复盘-t参数用于只看某个时间点之前的记录格式是YYYYMMDDHHMMSS# 查看 2025 年 3 月 10 日 12 点之前的所有登录记录 last -F -t 20250310120000较新版本的util-linux还支持-s从某时间开始和--time-format自定义时间格式。-s配合-t就能框定一个时间窗口非常适合事故复盘# 查看 2025-03-10 08:00 到 12:00 之间的登录记录 last -F -s 20250310080000 -t 20250310120000如果本地last不支持-s可以用awk做后置过滤虽然效率低一点但兼容性更好# 用 awk 过滤出包含指定日期的记录适用于老版本 last -F -i | awk $4Mar $510这类命令的价值在于缩小排查范围。当一台机器上有几十个账号、每天上百条记录时靠肉眼翻是不现实的先用时间窗口把范围压到几十行再看来源 IP 和用户名效率会高很多。4. lastlog 命令核心用法拆解4.1 默认输出与字段含义lastlog读取/var/log/lastlog为每个用户输出最近一次登录信息sudo lastlog输出格式如下Username Port From Latest root pts/0 192.168.10.21 Mon Mar 10 11:30:02 0800 2025 bin **Never logged in** daemon **Never logged in** testuser pts/1 192.168.10.35 Mon Mar 10 08:45:10 0800 2025四列含义分别是用户名、登录终端、来源地址、最近登录时间。系统内置账户如bin、daemon、sys从未登录过时间列会显示**Never logged in**。这份输出最大的价值是做账号盘点。正常的生产服务器上bin、daemon、lp、mail这类账户不应该有登录记录一旦发现某个系统账户的Latest列出现了时间就需要立刻排查是有人用这个账户登录了还是有服务被配置成以该账户交互式登录。建议用sudo执行。虽然/var/log/lastlog在多数发行版上对其他用户可读但不同发行版的权限策略存在差异用 root 执行能保证结果完整。4.2 按天数过滤找出长期未登录账号lastlog有两个非常实用的天数过滤参数理解它们的语义差异很重要-b 天数只显示最后一次登录早于 N 天前的用户用来找“长期没登录”的账号。-t 天数只显示最近 N 天内登录过的用户用来找“活跃”账号。# 找出超过 90 天没有登录过的用户 sudo lastlog -b 90 # 找出最近 7 天内登录过的用户 sudo lastlog -t 7-b 90这个能力在账号治理中特别好用。企业环境中经常有人员离职、项目结束、临时账号忘记回收的情况把这些账号按月筛出来走审批流程后锁定或删除是降低攻击面的有效手段。需要特别提醒执行userdel删除用户、或者用usermod -L锁定账号之前必须确认该账号没有被任何定时任务、服务进程、数据库连接所使用。删除前建议先执行ps -u 用户名检查是否有运行中的进程并备份/etc/passwd、/etc/shadow、/etc/group三个文件。这类操作属于生产环境变更必须走变更流程在测试环境验证后再执行。4.3 单用户查询与输出解读排查具体账号时用-u直接定位避免输出太长# 查询单个用户的最后登录信息 sudo lastlog -u testuser # 查询多个用户部分版本支持逗号分隔 sudo lastlog -u root,testuser如果某个用户显示**Never logged in**有几种可能需要结合场景判断第一种是账号确实从未被使用过比如刚创建的服务账号第二种是账号通过非交互方式使用比如su -s /bin/false、sudo -u、cron 任务这些方式未必会更新lastlog第三种是lastlog文件被重建过历史信息丢失。还有一种容易被忽略的情况通过 SSH 密钥登录、且 PAM 配置中关闭了pam_lastlog模块时lastlog可能不更新但wtmp仍然有记录。所以判断一个账号是否被使用过最好同时看lastlog -u和last | grep两个都对不上再下结论。5. 完整实战搭建一套登录审计脚本5.1 需求拆解与设计思路前面讲的都是单条命令实际运维中更需要的是“一键出报告”。我们把需求拆成四块第一块是当前在线情况用who快速看谁还在线第二块是最近登录流水用last输出最近 N 条第三块是失败登录排行用lastb统计来源 IP识别是否存在暴力破解第四块是僵尸账号盘点用lastlog -b找出长期未登录的账号。设计上遵循三个原则只读不写、失败不中断、输出可归档。脚本里所有命令都只读取日志文件不做任何修改每条命令后面加|| true避免某条失败导致整体退出最终输出重定向到带日期的文件方便后续比对。5.2 目录结构与脚本骨架先创建目录sudo mkdir -p /var/log/login-audit sudo chmod 0750 /var/log/login-audit脚本文件放在/usr/local/bin/login-audit.sh完整内容如下#!/bin/bash # 文件路径/usr/local/bin/login-audit.sh # 用途汇总 wtmp / btmp / lastlog 的登录审计信息 # 用法sudo bash /usr/local/bin/login-audit.sh [未登录天数默认90] set -u STALE_DAYS${1:-90} NOW$(date %Y-%m-%d %H:%M:%S) echo echo 登录审计报告 echo 生成时间${NOW} echo 主机名$(hostname) echo 长期未登录阈值${STALE_DAYS} 天 echo echo echo ---- [1] 当前在线用户 ---- who 2/dev/null || echo 无法读取 utmp当前无在线会话记录 echo echo ---- [2] 最近 15 条登录流水 ---- last -n 15 -i -F 2/dev/null || echo 无法读取 wtmp echo echo ---- [3] 最近 3 次系统启动 ---- last -x reboot -n 3 2/dev/null || true echo echo ---- [4] 失败登录来源 TOP 10 ---- lastb -n 2000 2/dev/null \ | awk NF3 {print $3} \ | sort | uniq -c | sort -rn | head -10 \ || echo 无 btmp 记录或权限不足 echo echo ---- [5] 超过 ${STALE_DAYS} 天未登录的账号 ---- lastlog -b ${STALE_DAYS} 2/dev/null \ | grep -v Never logged in \ | grep -v ^Username \ || echo 无匹配记录 echo echo ---- [6] 从未登录过的账号数量 ---- lastlog 2/dev/null | grep -c Never logged in || echo 0 echo echo ---- 报告结束 ----脚本里有几处细节值得说明。set -u让脚本在引用未定义变量时报错退出配合${1:-90}的默认值写法既保证了参数可选又能提前暴露拼写错误。这里没有用set -e因为审计脚本的定位是“尽量把能收集的信息都收集到”某条命令失败不应该中断整个流程。lastb那段用了awk NF3 {print $3}。原因是失败登录记录中有些条目用户名或终端为空字段数不足三行直接取第三列会拿到空值或错位数据。加上字段数判断后统计结果更干净。lastlog那段连续用了两个grep -v先把Never logged in的行去掉再去掉表头。如果只想去掉表头也可以直接用tail -n 2但表头在部分版本中不存在grep -v ^Username的兼容性更好。5.3 赋予权限并首次运行# 赋予执行权限属主设为 root避免被普通用户篡改 sudo chown root:root /usr/local/bin/login-audit.sh sudo chmod 0750 /usr/local/bin/login-audit.sh # 首次运行默认阈值 90 天 sudo /usr/local/bin/login-audit.sh预期输出会按章节依次打印六个部分。如果你在测试机上刚创建完用户还没登录过第 5 部分可能为空这是正常的。可以先手动su -登录几次或者用 SSH 连接几次再重新执行脚本对比结果。第 4 部分如果显示“无 btmp 记录或权限不足”先确认/var/log/btmp是否存在以及当前用户是否有读取权限。btmp的权限通常是0600 root:utmp普通用户读不到必须用 root 执行。5.4 输出重定向与归档单次执行看结果长期使用就要归档。推荐把输出重定向到带日期的文件sudo /usr/local/bin/login-audit.sh 90 \ /var/log/login-audit/audit-$(date %F).log 21归档的价值在于横向对比。比如某天发现失败登录突然暴增可以翻出前几天的报告比对来源 IP 是否相同再比如发现某个账号的登录记录消失可以确认是账号被删除了还是wtmp被清理了。单次快照看不出趋势连续归档才能形成基线。5.5 配置定时任务与日志轮转用 cron 每天凌晨执行一次# 编辑 root 的定时任务 sudo crontab -e写入下面一行。注意 cron 中%有特殊含义必须写成\%转义0 3 * * * /usr/local/bin/login-audit.sh 90 /var/log/login-audit/audit-$(date \%F).log 21审计报告本身也需要轮转否则一年下来文件数量会失控。新建一个 logrotate 配置# 文件路径/etc/logrotate.d/login-audit /var/log/login-audit/*.log { daily rotate 30 compress delaycompress missingok notifempty create 0640 root root }配置含义逐条说明daily表示按天轮转rotate 30保留 30 份历史compress开启 gzip 压缩delaycompress让最近一份保持未压缩方便直接查看missingok表示目录为空时不报错notifempty表示空文件不轮转create指定新文件的权限和属主。配置写完后不要直接等第二天用logrotate -d做一次 dry run 验证语法# 调试模式只打印动作不实际执行 sudo logrotate -d /etc/logrotate.d/login-audit # 确认无误后强制执行一次 sudo logrotate -f /etc/logrotate.d/login-audit6. 常见问题与排查思路实际使用中遇到的问题大多集中在“命令没有输出”和“输出不符合预期”两类。下面这张表整理了高频现象建议收藏备用问题现象常见原因解决思路last只显示wtmp begins ...一行wtmp 被轮转、被清空或系统刚安装检查/var/log/wtmp.1等历史文件用last -f读取last命令卡住十几秒才返回来源 IP 反向 DNS 解析超时加-i参数跳过解析或检查/etc/resolv.conflast报No such file or directory目标记录文件不存在确认路径必要时按 2.2 节创建文件并授权cat /var/log/wtmp输出乱码wtmp 是二进制文件不能直接读改用last或utmpdump解析lastlog全部显示Never logged inlastlog 文件被重建或 PAM 未写入检查/etc/pam.d/配置确认pam_lastlog是否启用lastlog提示权限不足/var/log/lastlog权限受限用sudo执行lastb无任何输出btmp 为空或权限不足确认/var/log/btmp存在用 root 执行容器里last完全没记录容器未挂载 utmpPAM session 不完整见 7.4 节容器环境应以应用日志为主last: invalid option -- sutil-linux 版本较老用awk做后置时间过滤替代用户名或域名被截断成默认列宽限制加-w参数显示完整内容针对其中几个问题展开说说排查顺序。现象一last输出极少甚至为空。第一步看文件是否存在、大小是否为 0ls -l /var/log/wtmp第二步看是否有轮转历史ls -l /var/log/wtmp*第三步如果存在wtmp.1直接读取last -f /var/log/wtmp.1 -n 20第四步如果文件是被意外清空的比如有人执行了echo /var/log/wtmp或者误删重建那历史记录已经无法恢复。这也说明审计记录需要额外备份不能只依赖本地文件。现象二lastb记录暴增。先统计来源 IP 分布再看用户名分布# 按来源 IP 统计失败次数 sudo lastb -n 5000 | awk NF3 {print $3} | sort | uniq -c | sort -rn | head -20 # 按尝试的用户名统计 sudo lastb -n 5000 | awk NF1 {print $1} | sort | uniq -c | sort -rn | head -20如果某个 IP 短时间内出现几百次失败基本可以判定为自动化扫描。处置方式包括在防火墙层面限制该来源、禁用密码登录改用密钥认证、调整 SSH 的MaxAuthTries和LoginGraceTime。所有安全加固操作都必须在授权范围内进行并且先在测试环境验证配置不会把自己锁在门外。现象三lastlog查不到某个用户。先用id确认用户存在再单独查询id testuser sudo lastlog -u testuser如果用户存在但无记录结合last | grep testuser交叉验证。两条路径都查不到说明该账号确实没有被交互式登录过这在服务账号上很常见。7. 最佳实践与工程建议7.1 权限控制与最小暴露登录记录文件本身就包含敏感信息谁在什么时间从哪个 IP 登录了服务器。这些信息如果被低权限用户随意读取等于把内网拓扑和人员活动规律暴露出去。建议按下面的原则控制权限# 确认关键文件权限 sudo chmod 0664 /var/log/wtmp sudo chmod 0600 /var/log/btmp sudo chmod 0644 /var/log/lastlog sudo chown root:utmp /var/log/wtmp /var/log/btmpbtmp权限设为0600是常见做法因为失败登录记录里往往包含被尝试的用户名泄露出去等于告诉攻击者哪些账号名是有效的。审计脚本本身也应该限制为 root 可执行避免普通用户通过脚本间接获得敏感信息。7.2 审计记录保全本地的wtmp会随着 logrotate 轮转默认配置下历史记录保留时间有限。如果所在业务有合规要求需要把审计报告定期同步到集中日志平台或独立的归档存储。推荐的做法是在审计脚本输出后再追加一次文件校验# 生成报告后计算校验值便于后续确认文件未被篡改 sha256sum /var/log/login-audit/audit-$(date %F).log \ /var/log/login-audit/checksum.log同时提醒一句清理wtmp、btmp、lastlog属于影响审计能力的操作任何情况下都不要为了让日志“看起来干净”而随意清空。如果确实需要归档后清理必须走审批流程并确保归档副本已经落地且可读。7.3 与 journalctl 的配合使用现代 systemd 系统上很多登录相关信息在 journal 里也有记录。last和journalctl不是替代关系而是互补# 查看本次启动以来的 sshd 日志 journalctl -u sshd -b --no-pager | tail -50 # 查看上次启动的日志排查重启前发生了什么 journalctl -b -1 --no-pager | grep -i session openedwtmp的优势是结构化、查询快、跨发行版通用journal 的优势是信息全、带上下文、可持久化到磁盘。实际排查时建议先看last定位时间点再用journalctl --since拉取对应时间段的详细日志。要注意 journal 默认可能不持久化重启后丢失。需要长期保留时要确认/var/log/journal目录存在# 检查 journal 是否持久化 ls -d /var/log/journal 2/dev/null echo 已持久化 || echo 未持久化重启后丢失7.4 容器与精简系统的特殊处理在容器中执行last常常没有任何输出原因有三点容器通常不挂载/run/utmp镜像里可能根本没有/var/log/wtmp容器内一般不会运行完整的 PAM session 流程。这种情况下不要试图在容器里“修好”last正确的思路是换审计入口# 容器内查看应用自身的访问日志更可靠 docker logs --since 24h 容器名 21 | tail -100 # 从宿主机侧观察容器的进程与连接 docker top 容器名 ss -tnp | grep 容器PID容器场景下的登录审计应该放在宿主机层和编排平台层比如统一采集宿主机的 sshd 日志、在 API Server 侧开审计日志。容器内部只关注应用层身份认证记录这是更合理的设计。7.5 审计结果的使用边界最后强调一个容易被忽视的点last和lastlog提供的是记录不是证据链。它们能告诉你“发生过什么”但不能证明“谁做的”。IP 可能是 NAT 后的地址账号可能被共享时间戳依赖系统时钟准确性。所以在做安全事件定性时必须结合多源信息交叉验证防火墙日志、应用访问日志、堡垒机会话录像、系统完整性监控。单凭一条last记录就下结论很容易误判。同时所有涉及账号锁定、删除、权限变更的操作都必须在获得明确授权后执行并提前做好数据备份和回滚方案。8. 总结与学习路线把这篇内容串起来看核心其实就三层。第一层是文件层wtmp记历史登录、btmp记失败登录、utmp记当前会话、lastlog记每人最后一次登录四个文件各司其职。第二层是命令层last解析流水、lastlog解析快照、lastb专看失败、who看在线参数上重点掌握-n、-i、-F、-x、-b、-t这几个。第三层是工程层把命令组合成脚本、配上定时任务和日志轮转、做好权限控制和归档保全。想继续深入的话建议沿着三条线走。第一条是 PAM 机制搞清楚pam_lastlog、pam_unix、pam_tally2这些模块是怎么把登录事件写进各种文件的这能解释很多“为什么记录不更新”的疑问。第二条是auditd它提供的是系统调用级别的审计能力粒度比wtmp细得多适合做高安全要求的场景。第三条是集中日志方案把多台机器的登录记录汇总到统一平台才能真正形成可检索、可告警的审计体系。建议你现在就找一台测试机把第 5 章的脚本跑一遍再故意用错误密码登录几次观察lastb的变化。亲手跑过一次比看十遍文档记得都牢。脚本可以直接收藏备用后面做服务器巡检时改个阈值就能用。