Exceptions in Exceptions - Abusing Special Cases in System Exception Handling to Achieve Unbelievable Vulnerability Exploitation
Memory Read / Write / Execute attributes are one of the most important part of system security. Usually it is mandatory to have writable attribute set before overwriting a block of memory, and executable attribute set before executing code in a block of memory, otherwise an exception is generated. However, there are some special cases in the Windows exception handling procedure that we can take advantage of. By abusing such exceptions, we could write to the unwritable, and execute the unexecutable.
0x01 Directly modify read-only memory locations
In my CanSecWest 2014 talk “ROPs are for the 99%” I introduced an interesting technique – by modifying some flag in JavaScript objects, we can disable the safe mode and let Internet Explorer (IE) load dangerous objects such as WScript.Shell, and execute arbitrary code without worrying about the DEP.
Modifying SafeMode flag isn’t the only way to let IE load dangerous objects.
Some parts of IE are actually implemented in HTML. These HTML code are usually stored in the resource section of ieframe.dll. for example, the print preview page is in res://ieframe.dll/preview.dlg, organize favorites page is in res://ieframe.dll/orgfav.dlg, page properties page is in res://ieframe.dll/docppg.ppg, and so on.
IE will create separate renderer and JavaScript engine instances for these HTML, but the SafeMode is disabled by default in these new JavaScript engine instances.
Therefore, we only need to insert our JavaScript code into the resource section of ieframe.dll, and trigger the corresponding IE functionality, the code will be executed as if it is part of the IE functionality in a SafeMode disabled JavaScript engine instance.
But the resource section of the PE file is read-only. If we use a write-what-where vulnerability to modify the resource of ieframe.dll, an access violation exception is generated:
1 | eax=00000041 ebx=1e2e31b0 ecx=00000000 edx=00000083 esi=1e2e31b0 edi=68b77fe5 |
In the above exception handler chain, the exception handler in mshtml.dll will call kernel32!RaiseFailFastException(). If g_fFailFastHandlerDisabled is set to false, the process will be terminated:
1 | int __thiscall RaiseFailFastExceptionFilter(int this) { |
However, if g_fFailFastHandlerDisabled is set to true, the exception handling chain will call into kernel32!UnhandledExceptionFilter(), and finally kernel32!CheckForReadOnlyResourceFilter():
1 | int __stdcall CheckForReadOnlyResourceFilter(int a1) { |
If BasepAllowResourceConversion is also true, CheckForReadOnlyResource() will set the target page to writable, and return normally.
That is, if we first modify g_fFailFastHandlerDisabled and BasepAllowResourceConversion flag to true, we can then directly modify the resource in ieframe.dll without worrying about read-only attributes, the operating system will take care of it for us.
Another small obstacle. Once page attribute modification is triggered in CheckForReadOnlyResource(), the RegionSize of the memory attribute will also be change to one page size, usually 0x1000. Before IE create renderer instances with HTML resources in ieframe.dll, mshtml!GetResource() checks if the RegionSize attribute is larger than the size of the resource, and fails otherwise. The solution is to completely overwrite the resource from start to end, the RegionSize will increase accordingly and the check is therefore bypassed.
We now have a surreal exploit thanks to the special case for PE resource section in Windows write exception.
0x02 Executing the unexecutable memory locations
In my VARA 2009 talk “Time Factors in Vulnerability Hunting” I introduced a rare module address use-after-free vulnerability. For example, Thread A calls a function in module X, module X in turn calls a time consuming function in module Y. if thread B unloads module X before the function call returns, the return address is invalid when the function call returns. I found such problems in Flash module of the Opera browser at that time. One of the download managers also had similar problems.
Some other vulnerability categories also exhibit similar properties – execution is possible but the address is not controllable. In environments without DEP, these kind of vulnerabilities are not hard to exploit – we only need to spray the code to the target address. But with DEP enabled, these vulnerabilities are usually considered unexploitable.
But if we spray the target address with the following data:
1 | typedef struct _THUNK3 { |
With DEP enabled, the target memory location is no doubt unexecutable, but surprisingly the system seems still executed these instructions, and jumped to the location in ecx. We only need to set ecx to jump to arbitrary memory location and execute the ROP chain.
For compatibility reasons, Windows implemented a mechanism called ATL thunk emulation. When the Windows kernel is handling execution exceptions, it checks if the exception address looks like a ATL thunk. If so, the kernel emulate its execution with KiEmulateAtlThunk() routine.
There are some limitations. ATL thunk emulation checks if the target address is within a PE file, and CFG checks are also enforced on supported systems. After Windows Vista, ATL thunk emulation only applies to applications compiled without IMAGE_DLLCHARACTERISTICS_NX_COMPAT under default DEP policy. If /NXCOMPAT is specified in compiler flag, the ATL thunk emulation is no longer supported. But there are still a lot of programs that does support the ATL thunk emulation, as seen in many third party application, and 32-bit iexplore.exe. Vulnerability such as CVE-2015-2425 in Hacking Team leaked emails is also exploitable with this technique if a heap spray is successful.
By abusing the ATL thunk emulation in system exception handling procedure, we make the unexcutable executable again, and bring some unexploitable vulnerabilities back to life.
Majority of this article was written in October 2014. Module addresses and symbol information were from Windows Technical Preview 6.4.9841 x64 with Internet Explorer 11.
References:
[1] ROPs are for the 99%, CanSecWest 2014, Yang Yu
[2] Bypassing Browser Memory Protections
[3] (CVE-2015-2425) “Gifts” From Hacking Team Continue, IE Zero-Day Added to Mix
[4] Time Factors in Vulnerability Hunting,VARA 2009