应检查 /etc/ld.so.preload 是否被篡改,因其会在每次动态链接库加载前强制预加载恶意共享对象;同时排查 LD_PRELOAD 和 LD_AUDIT 环境变量滥用,二者分别在进程启动时和动态链接器初始化阶段劫持行为,且传统工具如 lsof、strings 无法可靠检测。

检查 /etc/ld.so.preload 是否被篡改
该文件若存在且非空,系统在**每次动态链接库加载前**都会强制预加载其中列出的共享对象——这是最隐蔽的全局劫持入口之一。攻击者常写入恶意 .so 路径(如 /tmp/.x.so)实现持久化。
实操建议:
- 用
ls -l /etc/ld.so.preload确认文件是否存在、权限是否异常(如非 root 可写) - 用
cat /etc/ld.so.preload 2>/dev/null查看内容;若输出为空或报No such file,说明未被利用 - 若内容非空,立即检查路径是否合法:用
file和readelf -d验证目标.so是否为正常 ELF 共享库,而非 shellcode 或加壳二进制 - 注意:该文件本身无执行权限要求,但路径必须绝对、可读,且不能含空格或通配符
排查进程是否被 LD_PRELOAD 劫持
LD_PRELOAD 是用户态环境变量,仅影响当前 shell 启动的进程,但攻击者常通过 /etc/profile、~/.bashrc 或 systemd 用户服务注入,导致长期生效。
实操建议:
- 对可疑进程(如
sshd、crond)查其环境:cat /proc//environ | tr '\0' '\n' | grep LD_PRELOAD - 全局搜索启动脚本:
grep -r "LD_PRELOAD=" /etc/{profile*,bash*,systemd} ~/.bash* 2>/dev/null - 注意:普通用户也能设置该变量,但无法影响 setuid 进程(如
sudo、passwd),glibc 会自动忽略 - 临时禁用测试:启动命令前加
LD_PRELOAD= command(等号后为空)可清空该变量
识别 LD_AUDIT 滥用痕迹
LD_AUDIT 比 LD_PRELOAD 更危险:它指定一个审计库,在**动态链接器初始化阶段**即被加载,能拦截所有符号解析、重定位甚至 dlopen 调用,且绕过大多数基于 LD_PRELOAD 的检测逻辑。
实操建议:
- 检查运行中进程是否启用审计:
cat /proc/(看是否有审计库内存映射)/maps | grep -i audit - 查看进程启动时的环境:
cat /proc//environ | tr '\0' '\n' | grep LD_AUDIT - 审计库通常需导出特定符号(如
la_version、la_objopen),可用nm -D快速验证| grep la_ - 注意:
LD_AUDIT对 setuid 进程同样被 glibc 忽略,但普通服务(如 nginx、redis)若以非 root 启动则可能被利用
为什么不能只依赖 strings 或 lsof 扫描?
这些工具只能看到已加载的库,但 /etc/ld.so.preload 和 LD_* 变量的影响发生在**进程启动瞬间**,且恶意 so 可能主动卸载自身、隐藏符号、或仅在特定条件触发(如调用 getpwuid 时才注入)。
关键点:
-
lsof -p不显示由LD_PRELOAD加载的库(除非该库后续又被dlopen显式打开) -
strings在内存中找不到隐藏的 hook 函数,尤其当 so 使用 GOT/PLT patch 或直接 inline hook 时 - 真正可靠的基线是:比对当前运行进程的
/proc/与已知干净镜像的预期加载段/maps - 生产环境应禁用
LD_PRELOAD全局生效(通过/etc/ld.so.conf.d/中的ignorepreload选项,或升级到 glibc 2.34+ 后使用setenv("LD_PRELOAD", "", 1)在主程序中清除)










