Linux 服务器入侵早期信号:从 SSH 认证日志里读出「不对劲」的五个判读方法

Linux 服务器被入侵的早期信号:从 SSH 登录日志里读出"不对劲"

绝大多数个人站长的服务器被入侵后,第一个发现异常的渠道不是入侵检测系统,而是"网站突然变慢"或者"流量异常"。等你在 ps aux 里看到陌生的挖矿进程时,攻击者往往已经在机器里待了几天甚至几周。这篇文章讲的是入侵的早期阶段:在对方拿到 root 之前,在 SSH 层就已经留下的、可被日志捕捉的信号。

前提说清楚:本文只讨论日志读取与判读,不做任何攻击复现。所有命令都是运维自查用的。

认识两个你必须会读的日志文件

SSH 相关事件写在两个文件里,作用完全不同,很多人只知其一会漏掉一半线索。

/var/log/auth.log(Debian/Ubuntu)或 /var/log/secure(RHEL/CentOS)记录认证事件:成功登录、失败登录、sudo 提权、PAM 相关模块的决策。这是主战场。

/var/log/lastlog 是二进制文件,用 lastlog 命令读,记录每个账户最后一次登录的时间与来源 IP。它的价值在于发现不该活跃的账户被激活了

还有 last 命令读 /var/log/wtmp,看的是登录历史(含重启记录)。三者配合,能画出"谁、从哪、什么时候进来过"的完整图景。

信号一:失败登录的"节奏"比数量更重要

新手第一反应是看失败次数:grep -c 'Failed password' /var/log/auth.log,看到几百上千就紧张,看到个位数就放心。这个判断方法基本无效,因为公网服务器的 22 端口每天被扫几百次失败登录是常态,不代表被针对性攻击。

真正值得警惕的是失败登录的时间分布模式。看这个命令:

grep 'Failed password' /var/log/auth.log \
  | awk '{print $1, $2, substr($3,1,2)}' \
  | sort | uniq -c | sort -rn | head -20

它按"日期+小时"统计失败次数。判读规则:

如果失败集中在你完全没关注过的时间段(比如凌晨 3 点整片爆发),且来源 IP 高度集中(不是几百个不同的 IP 各试一两次,而是同一两个 IP 反复试几百次),这就是定向暴力破解,而不是无差别扫描。无差别扫描的特征恰恰相反:来源 IP 极其分散,每个 IP 只试几个用户名。

判断来源 IP 的分散度:

grep 'Failed password' /var/log/auth.log \
  | grep -oE 'from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' \
  | sort | uniq -c | sort -rn | head -20

如果榜首那几个 IP 的计数占到总量的很大比重,说明有人在持续针对你。

信号二:被尝试的用户名列表会暴露攻击者的意图

看攻击者用哪些用户名尝试登录,是判断威胁等级的关键。先提取:

grep 'Failed password' /var/log/auth.log \
  | grep -oE 'for (invalid user )?[a-zA-Z0-9_.-]+' \
  | sort | uniq -c | sort -rn | head -30

输出里要特别注意两点。第一,是否包含你机器上真实存在的用户名。如果攻击者试的都是 admintestubuntu 这类通用名,那是无差别字典攻击;但如果他试的是 yourcompanydeploy、或者你真实用户名,说明对方做了针对性侦察,威胁等级立刻上升。

第二,invalid user 这个前缀的含义:带这个前缀说明该用户在本机不存在。如果攻击者反复用同一个不存在的用户名尝试,说明他手里有一份字典,正在逐个试。

这里有个实用的加固定义:把你机器上真实存在的登录名整理成白名单,任何不在白名单里的用户名出现在失败日志中,直接告警:

# 生成当前可登录账户列表
awk -F: '$3>=1000 && $7 !~ /nologin|false/ {print $1}' /etc/passwd > /tmp/realusers.txt
# 找出日志里出现的不存在的用户名
grep -oE 'invalid user [a-zA-Z0-9_.-]+' /var/log/auth.log \
  | awk '{print $3}' | sort -u > /tmp/attempted.txt
comm -13 <(sort /tmp/realusers.txt) /tmp/attempted.txt | head

信号三:成功登录的来源 IP —— 这是最重要的一条

失败登录再多都可以忽略(只要你有强密码和密钥认证),但成功登录必须逐个核对。这条命令列出所有成功登录的来源:

grep 'Accepted' /var/log/auth.log \
  | awk '{print $1, $2, $3, $9, $11}' | sort | uniq -c | sort -rn

判读要点:你能否解释每一个来源 IP。如果你只有自己一台电脑会 SSH 进来,那日志里应该只有一个 IP。出现第二个陌生的、你从未用过的 IP,无论它登录成功还是失败,都必须立刻处理。

配合 last 命令看更长时间范围:

last -a | head -30
lastlog | grep -v 'Never logged in'

lastlog 特别适合发现"沉睡账户被激活":一个半年没登录过的账户突然有了昨天的登录记录,这几乎可以确定是入侵痕迹。

信号四:sudo 与 su 的提权记录

攻击者在拿到普通用户后,下一步是提权。提权尝试会在 auth.log 里留下痕迹:

grep -E 'sudo:|su:|incorrect password' /var/log/auth.log | tail -50

关注两点:一是来自非交互式会话的 sudo(比如从某个 web 用户的会话里发起),二是短时间内多次 incorrect password 后紧跟一次成功。正常运维很少出现这种模式。

还有一个容易被忽略的:COMMAND= 后面记的是实际执行的命令。sudo 默认会记录完整命令,这就是你发现异常操作的直接证据:

grep 'COMMAND=' /var/log/auth.log | grep -vE 'systemctl|apt|nginx' | tail -40

把常见的日常命令排除掉,剩下的就是需要人工判断的。

信号五:日志本身被"处理"过 —— 最高危的信号

如果攻击者已经拿到一定权限,他会尝试清理痕迹。以下任一现象出现,说明情况已经很严重,不要犹豫,直接进入应急响应流程:

其一,auth.log 出现时间断层。日志是连续追加的,如果某段时间的记录凭空消失(不是被轮转,轮转会在同目录留下 .1.2.gz),说明文件被编辑过。检查方法:

ls -la /var/log/auth.log*
stat /var/log/auth.log
journalctl --since "1 hour ago" | head -50

systemd 系统的 journalctl 是独立存储的,攻击者清空 /var/log/auth.log 通常不会同步清掉 journal,两者对照就能发现断层。

其二,日志文件的 inode 或权限被改。ls -la 看属主是否是 syslog:adm,权限是否为 640。被改成 666 或者属主变成别的用户,都是异常。

其三,出现意料之外的日志重定向。检查 /etc/rsyslog.conf/etc/rsyslog.d/ 下有没有指向陌生 IP 的 @@@ 规则 —— 那是攻击者把日志外发到自己的收集器。

把上述判读固化成一个每日巡检脚本

手动读日志只适合事后追查,日常防护要靠自动化。下面这个脚本每天跑一次,把关键指标推给你:

#!/bin/bash
# ssh-daily-audit.sh
LOGFILE=/var/log/auth.log
TODAY=$(date '+%b %e')
echo "=== 今日成功登录 ==="
grep "Accepted" "$LOGFILE" | grep "$TODAY"
echo "=== 今日失败次数 TOP IP ==="
grep "Failed password" "$LOGFILE" | grep "$TODAY" \
  | grep -oE 'from [0-9.]+' | sort | uniq -c | sort -rn | head -5
echo "=== 今日是否存在新增可登录账户 ==="
awk -F: '$3>=1000' /etc/passwd | wc -l
echo "=== sudo 异常命令 ==="
grep "COMMAND=" "$LOGFILE" | grep "$TODAY" | grep -vE 'nginx|systemctl|apt' | tail -10

把它放进 crontab 每天 8 点执行,输出邮件或推送到你的告警渠道。有基线之后,"今天和昨天有什么不一样"这个问题就变得极其容易回答,而异常检测的本质就是这个。

配套的加固顺序:先减少攻击面,再谈检测

日志判读是"发现",加固才是"预防"。按性价比排序,个人站长最该先做的三件事:

第一,关闭密码登录,只用密钥。/etc/ssh/sshd_config 里设 PasswordAuthentication no,改完务必先验证密钥能登录,再断开当前会话,否则你会把自己锁在外面。这一项直接消灭了 99% 的暴力破解威胁 —— 他们试再多密码也没用。

第二,用 AllowUsers 白名单限制可登录账户。AllowUsers yourname 一行,把所有其他账户的 SSH 访问全部关掉,包括那些你早已忘记存在的系统账户。

第三,装 fail2ban 或改用非标准端口。两者都是降低噪音的手段,不是安全屏障 —— 但它们能显著减少 auth.log 里的垃圾条目,让你的判读更聚焦在真正的异常上。

加固完不要忘记验证:另开一个终端测试密钥登录是否正常,用 sshd -t 检查配置语法,再 systemctl reload sshd(reload 不会断开现有连接,比 restart 安全得多)。

一个判读决策树,遇到异常时照着走

当你发现 auth.log 里有可疑记录时,按这个顺序判断:

第一步,这个 IP 登录成功了吗?如果成功且你解释不了,直接按入侵处理:立刻改密码、撤销该用户的 SSH 密钥、检查 ~/.ssh/authorized_keys 是否被追加了陌生公钥、查看 crontab 是否有新增任务。

第二步,如果只是失败,看来源 IP 是否集中。集中则针对性封 IP;分散则说明是被无差别扫到,加固认证方式即可,不必逐个封禁(那会变成打地鼠)。

第三步,无论哪种情况,都检查一下今天是否有新增的账户或新增的授权密钥,这是攻击者最常用的持久化手段:

ls -la /home/*/.ssh/authorized_keys
cat /root/.ssh/authorized_keys
grep -rn "authorized_keys" /etc/ssh/sshd_config

记住一条原则:失败登录是噪音,成功登录才是信号。把注意力集中在"谁真的进来了",而不是"谁尝试进来",你的判读效率会提升一个数量级。

Last modification:September 24th, 2026 at 09:25 pm

Leave a Comment