Exploiting the Otherwise Unexploitable on Windows skywing, skape May 2006 1) Foreword Abstract: This paper describes a technique that can be applied in certain situations to gain arbitrary code execution through software bugs that would not otherwise be exploitable, such as NULL pointer dereferences. To facilitate this, an attacker gains control of the top-level unhandled exception filter for a process in an indirect fashion. While there has been previous work [1, 3] illustrating the usefulness in gaining control of the top-level unhandled exception filter, Microsoft has taken steps in XPSP2 and beyond, such as function pointer encoding[4], to prevent attackers from being able to overwrite and control the unhandled exception filter directly. While this security enhancement is a marked improvement, it is still possible for an attacker to gain control of the top-level unhandled exception filter by taking advantage of a design flaw in the way unhandled exception filters are chained. This approach, however, is limited by an attacker's ability to control the chaining of unhandled exception filters, such as through the loading and unloading of DLLs. This does reduce the global impact of this approach; however, there are some interesting cases where it can be immediately applied, such as with Internet Explorer. Disclaimer: This document was written in the interest of education. The authors cannot be held responsible for how the topics discussed in this document are applied. Thanks: The authors would like to thank H D Moore, and everyone who learns because it's fun. Update: This issue has now been addressed by the patch included in MS06-051. A complete analysis has not yet been performed to ensure that it patches all potential vectors. With that, on with the show... 2) Introduction 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[4]. 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. 3) Understanding Unhandled Exception Filters This chapter provides an introductory background into the way unhandled exception filters are registered and how the process of filtering an exception that is not handled actually works. This information is intended to act as a base for understanding the attack vector described in chapter . If the reader already has sufficient understanding of the way unhandled exception filters operate, feel free to skip ahead. 3.1) Setting the Top-Level UEF In order to make it possible for applications to handle all exceptions on a process-wide basis, the exception dispatcher exposes an interface for registering an unhandled exception filter. The purpose of the unhandled exception filter is entirely application specific. It can be used to log extra information about an unhandled exception, perform some advanced error recovery, handle language-specific exceptions, or any sort of other task that may need to be taken when an exception occurs that is not handled. To specify a function that should be used as the top-level unhandled exception filter for the process, a call must be made to kernel32!SetUnhandledExceptionFilter which is prototyped as[6]: LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); When called, this function will take the function pointer passed in as the lpTopLevelExceptionFilter argument and encode it using kernel32!RtlEncodePointer. The result of the encoding will be stored in the global variable kernel32!BasepCurrentTopLevelFilter, thus superseding any previously established top-level filter. The previous value stored within this global variable is decoded using kernel32!RtlDecodePointer and returned to the caller. Again, the encoding and decoding of this function pointer is intended to prevent attackers from being able to use an arbitrary memory overwrite to redirect it as has been done pre-XPSP2. There are two reasons that kernel32!SetUnhandledExceptionFilter returns a pointer to the original top-level UEF. First, it makes it possible to restore the original top-level UEF at some point in the future. Second, it makes it possible to create an implicit ``chain'' of UEFs. In this design, each UEF can make a call down to the previously registered top-level UEF by doing something like the pseudo code below: ... app specific handling ... if (!IsBadCodePtr(PreviousTopLevelUEF)) return PreviousTopLevelUEF(ExceptionInfo); else return EXCEPTION_CONTINUE_SEARCH; When a block of code that has registered a top-level UEF wishes to deregister itself, it does so by setting the top-level UEF to the value that was returned from its call to kernel32!SetUnhandledExceptionFilter. The reason it does it this way is because there is no true list of unhandled exception filters that is maintained. This method of deregistering has one very important property that will serve as the crux of this document. Since deregistration happens in this fashion, the register and deregister operations associated with a top-level UEF must occur in symmetric order. In one example, the top-level UEF Fx is registered, returning Nx as the previous top-level UEF. Following that, Gx is registered, returning Fx as the previous value. After some period of time, Gx is deregistered by setting Fx as the top-level UEF, thus returning the top-level UEF to the value it contained before Gx was registered. Finally, Fx deregisters by setting Nx as the top-level UEF. 3.2) Handling Unhandled Exceptions When an exception goes through the initial phase of the exception dispatching process and is not handled by any of the registered exception handlers for the thread that the exception occurred in, the exception dispatcher must take one final stab at getting it handled before forcing the application to terminate. One of the options the exception dispatcher has at this point is to pass the exception to a debugger, assuming one is attached. Otherwise, it has no choice but to try to handle the exception internally and abort the application if that fails. To allow this to happen, applications can make a call to the unhandled exception filter associated with the process as described in [5]. In the general case, calling the unhandled exception filter will result in kernel32!UnhandledExceptionFilter being called with information about the exception being dispatched. The job of kernel32!UnhandledExceptionFilter is two fold. First, if a debugger is not present, it must make a call to the top-level UEF registered with the process. The top-level UEF can then attempt to handle the exception, possibly recovering and allowing execution to continue, such as by returning EXCEPTION_CONTINUE_EXECUTION. Failing that, it can either forcefully terminate the process, typically by returning EXCEPTION_EXECUTE_HANDLER or allow the normal error reporting dialog to be displayed by returning EXCEPTION_CONTINUE_SEARCH. If a debugger is present, the unhandled exception filter will attempt to pass the exception on to the debugger in order to give it a chance to handle the exception. When this occurs, the top-level UEF is not called. This is important to remember as the paper goes on, as it can be a source of trouble if one forgets this fact. When operating with no debugger present, kernel32!UnhandledExceptionFilter will attempt to decode the function pointer associated with the top-level UEF by calling kernel32!RtlDecodePointer on the global variable that contains the top-level UEF, kernel32!kernel32!BasepCurrentTopLevelFilter, as shown below: 7c862cc1 ff35ac33887c push dword ptr [kernel32!BasepCurrentTopLevelFilter] 7c862cc7 e8e1d6faff call kernel32!RtlDecodePointer (7c8103ad) If the value returned from kernel32!RtlDecodePointer is not NULL, then a call is made to the now-decoded top-level UEF function, passing the exception information on: 7c862ccc 3bc7 cmp eax,edi 7c862cce 7415 jz kernel32!UnhandledExceptionFilter+0x15b (7c862ce5) 7c862cd0 53 push ebx 7c862cd1 ffd0 call eax The return value of the filter will control whether or not the application continues execution, terminates, or reports an error and terminates. 3.3) Uses for Unhandled Exception Filters In most cases, unhandled exception filters are used for language-specific exception handling. This usage is all done transparently to programmers of the language. For instance, C++ code will typically register an unhandled exception filter through CxxSetUnhandledExceptionFilter during CRT initialization as called from the entry point associated with the program or shared library. Likewise, C++ will typically deregister the unhandled exception filter that it registers by calling CxxRestoreUnhandledExceptionFilter during program termination or shared library unloading. Other uses include programs that wish to do advanced error reporting or information collection prior to allowing an application to terminate due to an unhandled exception. 4) Gaining Control of the Unhandled Exception Filter At this point, the only feasible vector for gaining control of the top-level UEF is to cause calls to be made to kernel32!SetUnhandledExceptionFilter. This is primarily due to the fact that the global variable has the current function pointer encoded. One could consider attempting to cause code to be redirected directly to kernel32!SetUnhandledExceptionFilter, but doing so would require some kind of otherwise-exploitable vulnerability in an application, thus making it not useful in the context of this document. Given these restrictions, it makes sense to think a little bit more about the process involved in registering and deregistering UEFs. Since the chain of registered UEFs is implicit, it may be possible to cause that chain to become corrupt or invalid in some way that might be useful. One of the requirements that is known about the registration process for top-level UEFs is that the register and deregister operations must be symmetric. What happens if they aren't, though? Consider the following example where Fx and Gx are registered and deregistered, but in asymmetric order. In this example, Fx and Gx are registered first. Following that, Fx is deregistered prior to deregistering Gx, thus making the operation asymmetrical. As a result of Fx deregistering first, the top-level UEF is set to Nx, even though Gx should technically still be a part of the chain. Finally, Gx deregisters, setting the top-level UEF to Fx even though Fx had been previously deregistered. This is obviously incorrect behavior, but the code associated with Gx has no idea that Fx has been deregistered due to the implicit chain that is created. If asymmetric registration of UEFs can be made to occur, it might be possible for an attacker to gain control of the top-level UEF. Consider for a moment that the register and deregister operations in the diagram in figure occur during DLL load and unload, respectively. If that is the case, then after deregistration occurs, the DLLs associated with the UEFs will be unloaded. This will leave the top-level UEF set to Fx which now points to an invalid region of memory. If an exception occurs after this point and is not handled by a registered exception handler, the unhandled exception filter will be called. If a debugger is not attached, the top-level UEF Fx will be called. Since Fx points to memory that is no longer associated with the DLL that contained Fx, the process will terminate --- or worse. From a security prospective, the act of leaving a dangling function pointer that now points to unallocated memory can be a dream come true. If a scenario such as this occurs, an attacker can attempt to consume enough memory that will allow them to store arbitrary code at the location that the function originally resided. In the event that the function is called, the attacker's arbitrary code will be executed rather than the code that was was originally at that location. In the case of the top-level UEF, the only thing that an attacker would need to do in order to cause the function pointer to be called is to generate an unhandled exception, such as a NULL pointer dereference. All of these details combine to provide a feasible vector for executing arbitrary code. First, it's necessary to be able to cause at least two DLLs that set UEFs to be deregistered asymmetrically, thus leaving the top-level UEF pointing to invalid memory. Second, it's necessary to consume enough memory that attacker controlled code can reside at the location that one of the UEF functions originally resided. Finally, an exception must be generated that causes the top-level UEF to be called, thus executing the attacker's arbitrary code. The big question, though, is how feasible is it to really be able to control the registering and deregistering of UEFs? To answer that, chapter provides a case study on one such application where it's all too possible: Internet Explorer. 5) Case Study: Internet Explorer Unfortunately for Internet Explorer, it's time for it to once again dawn the all-too-exploitable hat and tell us about how it can be used as a medium to gain arbitrary code execution with all otherwise non-exploitable bugs. In this approach, Internet Explorer is used as a medium for causing DLLs that register and deregister top-level UEFs to be loaded and unloaded. One way in which an attacker can accomplish this is by using Internet Explorer's facilities for instantiating COM objects from within the browser. This can be accomplished either by using the new ActiveXObject construct in JavaScript or by using the HTML OBJECT tag. In either case, when a COM object is being instantiated, the DLL associated with that COM object will be loaded into memory if the object instance is created using the INPROC_SERVER. When this happens, the COM object's DllMain will be called. If the DLL has an unhandled exception filter, it may be registered during CRT initialization as called from the DLL's entry point. This takes care of the registering of UEFs, so long as COM objects that are associated with DLLs that set UEFs can be found. To control the deregister phase, it is necessary to somehow cause the DLLs associated with the previously instantiated COM objects to be unloaded. One approach that can be taken to do this is attempt to leverage the locations that ole32!CoFreeUnusedLibrariesEx is called from. One particular place that it's called from is during the closure of an Internet Explorer window that once hosted the COM object. When this function is called, all currently loaded COM DLLs will have their DllCanUnloadNow routines called. If the routine returns SOK, such as when there are no outstanding references to COM objects hosted by the DLL, then the DLL can be unloaded. Now that techniques for controlling the loading and unloading of DLLs that set UEFs has been identified, it's necessary to come up with an implementation that will allow the deregister phase to occur asymmetrically. One method that can be used to accomplish this illustrated by the registration phase and the deregistration phase described below. Registration: 1. Open window #1 2. Instantiate COMObject1 3. Load DLL 1 4. SetUnhandledExceptionFilter(Fx) => Nx 5. Open window #2 6. Instantiate COMObject2 7. Load DLL 2 8. SetUnhandledExceptionFilter(Gx) => Fx In the example described above, two windows are opened, each of which registers a UEF by way of a DLL that implements a specific COM object. In this example, the first window instantiates COMObject1 which is implemented by DLL 1. When DLL 1 is loaded, it registers a top-level UEF Fx. Once that completes, the second window is opened which instantiates COMObject2, thus causing DLL 2 to be loaded which also registers a top-level UEF, Gx. Once these operations complete, DLL 1 and DLL 2 are still resident in memory and the top-level UEF points to Gx. To gain control of the top-level UEF, Fx and Gx will need to be deregistered asymmetrically. To accomplish this, DLL 1 must be unloaded before DLL 2. This can be done by closing the window that hosts COMObject1, thus causing ole32!CoFreeUnusedLibrariesEx to be called which results in DLL 1 being unloaded. Following that, the window that hosts COMObject2 should be closed, once again causing unused libraries to be freed and DLL 2 unloaded. The diagram below illustrates this process. Deregistration: 1. Close window #1 2. CoFreeUnusedLibrariesEx 3. Unload DLL 1 4. SetUnhandledExceptionFilter(Nx) => Gx 5. Close window #2 6. CoFreeUnusedLibrariesEx 7. Unload DLL 2 8. SetUnhandledExceptionFilter(Fx) => Nx After the process in figure completes, Fx will be the top-level UEF for the process, even though the DLL that hosts it, DLL 1, has been unloaded. If an exception occurs at this point in time, the unhandled exception filter will make a call to a function that now points to an invalid region of memory. At this point, an attacker now has reasonable control over the top-level UEF but is still in need of some approach that can used to place his or her code at the location that Fx resided at. To accomplish this, attackers can make use of the heap-spraying[8, 7] technique that has been commonly applied to browser-based vulnerabilities. The purpose of the heap-spraying technique is to consume an arbitrary amount of memory that results in the contents of the heap growing toward a specific address region. The contents, or spray data, is arbitrary code that will result in an attacker's direct or indirect control of execution flow once the vulnerability is triggered. For the purpose of this paper, the trigger is the generation of an arbitrary exception. As stated above, the heap-spraying technique can be used to place code at the location that Fx resided. However, this is limited by whether or not that location is close enough to the heap to be a practical target for heap-spraying. In particular, if the heap is growing from 0x00480000 and the DLL that contains Fx was loaded at 0x7c800000, it would be a requirement that roughly 1.988 GB of data be placed in the heap. That is, of course, assuming that the target machine has enough memory to contain this allocation (across RAM and swap). Not to mention the fact that spraying that much data could take an inordinate amount of time depending on the speed of the machine. For these reasons, it is typically necessary for the DLL that contains Fx in this example scenario to be mapped at an address that is as close as possible to a region that the heap is growing from. During the research of this attack vector, it was found that all of the COM DLLs provided by Microsoft on XPSP2 are compiled to load at higher addresses which make them challenging to reach with heap-spraying, but it's not impossible. Many 3rd party COM DLLs, however, are compiled with a default load address of 0x00400000, thus making them perfect candidates for this technique. Another thing to keep in mind is that the preferred load address of a DLL is just that: preferred. If two DLLs have the same preferred load address, or their mappings would overlap, then obviously one would be relocated to a new location, typically at a lower address close to the heap, when it is loaded. By keeping this fact in mind, it may be possible to load DLLs that overlap, forcing relocation of a DLL that sets a UEF that would otherwise be loaded at a higher address. It is also very important to note that a COM object does not have to be successfully instantiated for the DLL associated with it to be loaded into memory. This is because in order for Internet Explorer to determine whether or not the COM class can be created and is compatible with one that may be used from Internet Explorer, it must load and query various COM interfaces associated with the COM class. This fact is very useful because it means that any DLL that hosts a COM object can be used --- not just ones that host COM objects that can be successfully instantiated from Internet Explorer. The culmination of all of these facts is a functional proof of concept exploit for Windows XP SP2 and the latest version of Internet Explorer with all patches applied prior to MS06-051. Its one requirement is that the target have Adobe Acrobat installed. Alternatively, other 3rd party (or even MS provided DLLs) can be used so long as they can be feasibly reached with heap-spraying techniques. Technically speaking, this proof of concept exploits a NULL pointer dereference to gain arbitrary code execution. It has been implemented as an exploit module for the 3.0 version of the Metasploit Framework. The following example shows this proof of concept in action: msf exploit(windows/browser/ie_unexpfilt_poc) > exploit [*] Started reverse handler [*] Using URL: http://x.x.x.x:8080/FnhWjeVOnU8NlbAGAEhjcjzQWh17myEK1Exg0 [*] Server started. [*] Exploit running as background job. msf exploit(windows/browser/ie_unexpfilt_poc) > [*] Sending stage (474 bytes) [*] Command shell session 1 opened (x.x.x.x:4444 -> y.y.y.y:1059) msf exploit(windows/browser/ie_unexpfilt_poc) > session -i 1 [*] Starting interaction with 1... Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\Documents and Settings\mmiller\Desktop> 6) Mitigation Techniques In the interest of not presenting a problem without a solution, the authors have devised a few different approaches that might be taken by Microsoft to solve this issue. Prior to identifying the solution, it is important to summarize the root of the problem. In this case, the authors feel that the problem at hand is rooted around a design flaw with the way the unhandled exception filter ``chain'' is maintained. In particular, the ``chain'' management is an implicit thing which hinges on the symmetric registering and deregistering of unhandled exception filters. In order to solve this design problem, some mechanism must be put in place that will eliminate the symmetrical requirement. Alternatively, the symmetrical requirement could be retained so long as something ensured that operations never occurred out of order. The authors feel that this latter approach is more complicated and potentially not feasible. The following sections will describe a few different approaches that might be used or considered to solve this issue. Aside from architecting a more robust implementation, this attack vector may also be mitigated through conventional exploitation counter-measures, such as NX and ASLR. 6.1) Behavioral Change to SetUnhandledExceptionFilter One way in which Microsoft could solve this issue would be to change the behavior of kernel32!SetUnhandledExceptionFilter in a manner that allows it to support true registration and deregistration operations rather than implicit ones. This can be accomplished by making it possible for the function to determine whether a register operation is occurring or whether a deregister operation is occurring. Under this model, when a registration operation occurs, kernel32!SetUnhandledExceptionFilter can return a dynamically generated context that merely calls the routine that is previous to the one that was registered. The fact that the context is dynamically generated makes it possible for the function to distinguish between registrations and deregistrations. When the function is called with a dynamically generated context, it can assume that a deregistration operation os occurring. Otherwise, it must assume that a registration operation is occurring. To ensure that the underlying list of registered UEFs is not corrupted, kernel32!SetUnhandledExceptionFilter can be modified to ensure that when a deregistration operation occurs, any dynamically generated contexts that reference the routine being deregistered can be updated to call to the next-previous routine, if any, or simply return if there is no longer a previous routine. 6.2) Prevent Setting of non-image UEF One approach that could be used to solve this issue for the general case is the modification of kernel32!SetUnhandledExceptionFilter to ensure that the function pointer being passed in is associated with an image region. By adding this check at the time this function is called, the attack vector described in this document can be mitigated. However, doing it in this manner may have negative implications for backward compatibility. For instance, there are likely to be cases where this scenario happens completely legitimately without malicious intent. If a check like this were to be added, a once-working application would begin to fail due to the added security checks. This is not an unlikely scenario. Just because an unhandled exception filter is is invalid doesn't mean that it will eventually cause the application to crash because it may, in fact, never be executed. 6.3) Prevent Execution of non-image UEF Like preventing the setting of a non-image UEF, it may also be possible to to modify kernel32!UnhandledExceptionFilter to prevent execution of the top-level UEF if it points to a non-image region. While this seems like it would be a useful check and should solve the issue, the fact is that it does not. Consider the scenario where a top-level UEF is set to an invalid address due to asymmetric deregistration. Following that, the top-level UEF is set to a new value which is the location of a valid function. After this point, if an unhandled exception is dispatched, kernel32!UnhandledExceptionFilter will see that the top-level UEF points to a valid image region and as such will call it. However, the top-level UEF may be implemented in such a way that it will pass exceptions that it cannot handle onto the previously registered top-level UEF. When this occurs, the invalid UEF is called which may point to arbitrary code at the time that it's executed. The fact that kernel32!UnhandledExceptionFilter can filter non-image regions does not solve the fact that uncontrolled UEFs may pass exceptions on up the chain. 7) Future Research With the technique identified for being able to control the top-level UEF by taking advantage of asymmetric deregistration, future research can begin to identify better ways in which to accomplish this. For instance, rather than relying on child windows in Internet Explorer, there may be another vector through which ole32!CoFreeUnusuedLibrariesEx can be called to cause the asymmetric deregistration to occur By default, ole32!CoFreeUnusedLibrariesEx is called every ten minutes, but this fact is not particulary useful in terms of general exploitation. There may also be better and more refined techniques that can be used to more accurately spray the heap in order to place arbitrary code at the location that a defunct top-level UEF resided at. Aside from improving the technique itself, it is also prudent to consider other software applications this could be affected by this. In most cases, this technique will not be feasible due to an attacker's inability to control the loading and unloading of DLLs. However, should a mechanism for accomplishing this be exposed, it may indeed be possible to take advantage of this. One such target software application that the authors find most intriguing would be IIS. If it were possible for a remote attacker to cause DLLs that use UEFs to be loaded and unloaded in a particular order, such as by accessing websites that load COM objects, then it may be possible for an attacker to leverage this vector on a remote webserver. At the time of this writing, the only approach that the authors are aware of that could permit this are remote debugging features present in ASP.NET that allow for the instantiation of COM objects that are placed in a specific allow list. This isn't a very common configuration, and is also limited by which COM objects can be instantiated, thus making it not particularly feasible. However, it is thought that other, more feasible techniques may exist to accomplish this. Aside from IIS, the authors are also of the opinion that this attack vector could be applied to many of the Microsoft Office applications, such as Excel and Word. These suites are thought to be vulnerable due to the fact that they permit the instantiation and embedding of arbitrary COM objects in the document files. If it were possible to come up with a way to control the loading and unloading of DLLs through these instantiations, it may be possible to take advantage of the flaw outlined in this paper. One particular way in which this may be possible is through the use of macros, but this has a lesser severity because it would require some form of user interaction to permit the execution of macros. Another interesting application that may be susceptible to this attack is Microsoft SQL server. Due to the fact that SQL server has features that permit the loading and unloading of DLLs, it may be possible to leverage a SQL injection attack in a way that makes it possible to gain control of the top-level UEF by causing certain DLLs to be loaded and unloaded However, given the ability to load DLLs, there are likely to be other techniques that can be used to gain code execution as well. Once that occurs, a large query with predictable results could be used as a mechanism to spray the heap. This type of attack could even be accomplished through something as innocuous as a website that is merely backed against the SQL server. Remember, attack vectors aren't always direct. 8) Conclusion The title of this paper implies that an attacker has the ability to leverage code execution of bugs that would otherwise not be useful, such as NULL pointer dereferences. To that point, this paper has illustrated a technique that can be used to gain control of the top-level unhandled exception filter for an application by making the registration and deregistration process asymmetrical. Once the top-level UEF has been made to point to invalid memory, an attacker can use techniques like heap-spraying to attempt to place attacker controlled code at the location that the now-defunct top-level UEF resided at. Assuming this can be accomplished, an attacker simply needs to be able to trigger an unhandled exception to cause the execution of arbitrary code. The crux of this attack vector is in leveraging a design flaw in the assumptions made by the way the unhandled exception filter ``chain'' is maintained. In particular, the design assumes that calls made to register, and subsequently deregister, an unhandled exception filter through kernel32!SetUnhandledExceptionFilter will be done symmetrically. However, this cannot always be controlled, as DLLs that register unhandled exception filters are not always guaranteed to be loaded and unloaded in a symmetric fashion. If an attacker is capable of controlling the order in which DLLs are loaded and unloaded, then they may be capable of gaining arbitrary code execution through this technique, such as was illustrated in the Internet Explorer case study in chapter . While not feasible in most cases, this technique has been proven to work in at least one critical application: Internet Explorer. Going forward, other applications, such as IIS, may also be found to be susceptible to this attack vector. All it will take is a little creativity and the right set of conditions. Bibliography [1] Conover, Matt and Oded Horovitz. Reliable Windows Heap Exploits. http://cansecwest.com/csw04/csw04-Oded+Connover.ppt; accessed May 6, 2006. [2] Kazienko, Przemyslaw and Piotr Dorosz. Hacking an SQL Server. http://www.windowsecurity.com/articles/HackinganSQLServer.html; accessed May 7, 2006. [3] Litchfield, David. Windows Heap Overflows. http://www.blackhat.com/presentations/win-usa-04/bh-win-04-litchfield/bh-win-04-litchfield.ppt; accessed May 6, 2006. [4] Howard, Michael. Protecting against Pointer Subterfuge (Kinda!). http://blogs.msdn.com/michael_howard/archive/2006/01/30/520200.aspx; accessed May 6, 2006. [5] Microsoft Corporation. UnhandledExceptionFilter. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/unhandledexceptionfilter.asp; accessed May 6, 2006. [6] Microsoft Corporation. SetUnhandledExceptionFilter. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/setunhandledexceptionfilter.asp; accessed May 6, 2006. [7] Murphy, Matthew. Windows Media Player Plug-In Embed Overflow; http://www.milw0rm.com/exploits/1505; accessed May 7, 2006. [8] SkyLined. InternetExploiter. http://www.edup.tudelft.nl/ bjwever/exploits/InternetExploiter2.zip; accessed May 7, 2006.