HexBrain

Rocket.Chat · Report #1401268

Persistent CSS injection with ’marked’ markdown parser in Rocket.Chat

Validstatus
highseverity
4upvotes
22 Sept 2022disclosed

Summary

Summary: Rocket.Chat offers two different markdown parsers out of the box: the ’orginal’ one and the ’marked’ one. Both markdown parsers offer a different set of features with different re- strictions. Due to more loose restrictions in the ’marked’ parser, a persistent CSS injection in the web interface of Rocket.Chat is possible.

Description: Due to style injection in the complete chat window, an adversary is able to manipulate not only the style of it, but will also be able to block functionality as well as hijacking the content of targeted users. Hence the payloads are stored in messages, it is a persistent attack vector, which will trigger as soon as the message gets viewed.

Releases Affected:

  • 4.1.0 with 'marked' parser

Steps To Reproduce (from initial installation to vulnerability):

(Add details for how we can reproduce the issue)

  1. Setup a new installation of Rocket.Chat
  2. Enable the 'marked' parser in the admin settings under 'Message' > 'Markdown' > 'Markdown Parser'
  3. Create a second user account with username usertest and a channel containing both accounts 4 . Send some messages between both accounts
  4. Send
<div style="position: fixed; top: 6px; right: 0px; height: 50px; width: 400px; background: rgb(255,0,0); z-index: 3">foobar</div>

This should block the top right channel settings with a red box. 6. Send

foo
<style >
[data-username="usertest"] div div p{
    background: rgba(255, 0, 0, 0.2);
    font-size: 0;
}
[data-username="usertest"] div div p::after{ font-size: initial;
    content: "hacked";
}
</style>

as admin user and observe, that the messages of 'usertest' are overwritten with the content 'hacked'. (It can be done vice versa when replacing 'usertest' in the payload with the admins username).

Supporting Material/References:

Root Cause

The implementation of the ’marked’ render removes html encoding of the message right before rendering it in app/markdown/lib/parser/marked/marked.js line 98.

	message.html = _marked(unescapeHTML(message.html), {
		gfm,
		tables,
		breaks,
		pedantic,
		smartLists,
		smartypants,
		renderer,
		highlight,
	});

	const window = getGlobalWindow();
	const DomPurify = createDOMPurify(window);
	message.html = DomPurify.sanitize(message.html, { ADD_ATTR: ['target'] });

Due to the unscape, the user will be able to inject custom HTML elements. Since DomPurify.sanitize will only sanitize XSS relevant elements and properties, the malicious HTML with the CSS injection will be set into the user’s message.

Suggested mitigation

To avoid the style injection, but still allow the usage of custom tags, DomPurify.sanitize could be configured to also remove style elements and attributes. Another way to mitigate the issue would be to not unescape the html before rendering it with ’marked’ to therefore prohibit the user to use custom HTML in their messages.

Impact

An attacker can block the user from certain functionalities as well as render the chat window unusable (e.g. with a rotation of the complete html body) after the user enters a channel. Another impact of the issue is the authenticity and integrity of messages. Since an adversary will be able to manipulate or hide arbitrary user messages, the authenticity and integrity is not given anymore. These attack vectors are stored in messages, which will make them available for every new user entering the channel.

Fix

Fixed in 5.0>

How it was found

The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original