当前位置: 首页 > 后端技术 > PHP

在PHP应用程序开发中不正当使用mail()函数引发的血案

时间:2023-03-29 18:05:33 PHP

PHP应用开发中mail()函数使用不当导致的血案2016-9920)。该漏洞允许攻击者通过使用Roundcube界面发送精心制作的电子邮件在目标系统上执行任意命令。在我们将漏洞提交给厂商并发布相关漏洞分析文章后,PHP内联函数mail()引起的类似安全问题也陆续在其他PHP应用中暴露出来。在本文中,我们将分析这些漏洞的共同点,哪些安全补丁仍然存在问题,以及如何安全地使用mail()函数。PHP的mail()函数分析PHP自带一个内联函数mail()用于在PHP应用程序中发送电子邮件。开发者可以通过以下五个参数配置邮件发送。http://php.net/manual/en/func...boolmail(string$to,string$subject,string$message[,string$additional_headers[,string$additional_parameters]]这里函数的前三个参数我此处不再赘述,因为这些参数一般不会受到注入攻击的影响,但值得注意的是,如果$to参数由用户控制,则可以向任意邮箱地址发送垃圾邮件,我们重点分析最后两个参数,第四个参数$additional_headers的主要作用是指定额外的邮件头,比如From,Reply-To,Cc,Bcc。由于邮件头是由CRLF换行符组成的rn分开。当用户输入可以控制第四个参数时,攻击者可以使用这些字符(rn)来添加其他邮件头。这种攻击方式称为邮件头注入(或短邮件注入)。这种攻击可以发送多封垃圾邮件通过注入抄送:或BCC:邮件头中的字段。值得注意的是,有些邮件程序会自动将n替换为rn。为什么mail()函数的第五个参数处理不当?引发安全问题为了在PHP中使用mail()函数,必须配置电子邮件程序或服务器。在php.ini配置文件中可以使用以下两个选项:1.配置PHP连接的SMTP服务器的主机名和端口2.配置PHP作为邮件传输代理(MTA)的邮件程序的文件路径)当PHP配置了第二个选项时,对mail()函数的调用将导致配置的MTA(邮件传输代理)程序被执行。虽然PHP内部可以调用escapeshellcmd()函数来防止恶意用户注入其他shell命令,但是mail()函数的第五个参数$additional_parameters允许向MTA(邮件传输代理)添加新的程序参数。因此,攻击者可以在某些MTA中附加程序标志,从而创建具有用户可控内容的文件。漏洞演示代码mail("myfriend@example.com","subject","message","","-f".$_GET['from']);上述代码中存在一个远程命令执行漏洞,这个问题很容易被没有安全意识的开发者所忽视。GET参数完全由用户控制,攻击者可以使用此输入将其他附加参数传递给邮件程序。例如在发送邮件的过程中,可以使用-O参数配置发送邮件的选项,使用-X参数指定日志文件的位置。概念验证(PoC)example@example.com-OQueueDirectory=/tmp-X/var/www/html/rce.php这个PoC的功能是在web目录中生成一个PHPwebshel??l。此文件(rce.php)包含被PHP代码污染的日志消息。因此,当访问rce.php文件时,攻击者能够在Web服务器上执行任意PHP代码。读者可以在我们发表的文章和此处找到有关如何利用此漏洞的更多信息。近期相关安全漏洞在很多实际应用中,由于对mail()函数的第五个参数使用不当而导致的安全问题很多。最近发现以下备受瞩目的PHP应用程序受到此类漏洞的影响(大多数是由DawidGolunski发现的)。由于一些广泛使用的Web应用程序(如Wordpress、Joomla和Drupal)的部分模块是基于上述库开发的,因此它们也会受到此类漏洞的影响。为什么escapeshellarg()函数不那么安全?PHP提供了escapeshellcmd()和escapeshellarg()函数来过滤用户输入,防止恶意攻击者执行其他系统命令或参数。直觉上,以下PHP语句看起来很安全,可以防止-param1参数被破坏:system(escapeshellcmd("./program-param1".escapeshellarg($_GET['arg'])));但是,当这个程序有其他可以被利用的参数时,那么这行代码就不安全了。攻击者可以通过注入“foobar'-param2payload”来突破-param1参数的限制。当用户的输入被两个escapeshell*函数处理后,后面的字符串将到达system()函数。./program-param1'foobar'\''-param2payload'从最终系统执行的命令可以看出,两个嵌套的转义函数混淆了引号,允许附加另一个参数param2。PHP的mail()函数内部使用escapeshellcmd()函数过滤传入的参数,防止命令注入攻击。这正是escapeshellarg()函数无法阻止mail()函数第五个参数的攻击的原因。Roundcube和PHPMailer的开发者率先发布了针对该漏洞的补丁。为什么FILTER_VALIDATE_EMAIL不安全?另一种直接的方法是使用PHP的电子邮件过滤器来确保在mail()函数的第五个参数中只使用有效的电子邮件地址。filter_var($email,FILTER_VALIDATE_EMAIL)但是,并非所有可能存在安全问题的字符串都会被此过滤器过滤掉。它允许带有嵌入式双引号的转义空格。由于函数的底层正则表达式实现,filter_var()没有正确过滤输入,导致构造的payload被执行。'a."'-OQueueDirectory=%0D-X/var/www/html/"@a.php对于上面给出的url编码输入,filter_var()的函数返回true,将有效负载标识为有效的电子邮件格式。当开发者使用该功能验证邮件格式作为唯一的安全验证措施时,仍然可以被攻击者利用:类似于我们之前的攻击方式,当PHP程序发送邮件时,我们精心构造的恶意“邮箱地址”将在web服务的根目录生成PHPwebshel??l/:Nosuchfileordirectory记住,filter_var()不适合过滤用户输入的内容,因为它没有严格验证部分字符串如何安全使用mail()函数仔细分析应用程序中传递给mail()函数的参数是否满足以下条件:$to除非用户的输入内容是可以预期的,do不直接使用用户的输入$subject$message可以安全使用$additional_headers过滤r和n字符是安全的$additional_parameters禁止用户输入实际上当用户输入作为shell命令执行时,没有办法恩确保系统的安全性。不要碰运气。如果第5个参数在你的应用程序开发过程中必须由用户控制,你可以使用电子邮件过滤器(emailfilter)将用户输入的合法数据限制为最小字符集,即使它违反了RFC合规性。我们建议不要相信任何转义或引用程序,因为根据历史数据,这些功能存在安全问题,尤其是在不同环境下使用时,可能会暴露出其他安全风险。解决此问题的另一种方法是由PaulBuonopane开发的,可在此处找到。总结许多PHP应用程序都具有向其用户发送电子邮件的功能,例如提醒和通知。尽管电子邮件标头注入是一个众所周知的安全问题,但开发人员在使用mail()函数时,往往会忽略使用不当可能导致远程命令执行漏洞的可能性。在这篇文章中,我们主要分析mail()函数的第五个参数使用不当可能带来的安全风险,以及如何预防此类问题,防止服务器被攻击。本文由家住会计师联盟(www.jiazhua.com)整理编辑!