Linux应急响应 - 10 SSH暴力破解与未授权访问

SSH 暴力破解与未授权访问分析

SSH(Secure Shell)是 Linux 服务器最常用的远程管理协议,同时也是攻击者最常瞄准的入口点之一。暴力破解 SSH 密码是互联网上最常见的自动化攻击行为,几乎每一台暴露在公网的 Linux 服务器都会遭受此类攻击。本章系统性地讲解 SSH 暴力破解与未授权访问的检测、分析、处置与加固全流程。

关联章节:

03-日志分析基础 — 日志分析的通用方法论

04-账户安全排查 — 用户与权限深度排查

16-SSH-authorized_keys后门 — SSH 密钥持久化后门专题

一、SSH 攻击类型概述

1.1 暴力破解(Brute Force)

暴力破解是最常见的 SSH 攻击方式,攻击者通过大量尝试用户名/密码组合来获取访问权限

字典攻击(Dictionary Attack)

使用预编译的用户名和密码字典进行尝试

常见字典来源:RockYou、SecLists、弱密码 Top 10000

特点:速度快,成功率依赖字典质量

典型工具:Hydra, Medusa, Patator

穷举攻击(Exhaustive Search)

遍历所有可能的字符组合

特点:耗时极长,实际攻击中较少使用纯穷举

通常会限定字符集和长度范围

撞库攻击(Credential Stuffing)

使用其他平台泄露的账号密码组合尝试 SSH 登录

利用用户在多个系统中重用密码的习惯

成功率通常高于随机字典攻击

分布式暴力破解

使用多个 IP(僵尸网络)同时发起攻击

目的:绕过基于单 IP 的封禁策略(如 fail2ban)

每个 IP 尝试次数少,但总尝试量大

1.2 密钥泄露导致的未授权访问

SSH 私钥泄露场景:

私钥文件被上传到 GitHub/GitLab 等代码仓库

开发者笔记本被入侵,私钥被窃取

容器镜像中打包了 SSH 私钥

备份文件中包含私钥且备份未加密

密钥泄露的危险性:

无需密码即可登录,不会触发密码暴力破解告警

如果私钥没有 passphrase 保护,攻击者可直接使用

一个私钥可能对应多台服务器的访问权限

检测难点:

密钥登录看起来与正常管理员登录无异

需要结合登录源 IP、时间等上下文分析

1.3 SSH 配置不当

允许空密码登录

PermitEmptyPasswords yes — 极度危险的配置

检查命令:

1
grep -i "PermitEmptyPasswords" /etc/ssh/sshd_config

允许 root 远程登录

PermitRootLogin yes — 攻击者首选目标用户名就是 root

配合弱密码 = 灾难

弱密码策略

系统未强制密码复杂度要求

未配置密码过期策略

默认端口 22

虽然改端口不是真正的安全措施(security through obscurity)

但可以大幅减少自动化扫描和攻击流量

未限制登录用户

未使用 AllowUsers/AllowGroups 限制可远程登录的用户

1.4 中间人攻击(MITM)

SSH 中间人攻击原理:

攻击者在客户端和服务器之间插入自己的节点

冒充服务器与客户端通信,同时冒充客户端与服务器通信

可以截获认证凭据和会话数据

触发条件:

首次连接时用户未验证服务器指纹(直接输入 yes)

服务器重装后指纹变更,用户习惯性忽略警告

ARP 欺骗 / DNS 劫持 将流量重定向

检测方法:

检查 ~/.ssh/known_hosts 中的主机指纹变更记录

网络层检测 ARP 异常

二、SSH 日志分析(重点)

2.1 日志文件位置

SSH 认证相关日志由 syslog/rsyslog 记录,不同发行版位置不同:

发行版 日志文件路径 日志服务
Ubuntu/Debian /var/log/auth.log rsyslog
CentOS/RHEL 7+ /var/log/secure rsyslog
CentOS/RHEL 8+ (使用 journald) journalctl -u sshd systemd-journald
SUSE /var/log/messages rsyslog

通用查看方法(适用于使用 systemd 的系统):

1
2
3
4
5
6
7
8
# 查看 sshd 相关的所有日志
journalctl -u sshd --no-pager

# 查看最近 1 小时的 SSH 日志
journalctl -u sshd --since "1 hour ago"

# 查看指定日期范围
journalctl -u sshd --since "2026-03-01" --until "2026-03-02"

2.2 SSH 日志格式详解

认证失败日志格式(密码错误)

1
Mar 15 14:23:01 web-server sshd[12345]: Failed password for root from 192.168.1.100 port 54321 ssh2

Mar 15 14:23:01 — 时间戳

web-server — 主机名

sshd[12345] — 服务名和进程 PID

Failed password — 事件类型:密码认证失败

for root — 目标用户名

from 192.168.1.100 — 来源 IP

port 54321 — 来源端口

ssh2 — SSH 协议版本

无效用户名的失败日志

1
Mar 15 14:23:05 web-server sshd[12346]: Failed password for invalid user admin from 192.168.1.100 port 54322 ssh2

注意关键区别:多了 invalid user 标记

说明系统中不存在该用户名,攻击者在猜测用户名

认证成功日志(密码登录)

1
Mar 15 15:00:00 web-server sshd[12400]: Accepted password for deploy from 10.0.0.50 port 60001 ssh2

Accepted password — 密码认证成功

认证成功日志(密钥登录)

1
Mar 15 15:00:00 web-server sshd[12401]: Accepted publickey for deploy from 10.0.0.50 port 60002 ssh2: RSA SHA256:xxxxxxxxxxx

Accepted publickey — 密钥认证成功

末尾会显示密钥指纹信息

会话打开/关闭

1
2
Mar 15 15:00:01 web-server sshd[12400]: pam_unix(sshd:session): session opened for user deploy by (uid=0)
Mar 15 15:30:00 web-server sshd[12400]: pam_unix(sshd:session): session closed for user deploy

连接断开(无认证)

1
Mar 15 14:22:50 web-server sshd[12340]: Connection closed by 192.168.1.100 port 54310 [preauth]

[preauth] 表示在认证阶段之前就断开了

通常是端口扫描或版本探测行为

2.3 暴力破解日志分析

统计失败登录 IP Top N

1
2
3
4
5
6
7
8
9
10
11
12
# Ubuntu/Debian
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20

# CentOS/RHEL
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20

# 输出示例:
# 15234 185.220.101.34
# 8921 45.33.32.156
# 5432 103.99.0.37
# 2100 192.168.1.105
# 341 10.0.0.50

统计被爆破的用户名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 统计所有被尝试的用户名(包括有效和无效用户)
grep "Failed password" /var/log/auth.log | awk '{
if ($0 ~ /invalid user/) {
print "(invalid) " $(NF-5)
} else {
print "(valid) " $(NF-5)
}
}' | sort | uniq -c | sort -rn | head -20

# 输出示例:
# 28341 (valid) root
# 5234 (invalid) admin
# 3421 (invalid) test
# 2100 (invalid) oracle
# 1890 (valid) deploy
# 543 (invalid) ubuntu
# 321 (invalid) postgres
# 210 (invalid) mysql

分析要点:

(valid) 标记的用户名是系统中实际存在的用户 — 如果被大量爆破,说明攻击者可能已经获得了用户名信息

(invalid) 标记的是字典中的常见用户名 — 这是典型的自动化扫描行为

如果某个实际存在但不常见的用户名被针对性爆破,需要调查用户名泄露源

分析攻击时间窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 按小时统计失败登录次数
grep "Failed password" /var/log/auth.log | awk '{print $1, $2, substr($3,1,2)":00"}' | sort | uniq -c | sort -rn | head -24

# 更精确的方式 — 按小时聚合
grep "Failed password" /var/log/auth.log | awk '{
split($3, t, ":");
printf "%s %s %s:00\n", $1, $2, t[1]
}' | sort | uniq -c | sort -rn

# 按分钟统计(定位高频攻击时段)
grep "Failed password" /var/log/auth.log | awk '{
split($3, t, ":");
printf "%s %s %s:%s\n", $1, $2, t[1], t[2]
}' | sort | uniq -c | sort -rn | head -30

分析要点:

如果攻击集中在某个时间段 → 可能是定向攻击

如果 24 小时均匀分布 → 典型的自动化僵尸网络扫描

突然出现的高频攻击 → 可能是新的僵尸网络或有针对性的攻击

按 IP 统计攻击时间范围

1
2
3
4
5
6
7
# 查看某个攻击 IP 的首次和最后一次尝试时间
TARGET_IP="185.220.101.34"
grep "Failed password.*${TARGET_IP}" /var/log/auth.log | head -1
grep "Failed password.*${TARGET_IP}" /var/log/auth.log | tail -1

# 统计该 IP 的攻击速率(每分钟尝试次数)
grep "Failed password.*${TARGET_IP}" /var/log/auth.log | awk '{print $1,$2,$3}' | uniq -c

区分字典用户名 vs 真实用户名

1
2
3
4
5
6
7
8
9
10
11
# 提取所有被爆破的"无效用户"名 — 这些是攻击字典中的用户名
grep "Failed password for invalid user" /var/log/auth.log | awk '{print $(NF-5)}' | sort -u > /tmp/dict_users.txt

# 提取所有被爆破的"有效用户"名 — 系统中确实存在的用户
grep "Failed password" /var/log/auth.log | grep -v "invalid user" | awk '{print $(NF-5)}' | sort -u > /tmp/valid_users.txt

# 对比系统实际用户
awk -F: '$3 >= 1000 && $7 != "/sbin/nologin" && $7 != "/bin/false" {print $1}' /etc/passwd > /tmp/system_users.txt

# 交叉对比
comm -12 /tmp/valid_users.txt /tmp/system_users.txt

2.4 成功登录分析

提取所有成功登录记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 密码认证成功
grep "Accepted password" /var/log/auth.log

# 密钥认证成功
grep "Accepted publickey" /var/log/auth.log

# 所有成功登录汇总(按 IP 和用户统计)
grep "Accepted" /var/log/auth.log | awk '{
for(i=1;i<=NF;i++) {
if($i=="for") user=$(i+1);
if($i=="from") ip=$(i+1);
}
print user, ip
}' | sort | uniq -c | sort -rn

密码登录 vs 密钥登录的日志区别

密码登录:Accepted password for user from IP port PORT ssh2

密钥登录:Accepted publickey for user from IP port PORT ssh2: KEY_TYPE KEY_FINGERPRINT

关键区别在于 password vs publickey,以及密钥登录会附加密钥指纹

如果某个通常使用密钥登录的账户突然出现密码登录 → 高度可疑

异常登录检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查非工作时间的登录(假设工作时间为 08:00-20:00)
grep "Accepted" /var/log/auth.log | awk '{
split($3, t, ":");
hour = t[1] + 0;
if (hour < 8 || hour > 20) print $0
}'

# 检查非常见 IP 的登录
# 首先建立已知 IP 白名单
KNOWN_IPS="10.0.0.50|10.0.0.51|192.168.1.100"
grep "Accepted" /var/log/auth.log | grep -vE "${KNOWN_IPS}"

# 检查 root 用户的直接登录(应该禁止)
grep "Accepted.*for root" /var/log/auth.log

关联暴力破解 IP 和成功登录 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 这是最关键的分析!如果暴力破解 IP 后来成功登录了,说明暴力破解成功

# 提取暴力破解 IP 列表
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort -u > /tmp/bruteforce_ips.txt

# 提取成功登录 IP 列表
grep "Accepted" /var/log/auth.log | awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}' | sort -u > /tmp/success_ips.txt

# 交叉对比 — 找出既有暴力破解又成功登录的 IP
comm -12 /tmp/bruteforce_ips.txt /tmp/success_ips.txt

# 如果有匹配的 IP,详细查看其登录过程
# SUSPECT_IP=<从上面结果获取>
# grep "$SUSPECT_IP" /var/log/auth.log | grep -E "Failed|Accepted"

重要提醒:如果发现暴力破解 IP 成功登录,立即启动应急响应流程!

2.5 完整攻击案例日志分析

以下是一个真实的暴力破解成功案例的日志样本(已脱敏):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Mar 15 02:13:01 web-prod sshd[8801]: Invalid user admin from 185.220.101.34 port 45231
Mar 15 02:13:01 web-prod sshd[8801]: pam_unix(sshd:auth): check pass; user unknown
Mar 15 02:13:03 web-prod sshd[8801]: Failed password for invalid user admin from 185.220.101.34 port 45231 ssh2
Mar 15 02:13:04 web-prod sshd[8801]: Connection closed by invalid user admin 185.220.101.34 port 45231 [preauth]
Mar 15 02:13:05 web-prod sshd[8805]: Invalid user test from 185.220.101.34 port 45232
Mar 15 02:13:07 web-prod sshd[8805]: Failed password for invalid user test from 185.220.101.34 port 45232 ssh2
Mar 15 02:13:08 web-prod sshd[8805]: Connection closed by invalid user test 185.220.101.34 port 45232 [preauth]
Mar 15 02:13:09 web-prod sshd[8809]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=185.220.101.34 user=root
Mar 15 02:13:11 web-prod sshd[8809]: Failed password for root from 185.220.101.34 port 45233 ssh2
Mar 15 02:13:12 web-prod sshd[8812]: Failed password for root from 185.220.101.34 port 45234 ssh2
Mar 15 02:13:14 web-prod sshd[8815]: Failed password for root from 185.220.101.34 port 45235 ssh2
Mar 15 02:13:15 web-prod sshd[8818]: Failed password for root from 185.220.101.34 port 45236 ssh2
Mar 15 02:13:17 web-prod sshd[8821]: Failed password for root from 185.220.101.34 port 45237 ssh2
Mar 15 02:13:18 web-prod sshd[8824]: Failed password for root from 185.220.101.34 port 45238 ssh2
Mar 15 02:13:20 web-prod sshd[8827]: Failed password for root from 185.220.101.34 port 45239 ssh2
Mar 15 02:13:22 web-prod sshd[8830]: Failed password for root from 185.220.101.34 port 45240 ssh2
--- 中间省略约 200 次失败尝试,持续约 30 分钟 ---
Mar 15 02:45:33 web-prod sshd[9201]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=185.220.101.34 user=deploy
Mar 15 02:45:35 web-prod sshd[9201]: Failed password for deploy from 185.220.101.34 port 46102 ssh2
Mar 15 02:45:36 web-prod sshd[9204]: Failed password for deploy from 185.220.101.34 port 46103 ssh2
Mar 15 02:45:38 web-prod sshd[9207]: Failed password for deploy from 185.220.101.34 port 46104 ssh2
Mar 15 02:45:40 web-prod sshd[9210]: Accepted password for deploy from 185.220.101.34 port 46105 ssh2
Mar 15 02:45:40 web-prod sshd[9210]: pam_unix(sshd:session): session opened for user deploy by (uid=0)
Mar 15 02:45:41 web-prod sshd[9210]: pam_loginuid(sshd:session): set_loginuid failed for uid=1001
Mar 15 02:46:02 web-prod sudo: deploy : TTY=pts/0 ; PWD=/home/deploy ; USER=root ; COMMAND=/bin/bash
Mar 15 02:46:02 web-prod sudo: pam_unix(sudo:session): session opened for user root by deploy(uid=1001)
Mar 15 02:47:15 web-prod useradd[9301]: new user: name=support, UID=1002, GID=1002, home=/home/support, shell=/bin/bash
Mar 15 02:47:20 web-prod usermod[9305]: add 'support' to group 'sudo'
Mar 15 02:47:35 web-prod sshd[9310]: pam_unix(sshd:session): session opened for user deploy by (uid=0)
Mar 15 02:48:01 web-prod CRON[9315]: (root) CMD (/tmp/.hidden/update.sh)

逐步分析:

02:13:01-02:13:08 — 攻击者首先尝试 admintest 等常见用户名,均为系统不存在的用户(Invalid user标记)。这是典型的字典攻击初始阶段

02:13:09-02:13:22 — 攻击者转向尝试 root 用户,高频(每 2 秒一次)提交不同密码。注意端口号递增(45233→45240),说明每次都是新连接

02:13-02:45 — 约 30 分钟持续暴力破解,中间可能更换了不同的用户名字典

02:45:33-02:45:38 — 攻击者开始针对 deploy 用户,先失败了 3 次

02:45:40关键节点! Accepted password for deploy — 暴力破解成功!攻击者猜中了 deploy 用户的密码

02:46:02 — 攻击者通过 sudo /bin/bash 提权到 root,说明 deploy 用户有 sudo 权限

02:47:15-02:47:20 — 攻击者创建了后门用户 support 并加入 sudo 组 — 这是持久化操作

02:48:01 — 出现可疑的 cron 任务执行 /tmp/.hidden/update.sh — 可能是攻击者植入的定时任务(后门/挖矿/C2通信)

三、入侵后排查

3.1 攻击者典型操作序列

攻击者成功登录后通常遵循以下操作序列:

阶段一:情报搜集(5-10 分钟)

whoami / id — 确认当前用户权限

uname -a — 系统版本信息

cat /etc/passwd — 查看系统用户

ifconfig / ip addr — 网络配置

netstat -tlnp — 开放端口和服务

cat /etc/crontab — 定时任务

ls -la /home/ — 其他用户目录

cat /etc/shadow(需 root)— 密码哈希

阶段二:权限提升(10-30 分钟)

sudo -l — 检查 sudo 权限

查找 SUID 文件:find / -perm -4000 2>/dev/null

内核提权漏洞利用(DirtyPipe, DirtyCow 等)

利用可写的 cron 任务或服务配置

阶段三:持久化(5-15 分钟)

创建后门用户

写入 SSH 公钥到 authorized_keys

植入定时任务(crontab / systemd timer)

安装 rootkit

修改系统二进制文件(如替换 ps, netstat

阶段四:横向移动

扫描内网其他主机

利用获取的密钥/密码尝试登录其他服务器

利用内网服务漏洞

3.2 排查清单

检查新建用户和 sudoers 修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 检查最近创建的用户(比较 /etc/passwd 的修改时间)
stat /etc/passwd
stat /etc/shadow

# 查找 UID >= 1000 的普通用户
awk -F: '$3 >= 1000 {print $1, $3, $6, $7}' /etc/passwd

# 查找 UID = 0 的用户(除了 root 以外不应该有)
awk -F: '$3 == 0 {print $1}' /etc/passwd

# 检查 sudoers 文件修改时间
stat /etc/sudoers
ls -la /etc/sudoers.d/

# 检查 sudo 组成员
getent group sudo # Ubuntu
getent group wheel # CentOS

# 查看 /etc/passwd 最近的修改(如果有版本控制或备份)
# 也可以检查 useradd 相关的日志
grep -E "useradd|usermod|groupmod" /var/log/auth.log # Ubuntu
grep -E "useradd|usermod|groupmod" /var/log/secure # CentOS

检查 authorized_keys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 遍历所有用户的 authorized_keys 文件
for user_home in /home/* /root; do
if [ -f "${user_home}/.ssh/authorized_keys" ]; then
echo "=== ${user_home}/.ssh/authorized_keys ==="
ls -la "${user_home}/.ssh/authorized_keys"
cat "${user_home}/.ssh/authorized_keys"
echo ""
fi
done

# 检查 authorized_keys 的修改时间
find /home /root -name "authorized_keys" -exec ls -la {} \; 2>/dev/null

# 检查非标准位置的 authorized_keys(攻击者可能修改 sshd_config 的 AuthorizedKeysFile)
grep "AuthorizedKeysFile" /etc/ssh/sshd_config

检查 crontab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 检查所有用户的 crontab
for user in $(cut -d: -f1 /etc/passwd); do
crontab_content=$(crontab -l -u "$user" 2>/dev/null)
if [ -n "$crontab_content" ]; then
echo "=== Crontab for $user ==="
echo "$crontab_content"
echo ""
fi
done

# 检查系统级 crontab
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
ls -la /etc/cron.hourly/

# 检查最近修改的 cron 文件
find /etc/cron* /var/spool/cron -mtime -7 -ls 2>/dev/null

# 检查 systemd timer(新型持久化方式)
systemctl list-timers --all
find /etc/systemd/system/ -name "*.timer" -mtime -7

检查 bash_history

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 读取所有用户的命令历史
for user_home in /home/* /root; do
for hist_file in .bash_history .zsh_history; do
if [ -f "${user_home}/${hist_file}" ]; then
echo "=== ${user_home}/${hist_file} ==="
cat "${user_home}/${hist_file}" | tail -100
echo ""
fi
done
done

# 检查历史文件是否被清空或删除
find /home /root -name ".*history" -empty 2>/dev/null
find /home /root -name ".*history" -exec ls -la {} \; 2>/dev/null

# 搜索可疑命令关键字
grep -rn "wget\|curl\|nc \|ncat\|/dev/tcp\|base64\|python.*import\|chmod 777\|chmod +s" /home/*/.bash_history /root/.bash_history 2>/dev/null

检查网络连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 当前所有网络连接
ss -tunap

# 检查可疑的外连连接
ss -tunap | grep ESTABLISHED | grep -v "127.0.0.1\|::1"

# 检查监听端口
ss -tlnp

# 检查异常的 DNS 查询(如果有 DNS 日志)
# 某些后门通过 DNS 隧道通信

# 使用 lsof 查看进程的网络连接
lsof -i -P -n | grep ESTABLISHED

检查文件修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查找最近 7 天内修改的文件(排除日志和临时文件)
find / -mtime -7 -type f \
-not -path "/proc/*" \
-not -path "/sys/*" \
-not -path "/var/log/*" \
-not -path "/tmp/*" \
-not -path "/run/*" \
2>/dev/null | head -100

# 查找隐藏文件和目录
find / -name ".*" -type f -mtime -7 \
-not -path "/proc/*" \
-not -path "/sys/*" \
2>/dev/null

# 查找 /tmp 下的可疑文件
ls -laR /tmp/ /var/tmp/ /dev/shm/

# 检查系统二进制文件是否被篡改(使用包管理器校验)
# Ubuntu/Debian
dpkg --verify
# CentOS/RHEL
rpm -Va

四、应急处置流程

4.1 立即处置

第一步:封禁攻击 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用 iptables 立即封禁(临时,重启失效)
iptables -A INPUT -s 185.220.101.34 -j DROP

# 使用 firewalld(CentOS 7+)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="185.220.101.34" reject'
firewall-cmd --reload

# 使用 ufw(Ubuntu)
ufw deny from 185.220.101.34

# 批量封禁多个攻击 IP
while read ip; do
iptables -A INPUT -s "$ip" -j DROP
done < /tmp/attack_ips.txt

第二步:禁用被入侵账户

1
2
3
4
5
6
7
8
9
10
11
12
# 锁定账户(禁止登录)
passwd -l deploy

# 或者修改 shell 为 nologin
usermod -s /sbin/nologin deploy

# 强制断开该用户的所有活跃会话
pkill -u deploy

# 如果攻击者创建了后门用户,同样处理
passwd -l support
pkill -u support

第三步:Kill 恶意进程

1
2
3
4
5
6
7
8
# 查找攻击者可能运行的进程
ps aux | grep -E "deploy|support"

# 查找从 /tmp 或其他异常路径运行的进程
ls -la /proc/*/exe 2>/dev/null | grep -E "/tmp|/dev/shm|/var/tmp"

# kill 可疑进程
kill -9 <PID>

4.2 深入排查

按照前述排查清单(第三节)逐项执行

重点关注:

攻击者是否已经获得 root 权限

是否安装了 rootkit

是否存在其他持久化后门

是否已经横向移动到其他服务器

工具辅助:

1
2
3
4
5
6
7
8
9
10
11
12
# 使用 chkrootkit 检查 rootkit
apt install chkrootkit # Ubuntu
yum install chkrootkit # CentOS
chkrootkit

# 使用 rkhunter 检查 rootkit
apt install rkhunter
rkhunter --check

# 使用 lynis 全面安全审计
apt install lynis
lynis audit system

4.3 SSH 加固措施

修改 /etc/ssh/sshd_config 进行加固:

禁止 root 远程登录

1
2
# /etc/ssh/sshd_config
PermitRootLogin no

效果:即使 root 密码被猜中也无法直接登录

管理员应使用普通用户登录后 sudo 提权

强制使用密钥认证

1
2
3
4
# /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no

这是对抗暴力破解最有效的措施

部署前确保所有管理员都已配置密钥登录

修改默认端口

1
2
# /etc/ssh/sshd_config
Port 22222

可以过滤掉 99% 的自动化扫描流量

注意:需要同步更新防火墙规则

1
2
3
4
5
6
7
8
9
10
11
# Ubuntu UFW
ufw allow 22222/tcp
ufw delete allow 22/tcp

# CentOS firewalld
firewall-cmd --permanent --add-port=22222/tcp
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --reload

# SELinux(CentOS)
semanage port -a -t ssh_port_t -p tcp 22222

限制登录用户

1
2
3
4
5
6
7
8
9
# /etc/ssh/sshd_config
# 只允许特定用户登录
AllowUsers deploy ops_admin

# 或只允许特定组
AllowGroups ssh-users

# 禁止特定用户
DenyUsers testuser guest

限制认证尝试次数

1
2
3
4
5
# /etc/ssh/sshd_config
MaxAuthTries 3
LoginGraceTime 30
MaxSessions 3
MaxStartups 3:50:10

MaxAuthTries 3:每次连接最多尝试 3 次认证

LoginGraceTime 30:30 秒内必须完成认证

MaxStartups 3:50:10:并发未认证连接限制(3 个全速,之后 50% 概率拒绝,10 个时全部拒绝)

安装 fail2ban

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Ubuntu
apt install fail2ban

# CentOS
yum install epel-release
yum install fail2ban

# 配置 SSH 防护
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log # Ubuntu
# logpath = /var/log/secure # CentOS
maxretry = 5
bantime = 3600
findtime = 600
banaction = iptables-multiport
EOF

# 启动服务
systemctl enable fail2ban
systemctl start fail2ban

# 查看封禁状态
fail2ban-client status sshd

# 手动解封
fail2ban-client set sshd unbanip 192.168.1.100

完整的加固配置模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# === SSH 安全加固配置 ===
# /etc/ssh/sshd_config

Port 22222
Protocol 2

# 认证设置
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes

# 登录限制
MaxAuthTries 3
LoginGraceTime 30
MaxSessions 3
MaxStartups 3:50:10

# 用户限制
AllowGroups ssh-users

# 其他安全设置
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no

# 日志
LogLevel VERBOSE

# 超时设置
ClientAliveInterval 300
ClientAliveCountMax 2

应用配置:

1
2
3
4
5
6
7
8
# 检查配置语法
sshd -t

# 重启 SSH 服务
systemctl restart sshd

# 注意!重启前确保有其他方式访问服务器(如控制台),
# 避免因配置错误导致无法远程连接

五、实战练习

5.1 实验环境

实验目录:labs/01-ssh-bruteforce/

环境要求:

两台 Linux 虚拟机(攻击机 + 靶机)

靶机配置弱密码账户

安装 Hydra(攻击机)

5.2 练习一:暴力破解日志分析

目标:分析提供的日志样本,回答以下问题

有多少个不同的攻击 IP?

攻击时间窗口是什么?

被尝试最多的用户名是什么?

暴力破解是否成功?如果成功,哪个用户被破解?

攻击者成功后执行了哪些操作?

练习日志文件:labs/01-ssh-bruteforce/sample-auth.log

5.3 练习二:SSH 加固实操

目标:对靶机进行完整的 SSH 安全加固

创建管理用户并配置密钥登录

修改 sshd_config 加固

安装并配置 fail2ban

验证加固效果(从攻击机发起暴力破解测试)

5.4 练习三:应急响应模拟

场景:你接到告警,某服务器疑似被暴力破解成功

任务:

分析日志确认入侵事实

执行完整的排查流程

清理攻击者的持久化后门

编写应急响应报告

5.5 思考题

分布式暴力破解(来自多个 IP,每个 IP 只尝试少量次数)该如何检测?

如果攻击者在暴力破解成功后清除了 auth.log,还有哪些方式可以发现入侵痕迹?

SSH 密钥泄露导致的未授权访问与暴力破解在日志上有什么区别?如何检测?


上一章 目录 下一章
09-历史记录与时间线分析 Linux应急响应 11-Tomcat与Java-Web应急