Bypassing Same Origin Policy With JSONP APIs and Flash

Disclosed: 2014-07-19 17:32:22 By molnarg To ibb
Unknown
Vulnerability Details
Overview ======== This is a new type of web vulnerability that is made possible by two seemingly unrelated things: - the way JSONP APIs work - the way Flash handles malformed SWF files and has an effect and limitations similar to XSS flaws: - the user has to visit a website set up by the attacker in order to trigger the vulnerability - as a result, the attacker can make arbitrary HTTP request to the vulnerable domain (with the user's cookies sent along with the request) and read the responses Description =========== [JSONP] APIs return JSON data wrapped by an invocation of a callback function specified by the caller. The caller first defines a JavaScript function and then injects a script tag with the JSON API URL as if it were a JavaScript file to load. JSONP APIs became popular because making JSONP requests are is not forbidden by the Same Origin Policy. From the point of view of this discussion, the important part is that **the first bytes of the response can be controlled by a GET parameter** (typically named callback). If an attacker can create a Flash file, that can be passed as callback parameter to a JSONP API, and passes the filters applied to the callback name, then she is able to load this Flash file in the security context of the JSONP API's domain (the target domain). After the Flash file is loaded, she can make HTTP requests through it to the target domain in the name of the user. Example: <object type="application/x-shockwave-flash" data="http://example.com/jsonp-api?callback=__URL_ENCODED_SWF__"> <param name="AllowScriptAccess" value="always"> </object> The response to the HTTP request: __SWF_FILE__({"actual": "API", "response": 15}) There is two significant problems that have to be solved by an attacker: 1. the end of the response is the actual JSON API response, and that makes the response as a whole an invalid SWF file. 2. callback names are almost always filtered, forcing the callback parameter into the [A-Za-z0-9] range The first problem is in fact solved by the way **Flash** handles invalid SWF files: it **ignores additional bytes at the end of an otherwise valid Flash file**. The second problem turns out to be solvable too. The SWF file format specifies a way to compress the whole file (except an 8 byte header) as a DEFLATE stream. **It is possible to create a DEFLATE stream in the [A-Za-z0-9] character range for arbitrary binary data.** (As proven by my [ascii-zip] project) As a demonstration, I've created a Flash file in the given character range that can load an arbitrary SWF file given by the embedder site (the attacker website) into it's security context (the target domain's security context): CWSA7000hCD0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUU7CiudIbEAtWGDtGDGwwwDDGDG0Gt0GDGwtGDG0sDttwwwDG33w0sDDt03G33333sDfBDIHTOHHoKHBhHZLxHHHrlbhHHtHRHXXHHHdHDuYAENjmENDaqfvjmENyDjmENJYYfmLzMENYQfaFQENYnfVNx1D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUU7CiudIbEAtwwwEDG3w0sG0stDDGtw0GDDwwwt3wt333333w03333gFPaEIQSNvTnmAqICTcsacSCtiUAcYVsSyUcliUAcYVIkSICMAULiUAcYVq9D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUU7CiudIbEAtwwuG333swG033GDtpDtDtDGDD33333s03333sdFPOwWgotOOOOOOOwodFhfhFtFLFlHLTXXTXxT8D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUU7kiudIbEAt33swwEGDDtDG0GGDDwwwDt0wDGwwGG0sDDt033333GDt333swwv3sFPDtdtthLtDdthTthxthXXHHHHhHHHHHHhHXhHHHHXhXhXHXhHhiOUOsxCxHwWhsXKTgtSXhsDCDHshghSLhmHHhDXHhEOUoZQHHshghoeXehMdXwSlhsXkhehMdhwSXhXmHH5D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SUUnUUUwGNqdIbe133333333333333333sUUef03gfzA8880HUAH The embedder site can specify the SWF to load through the "name" property of the object tag. The specified SWF file could be a [cross domain proxy] that can make HTTP requests for the embedder site. Related work ============ This attack is inspired by Alok Menghrajani's [related work], where he showed that it is possible to assemble a Flash file in the [\x01-\0x7F] byte range to prove that certain JSONP endpoints are not secure. The real contribution of my work is the demonstration of the fact that this attack is also feasible in the [A-Za-z0-9] character range. This is critical because overwhelming majority of the JSONP endpoints only accept this character range in the callback name. Mitigation ========== Limiting the callback name length is not a good solution, as there is no strong guarantee that it is not possible to come up with an SWF file that conforms to this tightened filter. The API maintainer can mitigate this type of attack by **putting an empty JavaScript callback in front of the callback name in the repsonse**. This makes it impossible to control the first bytes of the response. An other protection would be **hosting JSONP APIs on a sandbox domain**. The latter solution is only effective if there's no crossdomain.xml rule that would allow requests from the sandbox domain to the main domain. A proper solution would be **changing the way Flash handles malformed SWF files so that it won't files with additional data at the end of the SWF file**. Although one of the mitigations is fixing Flash, I don't consider this a Flash vulnerability, as an affected site does not even have to use the Flash technology in order to be vulnerable. Affected sites ============== I've tested the 35 top websites on Wikipedia's (somewhat out of date) copy of the Alexa [toplist](http://en.wikipedia.org/wiki/List_of_most_popular_websites) (after unifying www.google.* domains into a single entry), and 16 (~45%) of them proved to be vulnerable. The unaffected sites fall into the following categories: - Sites that simply don't have any JSONP API. - Google and Facebook: JSONP answers from these sites begin with empty JavaScript comments (probably because they are being extremely cautious and implemented this protection after the publication of Alok Menghrajani's [related work]). - Sites that host all JSONP APIs on a different domain (this is considered as a best practice) and don't have crossdomain.xml rule on the main site that enables cross domain requests from the API domain. - A single site limits the callback name length to 50 characters. [DEMO](https://gabor.molnar.es/bb/9bfb0835d1e72705bb374132c4d2cb3e9a4417e91b9be31a074fb7d644b34988/octameter.html) ======= JSONP: http://json-p.org/ ascii-zip: https://github.com/molnarg/ascii-zip cross domain proxy: https://github.com/borisreitman/CrossXHR related work: http://quaxio.com/jsonp_handcrafted_flash_files/ toplist: http://en.wikipedia.org/wiki/List_of_most_popular_websites
Actions
View on HackerOne
Report Stats
  • Report ID: 10373
  • State: Closed
  • Substate: resolved
  • Upvotes: 5
Share this report