Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Hacking Slack using postMessage and WebSocket-reconnect to steal your token (detectify.com)
343 points by rpicard on March 1, 2017 | hide | past | favorite | 23 comments


One of the best vuln write-ups I've read in a while, in that it steps you through how the initial entrypoint was found, and the steps needed to turn that into a dangerous exploit.

I think what really makes this writeup worth the read is the insight it shows into the thought process of identifying an interesting bug and weaponizing it. Thanks Frans!


Thanks a lot! I had a lot of fun doing it and I really wanted to get every step of the process out there, so that was some really nice feedback :)


That was a really cool read. It's pretty awesome to see Slack patch it and pay them so quickly, if only all companies could operate like that.


It is not the first one either. The Detectify team is top notch and I don't know how they and their product are not better known


The mitigation creating an a element seems a little bit awkward:

    if (!TS.utility.calls.verifyOriginUrl(evt.origin)) {
      return
    }
    ...
    verifyOriginUrl: function(originHref) {
            var a = document.createElement("a");
            a.href = originHref;
            return a.hostname == window.location.hostname
    },
Is there a JS API for getting the host name from an origin, or is creating DOM elements the way to do this?


The traditional way to do this with good cross browser support is to use a DOM element. As long as it's not added to -the- DOM (page) the overhead is quite small. When you think about it, creating DOM nodes is pretty much one of the core things for a browser to do, so there's been a lot of optimizations for those things over the years.

That doesn't mean that it's pretty. But neither is the DOM API.


There's a URL interface [0] in Web API, but unsupported in IE 11 [1].

[0] https://developer.mozilla.org/en/docs/Web/API/URL

[1] http://caniuse.com/#search=URL


Be careful with createElement('a') in IE. If the URL contains credentials (username or username and password), it'll throw a security exception.

https://support.microsoft.com/en-us/help/834489/internet-exp...


Nope, you would have to build your own, which is fraught with potential vulnerabilities. While roundabout, this does send you through the browser's own URL parsing and validation, which obviously should be secure and well-tested.


evt.origin is already provided by the browser, though. It shouldn't need canonicalization, unless this is some kind of browser compatibility workaround.


It's not canonicalization, it's extracting the hostname from the origin (which contains the protocol and port info as well) without implementing your own URL parsing.


Using a DOM element is the most efficient way to do this.


I would rather use the URL() api : https://developer.mozilla.org/en-US/docs/Web/API/URL


Absolutely no IE support though.


There is a new URL api but it's still "experimental" and not supported at all by IE. This new API is just a different interface to the url parsing logic already used for the location and href objects so you can use those instead and get the same functionality.

A tag elements expose this with the href attribute and it's very lightweight since it's not inserted into the DOM. Create one reusable global element and make a wrapper function around it if you want to be even more efficient.


My suspicion is that creating the <a> tag may be more secure because it's implemented at the browser level, below any Javascript which may be running. Probably also more performant. Not sure though.


There's a node module, but this is a quick hack to do it. Relatively low cost if this function isn't getting called too much. Combining this + some basic memoization would probably be the easiest and most performant solution. I imagine you're usually at most receiving events from a single origin.


That last line is killing my internal JS linter. No reason not to make it ===, right? Also, inconsistent semi-colon usage in the code he showed in the post.


Just out of curiosity, how long did it take for you to come up with this PoC? From the initial notice that something might be exploitable until you sent the email to slack?

Your post makes it look so easy, but it would surely take weeks for me to figure out all these things.


It's a common pitfall and easy to look for. The stuff I spent most time with regarding this specific issue was finding the proper event that did something bad.


Personally, my first clue is that token protection/revocation is rarely implemented properly. It's one of the first things I look at when dealing with a web-based system which is obviously using them.


Exposing onmessage wasn't the best idea. Instead it should be something more restrictive with origin check built in.

addMessageListener("https://*.slack.com", function(data){})


Kudos to Slack for the quick fix! I've also been pleasantly surprised by their response times for bug reports, and even feature requests.

Wonder if their support team is proportionately larger than most startups, or if "10x Support Agents" are a thing?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: