1. 项目概述:为什么我们需要关注用户历史
在Linux服务器运维、安全审计,甚至是团队协作管理的日常工作中,一个看似简单却至关重要的问题是:“刚才谁登录了系统?”“那个关键文件是谁修改的?”“这个异常进程是谁启动的?”无论是排查系统故障、追溯安全事件,还是进行合规性审查,清晰、完整的用户登录及操作历史记录都是我们手中最有力的“时光机”。对于使用Ubuntu这类主流发行版的系统管理员或开发者而言,掌握查看这些历史信息的方法,不是一项可选的技能,而是必备的看家本领。
很多人可能只知道用last命令看看登录记录,或者用history看看自己敲过的命令。但实际上,一个完整的用户活动画像,是由多个分散在系统各处的日志文件和工具共同描绘的。从用户尝试登录的那一刻起(无论成功与否),到他在系统中执行的命令、切换的目录、甚至打开的文件,都可能留下痕迹。这些信息有的记录在专用的二进制日志里,有的藏在用户的个人配置文件中,还有的则需要通过系统审计框架来主动捕获。
本文将带你深入Ubuntu系统,系统地拆解查看用户登录及操作历史的多种方法。我们不仅会介绍像last、who、history这样的基础命令,还会深入解析/var/log/auth.log、/var/log/wtmp、/var/log/btmp等关键日志文件的结构和解读技巧。更重要的是,我们会探讨如何配置更强大的审计工具,如auditd,来记录自定义的、更细粒度的操作事件。无论你是需要快速响应安全事件,还是想建立长期的系统监控机制,这篇文章都将提供从原理到实操的完整路径。
2. 核心思路:构建多层次的历史信息视图
要全面了解用户在Ubuntu系统中的活动,我们不能依赖单一工具或日志,而应该建立一个分层的、互补的信息收集体系。这个体系可以大致分为三个层次:登录与会话层、Shell命令层和系统调用与审计层。每一层关注的重点不同,使用的工具和数据源也不同,结合起来才能形成完整的证据链。
2.1 登录与会话层:谁在何时何地进入了系统
这是追踪用户活动的第一道关卡,核心是回答关于身份验证和会话管理的问题。其信息主要来源于几个关键的文件:
/var/log/wtmp: 这是一个二进制文件,永久性地记录所有成功的用户登录和注销事件。它是last命令的数据源。/var/log/btmp: 同样是一个二进制文件,但专门记录所有失败的登录尝试。这是lastb命令(需要root权限)查看失败登录的数据源,对于发现暴力破解攻击至关重要。/var/log/utmp: 这是一个动态的二进制文件,记录当前系统上的登录用户信息。who、w、users等命令实时读取的就是这个文件。- **
/var/log/auth.log(或/var/log/secure,取决于系统): 这是一个纯文本的详细认证日志。它记录了与身份验证、授权、特权命令(sudo)相关的所有事件,包括成功/失败的登录、sudo使用、su切换用户等,并附有详细的时间戳和来源IP(如果适用)。
注意:
wtmp和btmp是二进制格式,不能直接用cat或less查看,必须使用last、lastb或utmpdump这样的专用工具来解析。而auth.log是文本文件,可以直接查看和用grep、awk等工具分析。
2.2 Shell命令层:用户在终端里做了什么
用户登录后,在Bash、Zsh等Shell中执行的命令历史,是了解其操作意图最直接的证据。这部分信息主要存储在用户的家目录下:
~/.bash_history: 对于使用Bash shell的用户,其历史命令默认保存在这个文件中。需要注意的是,出于性能和安全考虑,Bash默认是在用户退出Shell时才将内存中的历史记录写入此文件,或者在达到$HISTSIZE设定的行数后才会写入。这意味着,如果一个终端会话尚未结束,你在这个会话中执行的命令可能还不会立即出现在.bash_history文件里。- 环境变量控制: Shell命令历史的行为由几个关键环境变量控制:
HISTSIZE: 控制当前Shell会话内存中保留的历史命令条数。HISTFILESIZE: 控制历史文件(如.bash_history)中最大保存的条数。HISTFILE: 指定历史命令文件的路径(默认为~/.bash_history)。HISTCONTROL和HISTIGNORE: 用于控制哪些命令不被记录(例如忽略重复命令、忽略以空格开头的命令等)。
2.3 系统调用与审计层:超越Shell的深度监控
前两层主要覆盖了登录和显式的Shell命令,但对于通过图形界面、脚本、或其他程序执行的文件操作、进程调用、系统配置更改等,就无能为力了。这时就需要更底层的系统审计框架。在Linux上,最强大的工具是auditd(审计守护进程)。
auditd是内核级别的审计系统,它可以按照管理员设定的规则(rules),监控特定的系统调用、文件访问、用户操作等,并将这些事件记录到/var/log/audit/audit.log中。你可以用它来监控:
- 对某个敏感文件(如
/etc/passwd,/etc/shadow)的读取、写入、属性更改。 - 特定用户执行的所有命令(即使他试图清空
.bash_history)。 - 系统的挂载、网络配置变更等特权操作。
auditd的配置更为复杂,但提供了无与伦比的深度和灵活性,是安全审计和合规性要求的基石。
3. 实操解析:查看登录与会话信息
掌握了核心思路,我们开始动手。首先从最常用的登录和会话信息查看工具开始。
3.1 使用last命令查看成功登录历史
last命令是查看历史登录记录的首选工具,它读取/var/log/wtmp文件。
基础用法:
last输出示例:
username pts/0 192.168.1.100 Mon Apr 15 10:23 still logged in username pts/1 192.168.1.100 Mon Apr 15 09:15 - 10:05 (00:50) reboot system boot 5.15.0-91-generic Mon Apr 15 09:14 still running username tty7 :0 Mon Apr 15 09:14 still logged in (unknown :0 :0 Mon Apr 15 09:14 - 09:14 (00:00))- 第一列: 用户名。
reboot表示系统重启,(unknown)可能表示来自图形登录管理器(如GDM)的登录。 - 第二列: 终端类型。
pts/0、pts/1代表伪终端(通常是SSH或终端模拟器),tty7通常是本地图形界面会话,tty1-tty6是本地文本控制台。 - 第三列: 登录来源IP地址或显示服务器(对于本地图形登录显示
:0)。 - 后续列: 登录时间、注销时间(或
still logged in)、会话持续时间。
常用参数:
last -n 10: 仅显示最近10条记录。last username: 仅显示指定用户username的登录记录。last 192.168.1.100: 仅显示来自特定IP地址的登录记录(非常有用!)。last -x: 同时显示系统关机(shutdown)、运行级别改变(runlevel)等事件。last -F: 显示完整的日期和时间(年-月-日 时:分:秒),默认格式可能省略年份。
实操心得:调查安全事件时,我通常会结合last和lastb。先用last确认是否有异常时间或来源的成功登录,再用lastb查看同一时间段是否有大量的失败尝试,这通常是攻击者进行“撞库”或暴力破解的迹象。
3.2 使用lastb命令查看失败登录尝试
lastb命令用法与last几乎完全相同,但它读取的是/var/log/btmp文件,用于查看失败的登录尝试。执行此命令通常需要root权限。
sudo lastb输出格式与last类似,但记录的都是失败的登录。如果发现某个IP在短时间内有数十甚至上百条失败记录,且尝试了不同的用户名(如 root, admin, test, ubuntu等),这几乎可以肯定是恶意扫描或攻击行为。
重要提示:
/var/log/btmp文件可能默认不存在。如果sudo lastb提示 “lastb: /var/log/btmp: No such file or directory”,你需要手动创建它并设置正确的权限,系统才会开始记录失败登录:sudo touch /var/log/btmp sudo chmod 600 /var/log/btmp # 确保只有root可读写 sudo chown root:utmp /var/log/btmp
3.3 使用who,w,users查看当前在线用户
这些命令用于查看当前谁登录在系统上,它们读取/var/log/utmp文件。
who: 显示当前已登录用户列表、终端、登录时间和来源。who # 输出:username pts/0 2024-04-15 10:23 (192.168.1.100)w: 比who更详细,显示用户、终端、登录时间、空闲时间、当前进程(JCPU, PCPU)以及他们正在执行的命令(WHAT)。w # 输出头部信息包括系统当前时间、运行时间、用户数、负载。 # 然后列出每个用户的详细信息,包括他们正在运行的命令(如 bash, top, vim等)。users: 仅以最简洁的形式输出当前登录的用户名,每个用户名占一个输出字段,重复登录会重复显示。常用于脚本中快速判断。
排查技巧:当你通过w命令发现某个用户正在执行一个陌生的、消耗大量资源的进程时,可以直接在命令输出中看到进程名,为后续的ps或kill操作提供了直接线索。
3.4 深入分析/var/log/auth.log认证日志
auth.log是文本日志的宝库,信息最全但也最杂。我们需要用过滤工具来提取有用信息。
1. 查看所有SSH相关登录(成功和失败):
sudo grep -i sshd /var/log/auth.log或者查看最近100行:
sudo tail -100 /var/log/auth.log | grep -i sshd在输出中,关注这样的行:
- 成功登录:
Accepted password for username from 192.168.1.100 port 22 ssh2 - 失败登录:
Failed password for invalid user hacker from 192.168.1.200 port 22 ssh2(尝试了不存在的用户) 或Failed password for root from 192.168.1.200 port 22 ssh2(尝试破解root) - 认证方式: 还可能看到
Accepted publickey for ...,这表示使用了密钥认证。
2. 查看所有sudo特权命令执行记录:
sudo grep -i sudo /var/log/auth.log这会显示谁在何时通过sudo执行了什么命令,例如:username : TTY=pts/0 ; PWD=/home/username ; USER=root ; COMMAND=/usr/bin/apt update
3. 查看特定用户的全部认证活动:
sudo grep "username" /var/log/auth.log4. 使用journalctl查看系统日志(Systemd系统):在Ubuntu新版本中,日志也可能被systemd-journald管理。你可以用journalctl来查看认证日志,它提供了更强大的过滤和时间筛选功能。
# 查看所有与认证相关的日志 sudo journalctl _SYSTEMD_UNIT=ssh.service # 查看今天以来的ssh日志 sudo journalctl -u ssh --since today # 查看特定时间段的日志 sudo journalctl --since "2024-04-15 09:00:00" --until "2024-04-15 11:00:00" | grep -i auth注意事项:auth.log文件会轮转(logrotate),旧的日志会被压缩成auth.log.1.gz,auth.log.2.gz等。要查看这些历史文件,可以使用zcat,zgrep或less(less可以直接打开.gz文件并搜索)。
4. 实操解析:追踪Shell命令历史
用户登录后,他们在终端里的操作轨迹主要保存在命令历史中。
4.1 查看当前用户的Bash历史
最简单直接的就是history命令:
history默认会列出带行号的所有历史命令。你可以通过一些参数来增强:
history 20: 显示最近20条命令。history | grep "apt install": 搜索历史中包含特定关键词的命令。!行号: 重新执行历史记录中对应行号的命令(慎用!尤其是涉及rm等危险命令时,务必先!行号:p预览)。
4.2 深入理解.bash_history文件
history命令显示的是当前Shell会话内存中的历史。而持久化存储则在~/.bash_history。
cat ~/.bash_history # 或使用 less 分页查看 less ~/.bash_history关键特性与陷阱:
- 写入时机: 如前所述,Bash默认在会话退出时才将历史写入文件。这意味着:
- 如果一个恶意用户在SSH会话中执行了破坏性命令,然后直接断开连接(或使会话异常终止),他的命令可能不会被记录到
.bash_history中。 - 你可以通过设置
PROMPT_COMMAND环境变量,让Bash在每次显示提示符后(即每条命令执行后)立即将历史写入文件,但这会增加I/O开销。
- 如果一个恶意用户在SSH会话中执行了破坏性命令,然后直接断开连接(或使会话异常终止),他的命令可能不会被记录到
- 多会话历史交织: 如果你同时打开多个终端标签或SSH连接,每个会话都有自己的内存历史。只有当你退出所有属于同一用户的Bash会话后,这些历史才会被合并写入
.bash_history,且顺序可能交错。 - 历史记录上限: 受
HISTFILESIZE控制,默认通常是1000或2000行。超出部分会被最早的记录覆盖。
4.3 查看其他用户的命令历史
有时你需要调查其他用户的操作。由于.bash_history文件位于用户的家目录下,且权限通常是-rw-------(仅所有者可读),你需要root权限才能查看。
sudo cat /home/otheruser/.bash_history # 或者使用 sudo -u otheruser bash -c 'history',但这只会显示该用户当前shell内存中的历史(如果他有活动会话的话)。重要安全提醒: 直接查看其他用户的历史文件是侵入性操作,应仅在安全审计、故障排查等合法授权场景下进行。同时,高明的攻击者会清空自己的.bash_history文件(history -c && history -w)来掩盖痕迹。因此,不能完全依赖于此。
4.4 增强历史记录:时间戳和更详细的记录
默认的历史记录只包含命令,没有时间戳。这在调查中非常不便。我们可以通过修改Bash配置来增强它。
编辑当前用户的~/.bashrc文件:
nano ~/.bashrc在文件末尾添加以下几行:
# 为历史命令添加时间戳 export HISTTIMEFORMAT="%F %T " # 设置历史文件大小(内存中和文件中) export HISTSIZE=10000 export HISTFILESIZE=20000 # 忽略重复命令和以空格开头的命令 export HISTCONTROL=ignoreboth # 忽略某些特定命令(如退出、清屏等) export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:history" # 在每个命令后立即追加到历史文件(避免丢失) shopt -s histappend PROMPT_COMMAND="history -a;$PROMPT_COMMAND"保存退出后,执行source ~/.bashrc使配置生效。之后,使用history命令,你会看到每条命令前都附带了执行的时间戳,这对于审计来说价值巨大。
5. 高级追踪:使用auditd进行系统级审计
当Shell历史记录可能被篡改或不足以覆盖所有操作(如文件访问、系统调用)时,auditd审计守护进程就是终极武器。它由内核驱动,记录无法被普通用户轻易抹除。
5.1 安装与启动auditd
在Ubuntu上,通常需要安装:
sudo apt update sudo apt install auditd audispd-plugins安装后,服务会自动启动。你可以检查其状态:
sudo systemctl status auditd5.2 配置审计规则
auditd的强大之处在于其灵活的规则系统。规则可以通过命令行临时添加,或写入配置文件/etc/audit/rules.d/audit.rules永久生效。
常用规则示例:
监控对
/etc/passwd文件的任何写、属性更改或重命名操作(这是用户账户文件,被修改可能意味着添加/删除用户):sudo auditctl -w /etc/passwd -p wa -k identity_file_change-w /etc/passwd: 监控此文件路径。-p wa: 监控写(w)和属性更改(a)权限。-k identity_file_change: 给这条记录打上一个“键(key)”标签,方便后续搜索。
监控特定用户(如
username)执行的所有命令:sudo auditctl -a always,exit -F arch=b64 -S execve -F auid=1000 -k user_cmds-a always,exit: 在系统调用退出时添加规则。-F arch=b64: 针对64位系统。-S execve: 监控execve系统调用(这是执行程序的主要调用)。-F auid=1000: 审计用户ID(auid)为1000的用户(auid是用户登录时的原始ID,不会因su或sudo改变,是追踪用户行为的黄金标准)。你可以用id -u username获取用户的UID。-k user_cmds: 标签。
监控所有删除文件的系统调用:
sudo auditctl -a always,exit -S unlink -S unlinkat -S rmdir -k deletion
查看当前生效的规则:
sudo auditctl -l5.3 查询与分析审计日志
审计日志默认保存在/var/log/audit/audit.log,是二进制格式,需要使用ausearch或aureport工具来查询。
使用
ausearch搜索特定事件:# 搜索带有特定key标签的事件 sudo ausearch -k identity_file_change # 搜索今天发生的与文件删除相关的事件 sudo ausearch -k deletion --start today # 搜索特定用户(auid=1000)的所有事件 sudo ausearch -ua 1000 # 搜索涉及特定文件(/etc/passwd)的事件 sudo ausearch -f /etc/passwd使用
aureport生成汇总报告:# 生成所有事件的摘要报告 sudo aureport # 生成关于认证事件的报告 sudo aureport -au # 生成关于文件访问的报告 sudo aureport -f # 生成关于所有用户的命令执行汇总 sudo aureport -x --summary
解读一条审计记录示例:运行sudo ausearch -k user_cmds --start recent可能会输出类似下面的内容:
time->Mon Apr 15 11:30:15 2024 type=SYSCALL msg=audit(1713180615.123:456): arch=c000003e syscall=59 success=yes exit=0 a0=55a1b2c3d4e0 a1=55a1b2c3d5a0 a2=55a1b2c3d600 a3=8 items=2 ppid=1234 pid=5678 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="apt" exe="/usr/bin/apt" key="user_cmds"time: 事件发生时间。type=SYSCALL: 这是一个系统调用事件。auid=1000:审计用户ID,即最初登录的用户,这里是UID 1000的用户。这是追踪责任人的关键字段,即使他后来用了sudo(uid=0)。uid=0: 执行命令时的有效用户ID,0表示root。说明这个命令是通过提权(如sudo)运行的。comm="apt"和exe="/usr/bin/apt": 执行的命令是apt,路径是/usr/bin/apt。key="user_cmds": 我们之前设置的规则标签。
5.4 永久化审计规则
通过auditctl添加的规则在重启后会失效。要永久生效,需要将规则写入配置文件。
sudo nano /etc/audit/rules.d/audit.rules将你的规则添加进去,例如:
-w /etc/passwd -p wa -k identity_file_change -a always,exit -F arch=b64 -S execve -F auid=1000 -k user_cmds保存后,重启auditd服务或运行sudo augenrules --load来加载规则。
踩坑提醒:auditd的日志量非常巨大,尤其是监控宽泛的规则(如监控所有execve)。务必谨慎定义规则,只监控最关键的文件和操作,并确保/var/log分区有足够的磁盘空间。可以使用aureport --summary定期查看日志量,并配置auditd的轮转和清理策略(在/etc/audit/auditd.conf中配置)。
6. 综合案例与排查技巧实录
理论说再多,不如一个实际案例来得直观。假设我们收到警报,服务器/etc/shadow文件(存储密码哈希)的修改时间在非维护时段发生了变化,我们需要立刻调查。
6.1 调查步骤实录
第一步:快速确认文件状态和近期登录
# 1. 查看文件的详细属性,确认修改时间 ls -la /etc/shadow # 2. 查看最近的成功登录记录,寻找可疑IP或用户 last -n 20 # 3. 查看最近的失败登录记录,看是否有暴力破解迹象 sudo lastb | head -30 # 4. 查看当前在线用户,确认是否有异常会话 w第二步:深入分析认证日志 (auth.log)
# 1. 围绕文件变化时间点,查看所有sudo记录 sudo grep "sudo" /var/log/auth.log | grep -i "Apr 15" # 2. 查看所有用户切换记录 sudo grep -E "(su:|pam_unix\(su:session)" /var/log/auth.log # 3. 如果怀疑是特定用户,过滤该用户的所有活动 sudo grep "username" /var/log/auth.log | tail -50第三步:检查相关用户的命令历史
# 1. 查看疑似用户的历史命令(需root) sudo cat /home/suspect_user/.bash_history | tail -100 # 注意:如果历史记录被清空或时间点对不上,这步可能无效。第四步:启用并查询审计日志 (如果已配置auditd)
# 1. 如果我们之前配置了监控 /etc/shadow 的规则 sudo ausearch -f /etc/shadow --start yesterday # 2. 或者搜索所有文件修改事件 sudo ausearch -k file_change --start yesterday | less如果auditd记录了该事件,你会看到详细的记录,包括是哪个用户(auid)、通过什么进程(exe)、在什么时间修改了文件。
第五步:如果没有审计日志,使用stat和find寻找线索
# 查看文件的inode变化历史(如果文件系统支持) sudo debugfs -R 'stat /etc/shadow' /dev/sda1 2>/dev/null | grep -i change # 查找近期被修改的系统关键文件 sudo find /etc -type f -mtime -1 -ls | head -206.2 常见问题与排查技巧速查表
| 问题现象 | 可能原因 | 排查命令/思路 |
|---|---|---|
.bash_history为空或记录缺失 | 1. 用户手动清空 (history -c && history -w)。2. 多会话未退出,历史未写入。 3. HISTSIZE或HISTFILESIZE设置过小被覆盖。4. Shell配置了 HISTIGNORE或HISTCONTROL=ignorespace且命令以空格开头。 | 1. 检查auth.log中该用户的登录/注销时间,比对历史记录时间段。2. 检查用户 .bashrc配置。3.更可靠的方法是配置 auditd监控用户命令。 |
last命令显示从未知IP登录 | 1. 账号密码泄露。 2. SSH密钥泄露。 3. 服务器存在漏洞被入侵。 | 1. 立即用w或ps auxf检查该会话是否仍在活动,如有则记录其PID并终止。2. 用 `sudo netstat -tnpa |
auth.log中出现大量Failed password | 遭受SSH暴力破解攻击。 | 1. 使用 `sudo lastb |
| 怀疑文件被篡改但无直接日志 | 攻击者可能使用了非交互式脚本或清除了日志。 | 1. 检查系统进程列表 (ps auxf),寻找异常进程。2. 检查计划任务 ( crontab -l,ls -la /etc/cron.*/)。3. 检查网络连接 ( ss -tnlp或netstat -tnlp)。4.强调预防:事前配置 auditd监控关键文件和目录。 |
audit.log文件增长过快 | 审计规则过于宽泛,记录了太多事件。 | 1. 使用sudo aureport --summary查看事件类型分布。2. 审查当前规则 ( sudo auditctl -l),优化规则,减少不必要的监控。3. 调整 /etc/audit/auditd.conf中的max_log_file和num_logs参数,并确保日志轮转正常工作。 |
6.3 个人实操心得:构建防御性调查习惯
经过多次安全事件排查,我养成了几个习惯:
- 第一时间保存现场: 怀疑被入侵后,在开始任何可能改变系统的调查前,如果条件允许,先对内存 (
sudo dumpram) 和关键日志文件(尤其是auth.log*,wtmp,btmp, 如果配置了还有audit.log*)进行备份,复制到安全位置。避免攻击者正在运行的进程覆盖证据。 - 时间线是关键: 将
last、auth.log中的登录事件、audit.log中的操作事件,以及文件系统时间戳 (stat) 放在一个时间线里对照,往往能发现关联性。 - 不要相信单一来源: 永远交叉验证。
.bash_history说没干,但auth.log里的sudo记录显示他提权了;last显示他从A地登录,但netstat显示当前连接来自B地。这些矛盾点就是突破口。 - 默认安装并配置基础
auditd规则: 在新服务器上线时,我会部署几条基础的auditd规则,比如监控/etc/passwd,/etc/shadow,/etc/sudoers的写操作,以及所有用户的特权命令 (sudo)。这相当于给系统装了一个“黑匣子”,平时不占多少资源,出事时能救命。 - 标准化与自动化: 对于重要的生产系统,我会编写脚本,定期(例如每天)将关键的日志摘要(如失败的登录尝试、sudo使用记录)发送到安全的中央日志服务器或监控平台。这样即使本地日志被清空,也有备份可查。
调查用户操作历史就像数字侦探工作,日志就是你的线索。从浅层的登录记录到深层的系统调用审计,工具层层递进。对于日常运维,熟练使用last,who,history和阅读auth.log基本足够。但对于有安全合规要求或需要深度取证的环境,花时间学习和配置auditd是绝对值得的投资。它提供的不可篡改(在root未被完全攻陷的前提下)的操作记录,是厘清责任、还原真相的最有力工具。记住,最好的调查源于最充分的准备,在风平浪静时就部署好监控,才能在风暴来临时从容应对。