history 命令仅记录当前 shell 会话的内存缓冲区命令,不存时间戳、不跨终端、不覆盖非交互式执行;需设 histtimeformat 并用 history -w 或 -a 同步到文件,审计应依赖 auditd 的 execve 系统调用日志。

history 命令只能看到当前 shell 会话里没被清空的命令,且不记录时间戳、不跨终端、不覆盖非交互式执行(如 ssh user@host 'ls'),它不是审计手段,只是操作便利功能。
用 history 查当前会话命令时要注意什么
它读的是内存中当前 shell 的历史缓冲区,不是磁盘文件;退出前未写入 ~/.bash_history 的命令就丢了。
-
history默认不显示时间,需提前设置HISTTIMEFORMAT(如export HISTTIMEFORMAT="%F %T ")并source ~/.bashrc -
history -c会清空内存记录,history -w才强制写入文件 - 多个终端同时运行时,彼此看不到对方刚执行的命令——
history -a可每次追加到文件,但需配合HISTCONTROL=ignoredups:ignorespace避免重复 - 普通用户无法直接查看他人
~/.bash_history,root 可读,但该文件易被手动删改或绕过
查某用户所有终端里执行过的命令,必须用 ausearch
auditd 记录的是 execve 系统调用,只要命令真正执行了(无论 bash、sh、python -c 还是 cron 脚本),都会留下痕迹,含完整路径、UID、PID、tty 和时间戳。
- 确认 auditd 正在运行:
sudo systemctl status auditd - 查指定用户(如
john)最近执行的所有命令:sudo ausearch -u john -m execve --raw | aureport -f -i - 查某次登录会话(比如 tty2)的操作:
sudo ausearch -ts recent -m event --session $(loginctl show-user john -p SessionId | cut -d= -f2)(注意 session ID 需从 loginuid 或last输出中提取) - 原始日志在
/var/log/audit/audit.log,但别直接cat——字段密集难读,ausearch是唯一实用入口
auditctl 规则为什么加了却查不到日志
规则加载失败或不匹配 arch 是最常见原因。x86_64 系统必须显式加 -F arch=b64,否则规则无效;只写 -S execve 不加 arch,规则根本不会触发。
- 正确写法(x86_64):
sudo auditctl -a always,exit -F arch=b64 -S execve - 兼容 32 位程序(如某些容器内命令)要额外加一行:
sudo auditctl -a always,exit -F arch=b32 -S execve -
-F uid!=0这类过滤建议去掉,auditd 对 uid 类型判断严格,容易导致规则加载失败而漏记全部事件 - 规则只存在内存中,重启即失效;必须写入
/etc/audit/rules.d/execve.rules并运行sudo augenrules --load
为什么不能靠修改 /etc/profile 或 ~/.bashrc 做审计
这类方案依赖 shell 启动和变量生效,而真实攻击场景中,90% 的绕过方式都直击这个弱点。
-
ssh user@host 'rm -rf /tmp'这种非交互式 shell 完全不加载/etc/profile -
su -切换后,新 shell 的 history 写入的是目标用户的.bash_history,与原用户无关 - 执行
unset HISTFILE; /bin/ls就能跳过所有基于 history 的记录逻辑 -
exec bash或python3 -c "import os; os.execv('/bin/ls', ['ls'])"绕过 shell wrapper,auditd 却照常捕获
auditd 的 execve 日志不记录参数明文(出于安全考虑),但记录完整路径(如 /usr/bin/curl)、UID、tty、时间戳和进程树关系——这些已足够定位谁、在哪个终端、什么时间、以什么权限执行了哪条命令。真正的盲区不在工具,而在没把规则持久化、没验证 arch 匹配、没用 ausearch 而不是 grep audit.log。











