PHP通过bypass disable functions执行系统命令的方法汇

一、为什么要bypass disable functions

为了安全起见,很多运维人员会禁用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也有所演示,具体可以参考官方文档: 。

在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漏洞

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/6a2150f8a3b5a2089d89a042e0eecac9.html