Last updated at Fri, 23 Aug 2019 13:50:15 GMT

Yesterday, Bas Alberts (of Immunity) posted to his blog about the recent Flash patch and his work reversing the code and exploiting the bug. The vulnerable function is exposed through the System.Product namespace but is also accessible by using the ASnative API directly.

The ASnative API is interesting because it offers a different way to call builtin functions, and the only way to call certain undocumented functions. ASnative functions are indexed in a two-dimensional array, with the first index being between 1 and 3000, while the second index is usually below 300. The "escape" function has an index value of (100,0). The two lines of code below are equivalent:

flash.Lib._root.escape("&");
flash.Lib._root._global.ASnative(100,0)("&");

The neat thing about accessing functions by index is that it provides a way to enumerate all available native functions. This can be used to write a quick input fuzzer that may shake out programming flaws in the Flash plugin API. Before we can get started, we still have a few problems to address.

First off, we need to determine what parameters should be passed to each function and how many parameters to test. The Flash ASnative API does not give us any information about parameter counts or types of each entry. The easy way to solve this is to try a set of "bad" inputs and pass these up to four times as four different parameters. This would lead to a series of calls like:

var str:String = "AAA[...]AAA";
flash.Lib._root._global.ASnative(100,0)();
flash.Lib._root._global.ASnative(100,0)(str);
flash.Lib._root._global.ASnative(100,0)(str,str);
flash.Lib._root._global.ASnative(100,0)(str,str,str);
flash.Lib._root._global.ASnative(100,0)(str,str,str,str);

This is far from perfect, but it does provide us with a starting point.

Next, we need a way to report progress back to the user. A common problem with client-side fuzzing (ActiveX, browser native objects, DOM, etc) is that while the test is happening, the user interface appears to be frozen. This makes it tough to provide meaningful feedback about progress during the test. Additionally, it makes it harder to determine what actual function and input that caused a crash when one occurs. In the case of AxMan, progress could be determined by watching the web server logs and the Internet Explorer status bar. In the case of Flash, we would have to call back via Javascript, since the normal UI elements aren't updated fast enough to track progress.

While using a Javascript callback might work, Flash has a feature which can make this process much easier. The XMLSocket class allows the Flash code to connect back to the originating server on a TCP port and perform bidirectional communication. This is a great way to report progress, since the last received TCP message will indicate what ASnative call and input combination triggered a crash. This requires a server-side daemon which handles the XML policy request and displays the progress reports to the user.

Finally, we have to solve one of the most dreaded issues in client-side programming -- the execution watchdog. In the case of Flash, any computation task that takes more than a few seconds will cause a dialog to appear that gives the user the option to interrupt the code. While this is a great feature and prevents a rogue Flash applet from hijacking a browser's resources, it does get in the way of automated testing, since the popups would require constant input from the user. To solve this, the testing loop is broken into chunks of 50 iterations, with each iteration scheduling the next iteration for 250ms in the future. This provides just enough of a break that the watchdog does not kick in. The required test time increases, but the process no longer needs to have a human clicking through the dialogs.

Once the initial code was complete, I tested the latest version of Flash on Ubuntu Linux (10.0.15.3) and Windows XP (10.0.12.36). Both tests resulted in the discovery of about four different fatal crashes. While these all appear to be NULL dereferences, sometimes these are exploitable after all (if you happen to be Mark Dowd).

To test the full set of ASnative functions, I updated the starting counter (createInput(): x = 0) to run the next test immediately after the function which triggered a crash. This, along with the input testing method itself, should be improved in the future to be configurable by the user and passed as parameters to the Flash code. This fuzzer barely scratched the surface in terms of coverage and features, but it still managed to find a  handful of new bugs, and only took a couple hours to hack together.

Have fun!
-HD