Author: Badcode, sebao (know Chong Yu 404 security lab)
Date: 2017-03-17
Roundcube is a widely used open source e-mail program, in the globe there are many organizations and companies are in use. On the server to successfully install Roundcube, it will provide to the user a web interface, authenticated user can through a Web browser, email. 1.1.8 version before and 1.2.4 versions prior to Roundcube the message body show the presence of stored cross site scripting vulnerability. Authorities have released the upgrade announcement is.
1.1. x < 1.1.8 1.2. x < 1.2.4
Payload from. mario
Use telnet to html form to send a packet containing the payload of the message to the target mailbox, or directly using Roundcube to send a html mail Send when using burpsuite capture the_message
value into the payload you can(you can also use other way to send mail, to be noted that the payload will be escaped to).
When a user views the email can trigger a cross site scripting vulnerability.
First look at the entire process, when the user view the messages namely action=show
, index.php
will contain the/program/steps/mail/show. inc
,it will call$OUTPUT->send('message',false)
, jump to/program/include/rcmail_output_html.php
the front end of the output page is generated here. Here will call the xml_command()
this function loops through the template to output the desired data(label,button,message headers,message body, etc.), splice returns. Wherein the fetch message body will jump to the rcmail_message_body
function.
Look under rcmail_message_body
function, in the/program/steps/mail/fun. inc
1169-1329.
``php function rcmail_message_body($attrib) { …
// fetch part of the 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 the value is the message the Content-type of the second part(text/html), when ctype_secondary as html, that is, the mail is html type, it will call rcmail_html4inline
function on the message content for processing. This is why you want to the html form to send the mail of the reasons. Follow up to rcmail_html4inline
function
``php 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, '<style', $last_style_pos)) && ($pos2 = stripos($body, '</style>', $pos))) {
$pos = strpos($body, '>', $pos) + 1;
$len = $pos2 - $pos;
// replace all css definitions with #container [def]
$styles = substr($body, $pos, $len);
$styles = rcube_utils::mod_css_styles($styles, $cont_id, $allow_remote);
$body = substr_replace($body, $styles, $pos, $len);
$last_style_pos = $pos2 + strlen($styles) - $len;
}
......
return $body;
``
You can see that when the message content contains style tags, the style tag content as css styles, call mod_css_styles
function processing, the filter css style danger label. This is also the whole vulnerability to trigger the critical point, the style label’s value is reflected in this. Continue to follow up
``php public static function mod_css_styles($source, $container_id, $allow_remote=false) { $last_pos = 0; $replacements = new rcube_string_replacer;
// ignore the whole block if evil styles are detected
$source = self::xss_entity_decode($source);
$stripped = preg_replace('/[^a-z\(:;]/i', ", $source);
$evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$ allow_remote ? '|url\(' : ");
if (preg_match("/$evilexpr/i", $stripped)) {
return '/* evil! */';
}
......
return $source;
}
``
Come here, you can see that for$source
call xss_entity_decode
function processing, the code behind is the$source
is judged and filtered.
``php public static function xss_entity_decode($content) { $out = html_entity_decode(html_entity_decode($content)); $out = preg_replace_callback(‘/\([0-9a-f]{4})/i’, array(self, ‘xss_entity_decode_callback’), $out); $out = preg_replace(‘#/*.**/# Ums’, ", $out);
return $out;
}
``
xss_entity_decode
the css of the content is decoded, the<img/src=x onerror=alert(1)//
for decoding, return to the<img/src=x onerror=alert(1)//
The original road to return, return to the rcmail_message_body
function, then the$body
content below, and finally return to the rcmail_out_html.php
, splice the other data output contains the payload of the page is the complete output to the front end.
$content
is decoded after, before return$out
using a strip_tags
filter,remove HTML and PHP tags.
Upgrade procedure: https://roundcube.net/news/2017/03/10/updates-1.2.4-and-1.1.8-released