Monday, July 20, 2015

One Perfect Bug: Exploiting Type Confusion in Flash


Posted by Natalie Silvanovich, Dazed and (Type) Confused

For some attackers, it is important that an exploit be extremely reliable. That is to say, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit should consistently lead to code execution when it is run on a system with a known platform and Flash version. One way to create such an exploit is to use an especially high-quality bug. This post describes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation of one such bug, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 factors that make it especially good for reliable exploitation.

The Bug


CVE-2015-3077 is a type confusion issue in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Adobe Flash Button and MovieClip filters setters that allows any filter type to be confused with any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r filter type. I reported it to Adobe in early February 2015 and it was fixed in May. The bug occurs due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability of an attacker to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constructor that is used to initialize a filter object. An example of code that manifests cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue is below:
         var filter = new flash.filters.BlurFilter();
         object.filters = [filter];
         var e = flash.filters.ConvolutionFilter;
         flash["filters"] = [];
         flash["filters"]["BlurFilter"] = e;
         var f = object.filters;
         var d = f[0];

This code is somewhat confusing because of its use of operator [], which is necessary for it to compile in Flash CS. Logically equivalent code (which is not guaranteed to compile) is below:

         var filter = new flash.filters.BlurFilter();
         object.filters = [filter];
         flash.filters.BlurFilter = flash.filters.ConvolutionFilter;
         var f = object.filters;
         var d = f[0];

This code sets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 filters field of object, a Button or MovieClip to a BlurFilter, which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n stored natively by Flash. The BlurFilter constructor is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n overwritten by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter constructor. Then cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 filters getter is called and an ActionScript object to hold cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 native BlurFilter is constructed, however, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constructor has been overwritten, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter constructor is called. This leads to an object of type ConvolutionFilter that is backed by a native BlurFilter being returned.

The end result of this is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fields of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter can be accessed (read or written) as if it was a BlurFilter, and likewise for any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r filter type. This allows a wide array of manipulation that is useful for exploitation.

The following diagram shows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 layout in memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 native objects that can potentially be confused using this vulnerability in 64-bit Linux.

AS2 Filter Types

In two situations, pointers line up with integers or floats that can be manipulated, which means that pointers can be read and written directly. Also, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fields of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 objects are ordered and sized based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 class definition, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are always in an expected location, so reading and writing will never fail. These properties are important in making cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit reliable.

The Exploit


Since exploiting this issue would likely require triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confusion issue many times, I started off by creating a utility function that performed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confusion, FilterConfuse.confuse. It also performs some cleanup, such as setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ActionScript filter constructors back to normal so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable function can be called multiple times without impacting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 behaviour of ActionScript outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function.

The first step was to bypass ASLR by determining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of a vtable. An ideal way to do this would be to confuse an object with a vtable with an object with a member overlapping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable that can be manipulated, but all filter objects have vtables at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same offset. Instead, I used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object in DisplacementMapFilter to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable address.

To determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location in memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object, I confused cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DisplacementMapFilter with a BevelFilter. This caused cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData pointer stored in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DisplacementMapFilter to line up with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 color properties (shadowColor, shadowAlpha, highlightColor and highlightAlpha) of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BevelFilter. These properties are backed by two 32-bit integers (shown as scolor and hcolor above and below), and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 color properties access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bottom 24 bits of each integer while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 alpha properties access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top 8 bits. Reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se properties and combining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m using bitwise arithmetic, it is possible to extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object.

Retrieving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData pointer

Next, we need to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 top of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object. To do this, I used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix property of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter object. This property is stored as a pointer to an array of floats that are allocated when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 property is set, and an ActionScript array containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se floats is returned when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 property is retrieved. By setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object, it is possible to read out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of this object in memory as an array of floats.

To set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer, I confused a ConvolutionFilter object with a DisplacementMapFilter object (not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same DisplacementMapFilter as used above!) and set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mapPoint property to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object above. The mapPoint property is a point with x and y coordinates that are both integers (p_x and p_y in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 figure below) that line up with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter, which made it easy enough to set this value. It was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n possible to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object by reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix array from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter object (note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object had to be confused to a DisplacementBitmapFilter and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n confused back to a ConvolutionFilter to allow this).

Retrieving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer value

At this point, it becomes more difficult to make this exploit reliable due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of floats. The vtable_low and vtable_high values are read from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter matrix as floats, as that is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array type, but unfortunately, not every possible valid value of a pointer is also a valid float. This means it’s possible that reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value will lead to NaN, or worse, a numeric value that is not quite correct.

The ideal solution to this problem would be to access vtable_high and vtable_low through a getter that interprets cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m as integers, but one is not available, as filter members tend to be floats due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 nature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir functionality.

Fortunately, though, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AS2 virtual machine is lazy with regards to interpreting floats-- it only converts a value in memory to a float when an operation in ActionScript is performed on it. Native operations generally do not cause floats to be interpreted, unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specific operation, such as arithmetic requires it.  This means that when a float from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix array is copied to vtable_low or vtable_high, it will maintain its value in memory, even if it is invalid for a float, until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 variable it was copied to is actually used in ActionScript, or has arithmetic performed on it in native code. So if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 variable value is immediately type confused to a different type that supports a full range of 32-bit values, such as an int, it is guaranteed that it will be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same value as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original value in memory of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix array. So to avoid introducing unreliability into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, it is necessary to perform this type confusion before manipulating any floats in ActionScript.

To do this, I wrote a conversion class, FloatConverter, that uses type confusion in filters to implement integer-to-float and float-to-integer functions. It confuses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ColorMatrixFilter matrix property (not to be confused with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter matrix property) which is a series of inline floats with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GlowFilter color and alpha properties, which access different bytes of an int.

Float converter

While this implements reliable float-to-int conversion, unfortunately, it is not reliable for int-to-float. The way cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 color array in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ColorMatrix filter is accessed in ActionScript, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire array is copied, even if only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first element is accessed. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array is copied, each element is converted to a Number, which sometimes involves accessing pointers (for example, calling valueOf on an object). Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 color array is longer than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire GlowFilter class, it extends onto cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap when confused with a GlowFilter. This means that conversion could occur on unknown values on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap, possibly leading to crashes if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y reference invalid pointers when being converted to Numbers. So for int-to-float, I implemented a float converter (below) that uses a different confusion in ConvolutionFilter and DisplacementMapFilter that is a direct cast, and does not cause any unknown values on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap to be accessed.
Alternate float converter

This solves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem of crashes due to accessing unknown heap values, but unfortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is one more issue with reliability in this exploit relating to floats. It occurs due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter matrix getter. In ActionScript 2, all numeric values are stored as type Number, which is a union between an integer and a pointer to a double. The native ConvolutionFilter matrix is stored as an array of floats, but it is copied into an ActionScript array so that it can be accessed in ActionScript when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix getter is called, and its values are cast to doubles in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process. Then, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 float converter is called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are cast back to floats.

Casting a float to a double and back generally conserves its value, except in one specific case, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 float value is an SNaN. According to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 floating point specification, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are two types of NaNs, quiet NaNs (QNaNs) and signalling NaNs (SNaNs). QNaNs do nothing if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y occur, but SNaNs throw a floating point exception in some situations. In x86, casting a double to a float always results in a QNaN (even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 double resulted from an SNaN) to avoid unexpected exceptions.

So if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lower bits of a pointer happen to be an SNaN, it will be converted to a QNaN, which means that one bit (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first bit of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mantissa, bit 22) will be set when it shouldn’t be. This problem is avoidable when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable is being read-- cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 third byte of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer, which contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit that gets flipped can be read unaligned to verify what its real value is. So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code will do an unaligned read (by performing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 read of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable a second time with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Bitmap pointer incremented by one) and correct cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 int value if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 float happens to be an SNaN.

Using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 float converters implemented above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable address can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be converted to an integer. Now we need to gain code execution using this address. An easy way to move cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 instruction pointer is to overwrite a vtable of an object (or a pointer to an object that has a vtable). This can be done by confusing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter matrix array with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DisplacementFilter BitmapData pointer.

BitmapData objects consist of a series of native backing objects. The ActionScript object contains a pointer to a BitmapData native object, which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n contains pointers to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r native objects. One such object is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bits object, which contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual bitmap bits. This bits object contains many virtual methods which are often cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first methods called when any action is performed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object. To take advantage of this, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit creates a fake BitmapData object with a pointer to a fake bits object, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls a method which will lead to a virtual method call on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake bits object.

The ConvolutionFilter.matrix property can be used to allocate a buffer of floats of any size via its setter as described above. The location of this buffer can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be determined by confusing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ConvolutionFilter with a DisplacementMapFilter and using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DisplacementMapFilter mapPoint property, similar to what was done to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable location. Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated arrays are immutable, it is necessary to first create a fake vtable object and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n a fake bits object pointing to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n create a fake bitmap pointing to it.

The first step is creating a fake vtable and determining its address using ConvolutionFilter/DisplacementMapFilter confusion.

Creating a fake vtable

Then, fake bitmap bits can be created and retrieved using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same method.

Creating a fake Bitmap Bits

Finally, a fake Bitmap pointing to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bits is created.

Creating a fake Bitmap

A reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake bitmap can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be retrieved in ActionScript by setting a DisplacementMapFilter object’s BitmapData object to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake bitmap by confusing it with a BevelFilter, and setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 color properties to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer value, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reverse of what was done to read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original BitmapData object cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable was read out of. This object can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be confused back to a DisplacementMapFilter and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object accessed by calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mapImage getter. Then, whenever a method containing a virtual call (such as setPixel32) is called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method will call into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable.

At this point, it’s worth looking into what’s actually in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable in more detail. The previous discussion of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 float converter ignored one issue with SNaNs: writing floats. The ConvolutionFilter.matrix setter also converts floats to doubles and back before writing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, so if a pointer happens to be an SNaN value, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n gets written to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 matrix array, bit 23 will get set, even if it is not set in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original value. This can be avoided in a limited way by using unaligned writes.

In memory, an SNaN pointer is laid out as follows:

00: XX XX YY QQ XX ZZ 00 00

Where:

XX can be any value from 0 to 0xFF
YY has bit 5 set to zero and no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r constraints
QQ has all bits set to one except for bit 7 which can be 1 or 0
ZZ is a value with bit 7 set to zero with no ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r constraints.

It can be written unaligned as 32-bit floats as follows:

00: 00 XX XX YY
04: QQ XX ZZ 00
08: 00 00 00 00

This guarantees that if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original pointer is an SNaN, none of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unaligned values will be SNaNs (as YY will always have bit 5 unset if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original float is an SNaN). It is not possible to do this with two consecutive pointers (unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are known to both be SNaNs), though as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 layout would cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be:

00: 00 XX XX YY
04: QQ XX ZZ 00
08: 00 XX XX XX
0C: QQ XX ZZ 00
10: 00 00 00 00

The float at 0x08 has bits 22 to 31 unconstrained, so it could end up being an SNaN and be written incorrectly.

So it is possible to write any pointer to a float array, regardless of whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it is an SNaN or not an SNaN, but it can only be done once. After cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial pointer has been written, all additional pointers need to be an SNaN if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original pointer was an SNaN and not an SNaN if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original pointer was not an SNaN. This exploit manages this constraint by only ever writing one pointer to any ConvolutionFilter.matrix array.

For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake Bitmap and fake Bitmap bits, this is easy, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y only need to contain one pointer. The challenge is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable can only contain one pointer. This makes it difficult to both set up parameters for a call and make a call.

A good solution would be to move to a buffer that is fully modifiable after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first call to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable. Fortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData class (which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake bitmap is emulating) has a method, paletteMap which creates such a buffer.  This method has four parameters (redArray, greenArray, blueArray and alphaArray) which are ActionScript arrays of Numbers. When this method is called, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are converted to integers, and copied to a native Array of ints. Then, anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r native method with four pointers to this array (at appropriate offsets for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input arrays) is called. This method cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual call that jumps into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable.

As a part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial call, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array pointers are stored in x64 registers r12, r13, r14 and r15. This is very useful, as it makes pointers to four controllable buffers available. The single pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following gadget:

mov rdi, r13
call [r12]

The buffer at r13 is set to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string “gedit”, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer at r12 is set to a pointer to a gadget in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash library that calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 method system (with no concerns about SNaNs). This will cause gedit to be launched when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual call into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable is made.

This exploit is deterministic up to this point, though it does not exit cleanly (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash player crashes when gedit is exited). This should be fairly trivial to fix by putting multiple calls into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 four available buffers, though. Even if this was fixed, it is not able to survive cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destruction of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash Player (for example, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tab is closed, or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 swf is refreshed). This is because calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destructor of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 filter objects will cause crashes due to confusion of pointers to ConvolutionFilter matrix arrays with pointers to BitmapData objects. These objects are allocated on different heaps, so calling delete on one object when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r was expected will lead to a crash. It is not possible to correct this by type confusing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se objects ‘back’ to a good state, as type confusion in this specific bug creates a copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original bad object will remain, and still need to be freed. It is also not possible to fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem by setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameters on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original object, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BitmapData object and matrix object setters attempt to delete any existing object before setting it. It is possible to avoid this crash while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit in is progress, and as long as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 player remains open, by retaining references to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 objects so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y won’t be freed. The crash will still occur when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 player is destroyed though. That said, it should be possible for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code executed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit to avoid cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash by correcting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confused objects in memory, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r by putting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in a correct state, or setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir destructor pointers to null. This is not implemented in this proof-of-concept exploit though.

What Makes this Bug Reliable?

While type confusion is generally exploitable, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few factors that make CVE-2015-3077 especially amenable to reliable exploitation.

When type confusion is triggered, it always includes two types, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original type of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable object when it is instantiated, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confused type that it becomes after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is triggered. How cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original type object members align with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confused type object members has a big impact on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitability and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reliability of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue. In this case, vulnerable original type members (i.e. pointers) line up with confused type members that can be directly manipulated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker and vice versa. This is a best case scenario that leads to reliable exploitation. Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r common scenario is where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable original type members extend past cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confused type members and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir values are determined by out-of-bounds memory. This situation is usually exploitable, though not as reliably, as it can be difficult to ensure that heap blocks line up with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object in memory as expected. Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r possibility is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are limits on how objects can be manipulated, for example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original type object’s members can only be set to a limited number of values, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confused object can only be read, or only have one specific method called on it. This situation tends to eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r be exploitable or not, based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specific nature of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, and can also lead to bugs such as info leaks that need to be combined with ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r bugs to be exploitable. It is possible that this type of bug could be exploited reliably, but it would need to be a very ‘lucky’ bug that happens to have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right members with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right values.

Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r aspect of this bug is that type confusion occurs at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable function that causes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confusion. This is important because it means that an object can be confused, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n never manipulated in a way that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker doesn’t want it manipulated. Some type confusion bugs can be unreliable or unexploitable because methods that are called after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confusion occur use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confused objects in ways that expect it to be valid when it is not. Note that in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MovieClip object that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type confused field occurs in is set to have 0 by 0 dimensions. This prevents certain calls to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 filter objects that could cause unreliability from occurring, as filters do not need to be applied to an object with no pixels.

Also, in this bug, object members outside of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ones that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker chooses to access are not used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 software. This is anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r problem that can impact cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reliability and exploitability of type confusion bugs. Sometimes, a non-useful (from an attack perspective) member can cause crashes if it’s not possible for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker to correct it. Once again, setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MovieClip to 0 by 0 prevents this, as filter methods are not accessed by Flash for an image with no pixels.

Finally, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to hold a reference to both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original and confused objects is important, as it prevents garbage collection, which almost always leads to a crash if it’s called on a type-confused object. Garbage collection assumes that object members are ‘correct’ in certain ways, such as containing valid pointers, which can cause crashes if this is not true, and it is usually not possible for an attacker to correct this, as garbage collection can occur at any time, so any window of invalidity is a problem. The only completely reliable solution is to prevent garbage collection while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 objects are valid.

Conclusion

A number of factors, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 layout of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original and confused objects members, how and when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object is used and whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object is subject to garbage collection can affect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reliability of a type confusion bug. CVE-2015-3077 is an especially high-quality bug that can be exploited very reliably due to a convergence of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se factors. Exploiting this bug required triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug up to 31 times: eight times to get and set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object members needed for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit and 19 to 23 times for float conversion, depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of SNaNs that occur. While this may seem large, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit is reliable because each step is deterministic and does not rely on any behaviour that is not guaranteed to occur.

1 comment:

  1. Thanks for great article, but It seems that FloatConverter and FilterConfuse.confuse links are broken.

    ReplyDelete