LD_PRELOAD 与 ld.so.preload
Linux 动态链接器在加载程序时,会优先载入 LD_PRELOAD 环境变量列出的共享库;若存在全局配置文件 /etc/ld.so.preload,其中列出的库会对每个新启动的进程强制生效。这套机制本用于调试与兼容性修补,但也常被恶意程序用来劫持库函数,从而隐藏进程、文件与网络连接。因此它同时是排查项和清除难点:存在不等于恶意,但出现来源不明、路径在临时目录、时间与入侵窗口吻合的库文件时,需要作为重点线索深入核对。
基本信息
| 适用平台 | 使用 glibc 的 Linux 发行版(RHEL/CentOS、Ubuntu/Debian 等) |
|---|---|
| 环境变量 | LD_PRELOAD(可在 shell 会话或服务单元中设置) |
| 全局文件 | /etc/ld.so.preload(内容为库的绝对路径,一行一个) |
| 检查命令 | echo "$LD_PRELOAD"、cat /etc/ld.so.preload、/proc/<pid>/maps |
| 生效范围 | 对配置文件改动后新启动的进程生效,已在运行的进程不受影响 |
典型使用场景
- 排查“命令列出的进程比实际少”“文件明明存在却看不到”这类被劫持的迹象
- 确认系统上是否存在来源不明的全局预加载库
- 处理告警时核查是否存在围绕提权或隐藏的库注入行为
- 在清理前固定证据:保存配置文件内容、库文件哈希与时间戳
- 审计服务单元配置:确认是否有服务通过环境变量方式注入库
检查与取证
检查与取证
# 1) 当前环境变量(可为空)
echo "$LD_PRELOAD"
# 2) 全局预加载配置文件:存在即可疑,先看内容再判断
ls -l --time-style=full-iso /etc/ld.so.preload 2>/dev/null && cat /etc/ld.so.preload
# 3) 固定证据:文件内容与库文件哈希、时间戳
md5sum /etc/ld.so.preload 2>/dev/null
cat /etc/ld.so.preload 2>/dev/null | while read -r lib; do ls -l "$lib"; sha256sum "$lib"; done
# 4) 确认某进程实际加载的库,验证是否命中预加载
sudo grep -i preload /proc/1234/maps; sudo tr '\0' '\n' < /proc/1234/environ | grep -i ld_preload
# 5) 服务侧检查:单元文件里是否被人加了环境变量
grep -Rn 'LD_PRELOAD' /etc/systemd/system /lib/systemd/system 2>/dev/null检查点对照
| 检查点 | 含义 | 判读要点 |
|---|---|---|
| /etc/ld.so.preload | 全局预加载列表 | 文件存在且指向不明路径时优先级最高 |
| $LD_PRELOAD | 当前会话/服务的环境变量 | 为空不代表全局文件不存在,两者都要查 |
| /proc/<pid>/maps | 进程实际映射的库 | 可验证预加载是否真在该进程中生效 |
| 库文件属性 | 路径、属主、mtime、哈希 | 路径在 /tmp、/dev/shm 或属主异常时高度可疑 |
| systemd 单元 | 服务级环境变量 | 攻击者倾向在服务里持久注入而少改全局文件 |
发现 /etc/ld.so.preload 指向不明库时不要直接删除文件或库:先保存内容、路径、哈希与时间戳(清理后无法复核),再评估卸载方式,避免破坏系统命令的正常运行。
设置用户 ID 位的程序会出于安全考虑忽略 LD_PRELOAD,因此预加载并不能影响所有程序;对这类程序做验证时不能用“它没被劫持”来反推系统干净。