Applied high-speed in-process fuzzing: the case of Foxit Reader

Introduction

Fuzzing has now become commonplace, especially since the release of AFL [1]. As performance is key, we’d like to optimize our fuzzing methods to maximize the number of bugs found during a given period of time. This article describes a general method applied to a plugin of Foxit Reader [2] which is responsible for converting an image to PDF.

More specifically, we are focusing on version 7.3.6.321 of Foxit and version 7.3.4.308 of the vulnerable plugin (ConvertToPDF_x86). Several interesting crashes were found for this version of the plugin. As they were independently discovered by another researcher who disclosed them to the Foxit team (leading to a new, fixed version) we have decided to release them now.

Fuzzing method

When an image is opened with Foxit Reader, the plugin ConvertToPDF_x86 is loaded in order to convert the image to PDF and display it. This plugin takes care of the most common image file formats (JPEG, GIF, PNG, …).

By examining the arguments pushed on the stack, we can see that the first one points to the image file path, and the second to the temporary PDF file to be written. Note that due to ASLR the addresses shown below may differ from the list of modules above.

By dynamically altering the arguments when Foxit calls the function, we were able to open any other arbitrary image. Then by restoring the context (notably x86 registers) between calls, it becomes possible to quickly call this conversion function repeatedly. Fortunately, the heap does not need to be restored each time.

This approach can be automated in a number of ways. We could have used Pintool [3], but instead I decided to write a specific tool for optimization purposes.
To this end I wrote a mini debugger that starts Foxit Reader by passing an image as parameter and breaks on the relevant call to the image conversion function in ConvertToPDF_x86.dll in order to get the context to be replayed in the next step.

On an Intel Xeon E3-1230v3 (3.3 GHz) we managed to run between 150 and 300 tests/sec depending on the fuzzing method used.
It is important to note that the fuzzing has to take place within the Foxit process: manually calling the DLL plugin will not work directly.

Fuzzing results

Even with simple bit flipping, a number of crashes were quickly produced, some of them potentially exploitable. A total of three days of fuzzing led to the discovery of the crashes below.

Conclusion

This method could potentially be applied to any piece of software on the condition that one is able to easily recreate the state of the software right before the targeted function (or group of functions) is to be called. This is in my opinion the biggest hurdle to overcome.
The case of ConvertToPDF_x86 is straightforward, but in a number of other cases, memory allocations, deallocations and global state changes (or initialization routines) must be taken care of. Towards this aim Pintool [3] might become very useful and may be an interesting direction for further research.

Note that we could optimize this fuzzing method by hooking the plugin’s read/write access, thus avoiding writing any files on disk during the job.