抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

LD_PRELOAD tips

很多程序都需要链接共享库才能运行, 链接共享库默认会从系统/usr/lib目录中查找, 然后链接.so文件。而且对于同名函数, 只会识别最先出现的那一个。指定LD_PRELOAD变量就能让链接器先去找LD_PRELOAD指定的路径再去找默认路径, 从而实现对函数劫持。

详见man ld.so

实验例子

我们可以通过strace查看一个程序执行过程中使用到的系统调用。再配合上man 2就可以查看系统调用的详细信息, 以便后续覆盖。

来一个经典的篡改whoami

使用strace查看whoami的调用。可以看到调用了geteuid, 使用man 2 geteuid查看详情来做点伪造uid_t geteuid(void)可见返回的是一个用户id。

1
2
3
4
5
6
7
8
9
$ strace whoami
execve("/usr/bin/whoami", ["whoami"], 0x7ffe49e38f60 /* 102 vars */) = 0
brk(NULL) = 0x55b44d693000
...
geteuid() = 1000
...
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++

使用cat /etc/passwd看看都有哪些uid

1
2
$ cat /etc/passwd
root:x:0:0::/root:/bin/zsh

那么可以简单返回个int, 然后gcc --shared -fPIC a.c -o a.so编译.so动态库

1
2
3
4
// a.c
int geteuid() {
return 0;
}

whoami程序前使用LD_PRELOAD环境变量LD_PRELOAD=$(pwd)/a.so whoami, 可以看到返回root, 而我们现在并非root用户。

进一步的, 可以使用ldd命令查看运行都要链接哪些库。可以看到差异

1
2
3
4
5
6
7
8
9
10
$ ldd $(which whoami)
linux-vdso.so.1 (0x00007ffdf99ee000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f3239db6000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f3239fcf000)

$ LD_PRELOAD=$(pwd)/a.so ldd $(which whoami)
linux-vdso.so.1 (0x00007ffd36bf8000)
/home/ring/a.so (0x00007fc4ac3ff000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fc4ac1f2000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fc4ac410000)

伪造后怎么再去调用原来的?

使用<dlfcn.h>中的dlsym(RTLD_NEXT, "name")RTLD_NEXT会找下一个出现的,返回函数指针, 从而实现对原始函数的调用。

使用dlcn.h需要引用dl库-ldlgcc --shared -fPIC -ldl a.c -o a.so

1
2
3
4
5
6
7
#include<stdlib.h>
#include<dlfcn.h>
int geteuid() {
int (*f)(void);
f = dlsym(RTLD_NEXT, "geteuid");
return f();
}

评论