Roundcube 邮件正文存储型XSS(CVE-2017-6820)。
0x00 漏洞概述
1. 漏洞简介
Roundcube 是一款被广泛使用的开源的电子邮件程序,在全球范围内有很多组织和公司都在使用。 在服务器上成功安装 Roundcube 之后,它会提供给用户一个web 接口,通过验证的用户就可以通过 Web 浏览器收发电子邮件。 1.1.8 版本之前和 1.2.4 版本之前的 Roundcube 邮件正文展示中存在存储型跨站脚本漏洞。官方已发布 升级公告 。
2. 影响版本
1.1.x < 1.1.8
1.2.x < 1.2.4
0x01 漏洞复现
Payload来自 .mario
使用telnet 以html的形式发送一封包含 payload 的邮件到目标邮箱中,或者直接使用Roundcube发送一份html的邮件,发送的时候用burpsuite抓包将 _message 的值改成payload即可(也可使用其他方式发送邮件, 要注意的是 payload 是否会被转义)。
当用户查看邮件即可触发跨站脚本漏洞。
0x02 漏洞分析
首先看一下整个处理的流程,当用户查看邮件即 action=show 时, index.php 会包含 /program/steps/mail/show.inc ,这里会调用 $OUTPUT->send('message',false) ,跳到 /program/include/rcmail_output_html.php ,在前端的输出页面就是在这里产生的。在这里会调用 xml_command() 这个函数循环遍历模板输出所需的数据(label,button,message headers,message body等),拼接返回。其中取message body时会跳到 rcmail_message_body 函数。
先看下 rcmail_message_body 函数,在 /program/steps/mail/fun.inc 1169-1329行。
function rcmail_message_body($attrib) { ...... // fetch part body $body = $MESSAGE->get_part_body($part->mime_id, true); // message is cached but not exists (#1485443), or other error if ($body === false) { rcmail_message_error($MESSAGE->uid); } $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array('part' => $part, 'prefix' => '')); $body = rcmail_print_body($body, $part, array('safe' => $safe_mode, 'plain' => !$RCMAIL->config->get('prefer_html'))); if ($part->ctype_secondary == 'html') { $container_id = 'message-htmlpart' . (++$part_no); $body = rcmail_html4inline($body, $container_id, 'rcmBody', $attrs, $safe_mode); $div_attr = array('class' => 'message-htmlpart', 'id' => $container_id); $style = array(); if (!empty($attrs)) { foreach ($attrs as $a_idx => $a_val) $style[] = $a_idx . ': ' . $a_val; if (!empty($style)) $div_attr['style'] = implode('; ', $style); } $out .= html::div($div_attr, $plugin['prefix'] . $body); } else $out .= html::div('message-part', $plugin['prefix'] . $body); } } } ...... return html::div($attrib, $out);}
ctype secondary的值是邮件的Content-type的第二部分(text/html),当ctype secondary为html时,也就是邮件是html类型的,会调用 rcmail_html4inline 函数对邮件的内容进行处理。这就是为什么要以html的形式发送邮件的原因。跟进到 rcmail_html4inline 函数
function rcmail_html4inline($body, $container_id, $body_class='', &$attributes=null, $allow_remote=false) { $last_style_pos = 0; $cont_id = $container_id . ($body_class ? ' div.'.$body_class : ''); // find STYLE tags while (($pos = stripos($body, '