LD_PRELOAD 与 ld.so.preload 劫持
动态链接程序启动时,loader 会把 preload 列表中的共享库提前载入进程地址空间。利用分两条路线:环境变量 LD_PRELOAD 只影响一次调用或子进程,适合劫持由高权限任务派生的脚本;/etc/ld.so.preload 文件则对系统上每个动态链接程序生效,一旦能以 root 身份写入就是稳定的提权点。
仅限授权环境
写坏 /etc/ld.so.preload 或污染被 source 的配置文件,可能影响目标系统上所有动态链接程序。仅在授权环境操作,保留原始文件副本,验证后立即清理。
路线 A:LD_PRELOAD 环境注入
root 定时任务脚本常常 source 一个配置文件来读取变量。如果该配置文件对当前用户可写,就在里面追加一行:
export LD_PRELOAD=/var/tmp/evil.so
cron 以 root 身份执行脚本时,恶意 so 会随之加载进进程。
编译恶意 so
__attribute__((constructor)) void init(void) {
/* 库被加载时执行的目标动作 */
}
gcc -shared -fPIC -o /var/tmp/evil.so evil.c
__attribute__((constructor)) 标记的函数在库被加载时自动执行,不需要导出符号替换。
受限环境
fork 被禁、system 不可用时,constructor 内只用裸 syscall(如 write、chmod)实现目标动作,避免依赖会触发 fork/exec 的 libc 封装。
路线 B:/etc/ld.so.preload 提权
/etc/ld.so.preload 列出的 so 会随每个动态链接程序 preload。若能以 root 身份写这个文件——例如利用可写组继承的 SUID touch 创建文件,或把输出路径 symlink 到可写输出原语——写入恶意 so 后,任意 root 动态程序启动都会触发。
常见 payload 是在 constructor 里生成 SUID shell:
__attribute__((constructor)) void init(void) {
chmod("/bin/bash", 04755);
}
挂载与清理注意事项
| 事项 | 处理 |
|---|---|
/tmp 常有 sticky 位 | sticky 位提供 symlink 保护,软链接利用需换路径 |
/tmp 常带 nosuid | SUID bash 副本放 /var/tmp 或 home 目录 |
| 攻击后清理 | 还原 ld.so.preload,删除恶意 so 与 SUID 副本 |
审计清单
/etc/ld.so.preload是否存在、属主与内容是否异常。- cron 引用的配置文件是否允许低权限用户写入。
- 系统上是否存在可写组继承的 SUID 工具、可被 symlink 的输出原语。
find / -perm -4000中是否有新增或非常见的 SUID 文件。
防御建议
/etc/ld.so.preload默认不存在,监控该文件的创建事件。- cron 引用的配置文件属主 root 且权限 644。
- 定期审计异常 SUID 文件:
find / -perm -4000。 - 收紧 sudo 白名单中的任意写原语,避免输出路径被 symlink 替换。