JSON Escaping Out In The Wild (The 10-Minutes XSS)

This case-study focuses on the core aspects and utilities of JSON, specifically its escaping method.

SoundCloud.com, such as many others, uses JSON to fetch user-relative information from the server.
The idea is simple, the server sends the client the HTML (and the Javascript, CSS, images etc) first, and then the javascript code uses ajax to fetch the data from the server.

In this case, the data from the server returns in a JSON format, and the javascript code knows to dissect it and to insert the data in the right places of the page.
The returned data is being escaped (probably) by the JSON escaper mechanism, so any malicious payloads won’t work.

The main question that should be asked here is: can we exploit the way the browser fetches the data? Can we make it fetch arbitrary HTML or Javascript code?

Well, the short answer is no.
The long answer (10 minutes after starting this research) is yes.

At first, I decided to focus on the notifications area (https://soundcloud.com/notifications), where I noticed that ajax requests are being executed when scrolling done (to fetch old notifications).

I have previously inserted some payloads in variant locations on SoundCloud, and analyzed the way the ajax asks for more notifications.
To safely print “bad” characters (‘,”,<,….), the JSON escapes them by putting a \ char before any “bad” character.

And so I started thinking.

What if i’ll do the escaping myself? Will the JSON still escapes it?

Well, it did. The JSON escaper mechanism ‘double-escaped’ payloads that were already escaped. All there was left to do was to pre-escape a payload, which caused to a stored XSS at the notification area.

JSON escaping must be done properly
The only reason why this worked is the assumption of the developers that no one will “pre-escape” their input before submitting it. The JSON mechanism always escaped the input (by adding ” or ‘ chars before it). If you are expecting user’s input to be outputted by a 3rd-party code, you should:
1. Never allow direct use of HTML/Script tags. If you must, allow users to use ‘special chars’ to design their input (such as *bold* instead of <b>).
2. Know the mechanism. JSON adds ” or ‘ before the text. Therefore, if you accept these chars from the user – simply URL encode them.

I’ll use this opportunity to note that the response team of SoundCloud was the fastest one I have ever worked with. Take a loot at the disclosure timeline.

Disclosure Timeline
13/02/2016 23:00 – Vulnerability found & reported.
14/02/2016 08:00 – Vulnerability confirmed by Soundcloud.
14/02/2016 14:00 – Vulnerability patched and bounty awarded (HoF + Swag).