|Informative Information for the Uninformed
Next: Understanding Unhandled Exception Filters Up: Exploiting the Otherwise Unexploitable Previous: Foreword Contents
In the security field, software bugs can be generically grouped into two categories: exploitable or non-exploitable. If a software bug is exploitable, then it can be leveraged to the advantage of the attacker, such as to gain arbitrary code execution. However, if a software bug is non-exploitable, then it is not possible for the attacker to make use of it for anything other than perhaps crashing the application. In more cases than not, software bugs will fall into the category of being non-exploitable simply because they typically deal with common mistakes or invalid assumptions that are not directly related to buffer management or loop constraints. This can be frustrating during auditing and product analysis from an assessment standpoint. With that in mind, it only makes sense to try think of ways to turn otherwise non-exploitable issues into exploitable issues.
In order to accomplish this feat, it's first necessary to try to consider execution vectors that could be redirected to code that the attacker controls after triggering a non-exploitable bug, such as a NULL pointer dereference. For starters, it is known that the triggering of a NULL pointer dereference will cause an access violation exception to be dispatched. When this occurs, the user-mode exception dispatcher will call the registered exception handlers for the thread that generated the exception, allowing each the opportunity to handle the exception. If none of the exception handlers know what to do with it, the user-mode exception dispatcher will call the top-level unhandled exception filter (UEF) via kernel32!UnhandledExceptionFilter (if one has been set). The implementation of a function that is set as the registered top-level UEF is not specified, but in most cases it will be designed to pass exceptions that it cannot handle onto the top-level UEF that was registered previously, effectively creating a chain of UEFs. This process will be explained in more detail in the next chapter.
Aside from the exception dispatching process, there are not any other controllable execution vectors that an attacker might be able to redirect without some other situation-specific conditions. For that reason, the most important place to look for a point of redirection is within the exception dispatching process itself. This will provide a generic means of gaining execution control for any bug that can be made to crash an application.
Since the first part of the exception dispatching process is the calling of registered exception handlers for the thread, it may make sense to see if there are any controllable execution paths taken by the registered exception handlers at the time that the exception is triggered. This may work in some cases, but is not universal and requires analysis of the specific exception handler routines. Without having an ability to corrupt the list of exception handlers, there is likely to be no other method of redirecting this phase of the exception dispatching process.
If none of the registered exception handlers can be redirected, one must look toward a method that can be used to redirect the unhandled exception filter. This could be accomplished by changing the function pointer to call into controlled code as illustrated in[1,3]. However, Microsoft has taken steps in XPSP2, such as encoding the function pointer that represents the top-level UEF. This no longer makes it feasible to directly overwrite the global variable that contains the top-level UEF. With that in mind, it may also make sense to look at the function associated with top-level UEF at the time that the exception is dispatched in order to see if the function itself has any meaningful way to redirect its execution.
From this initial analysis, one is left with being required to perform an application-dependent analysis of the registered exception handlers and UEFs that exist at the time that the exception is dispatched. Though this may be useful in some situations, they are likely to be few and far between. For that reason, it makes sense to try to dive one layer deeper to learn more about the exception dispatching process. Chapter will describe in more detail how unhandled exception filters work, setting the stage for the focus of this paper. Based on that understanding, chapter will expound upon an approach that can be used to gain indirect control of the top-level UEF. Finally, chapter will formalize the results of this analysis in an example of a working exploit that takes advantage of one of the many NULL pointer dereferences in Internet Explorer to gain arbitrary code execution.