Xlab · 2016/04/07 10:11
The Author:[email protected]
0 x00 profile
Read, write, and execute attributes of memory are one of the most important mechanisms for system security. In general, if you want to overwrite data in memory, you must first make sure that the memory has writable properties, and if you want to execute code in memory, you must first make sure that the memory has executable properties, otherwise an exception will be thrown. However, there are some small exceptions in the Windows system exception handling process, with the help of these exceptions, you can know that it is not writable, know that it is not executable.
0x01 Overwrites read-only memory directly
In my CanSecWest 2014 talk “ROPs are for the 99%”, I introduced an interesting exploit technique for Internet Explorer: By modifying certain flags in JavaScript objects to turn off safe mode, IE can load dangerous objects like wscript.shell and execute arbitrary code without DEP in mind.
However, changing the SafeMode flag isn’t the only way IE can load dangerous objects.
Some of the interfaces in IE are actually implemented in HTML, which is usually stored in resources in IEframe.dll, for example: Print preview is res: / / ieframe. DLL/preview. DLG, organize favorites is res: / / ieframe. DLL/orgfav DLG, page properties is res: / / ieframe. DLL/docppg PPG.
Internet Explorer creates separate rendering instances for this HTML, as well as separate JavaScript engine instances. In the JavaScript engine instances created for the HTML, SafeMode itself is turned off.
So, simply insert JavaScript code into a resource in ieframe.dll and trigger the corresponding function in IE. The inserted code will be treated as IE’s own function code and executed under SafeMode’s closed JavaScript instance.
However, the PE resource section is read-only, and attempts to directly override ieframe.dll resources with a vulnerability that can write to arbitrary addresses will trigger a write access violation:
#! bash eax=00000041 ebx=1e2e31b0 ecx=00000000 edx=00000083 esi=1e2e31b0 edi=68b77fe5 eip=69c6585f esp=0363ac00 ebp=0363ac84 iopl=0 nv up ei pl nz na pe cy cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010207 jscript9! Js::JavascriptOperators::OP_SetElementI+0x117: 69c6585f 88040f mov byte ptr [edi+ecx],al ds:002b:68b77fe5=76 0:008> ! exchain 0363b0f0: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1) 0363b648: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1) 0363bab8: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1) 0363bb78: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+28c0 (69c71564) 0363bbc0: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+2898 (69c7150f) 0363bc44: jscript9! DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+276a (69d0dedd) 0363c588: MSHTML! _except_handler4+0 (66495fa4) CRT scope 0, filter: MSHTML! . Omitted... (6652bbe8) func: MSHTML! . Omitted... (6652bbf1) 0363c62c: user32! _except_handler4+0 (7569a61e) CRT scope 0, func: user32! UserCallWinProcCheckWow+123 (75664456) 0363c68c: user32! _except_handler4+0 (7569a61e) CRT scope 0, filter: user32! DispatchMessageWorker+15e (756659b7) func: user32! DispatchMessageWorker+171 (756659ca) 0363f9a8: ntdll! _except_handler4+0 (776a71f5) CRT scope 0, filter: ntdll! __RtlUserThreadStart+2e (776a74d0) func: ntdll! __RtlUserThreadStart+63 (776a90eb) 0363f9c8: ntdll! FinalExceptionHandler+0 (776f7428)Copy the code
In the exception handling chain above, the exception handler in mshtml. DLL ends up calling Kernel32! RaiseFailFastException (). If the g_fFailFastHandlerDisabled flag is false, it terminates the current process:
#! cpp int __thiscall RaiseFailFastExceptionFilter(int this) { signed int **v1; //[email protected]
CONTEXT *v2; // [email protected]
signed int v3; // [email protected]
UINT v4; // [email protected]
HANDLE v5; // [email protected]v1 = (signed int **)this; if ( ! g_fFailFastHandlerDisabled ) { v2 = *(CONTEXT **)(this + 4); g_fFailFastHandlerDisabled = 1; RaiseFailFastException(*(PEXCEPTION_RECORD *)this, v2, 2u); v3 = 1653; if ( *v1 ) v3 = **v1; v4 = v3; v5 = GetCurrentProcess(); TerminateProcess(v5, v4); } return 0; }Copy the code
However, if the g_fFailFastHandlerDisabled flag is true, the exception handling chain executes to Kernel32! UnhandledExceptionFilter(), and finally kernel32! CheckForReadOnlyResourceFilter () :
#! cpp int __stdcall CheckForReadOnlyResourceFilter(int a1) { int result; //[email protected]
if ( BasepAllowResourceConversion )
result = CheckForReadOnlyResource(a1, 0);
else
result = 0;
return result;
}
Copy the code
If BasepAllowResourceConversion also is true, CheckForReadOnlyResource () function will try to write the paging attribute set to write, and then return to normal.
That is to say, if g_fFailFastHandlerDisabled and BasepAllowResourceConversion first sign these two rewrite to true, then you can directly modify ieframe. The DLL’s resources, and don’t have to worry about the problem of the read-only property of the The operating system takes care of everything.
There’s another small problem. If an operation to modify a memory attribute in CheckForReadOnlyResource() is triggered as described above, the RegionSize of the memory attribute also becomes the size of one memory page, usually 0x1000. Before IE creates a rendering instance from an HTML resource in Ieframe. DLL, MSHTML! The GetResource() function checks the RegionSize property of the memory on which the resource is located and returns a failure if it is smaller than the size of the resource. However, this check can be bypassed by simply overwriting the resource to be overwritten from beginning to end, and the RegionSize grows accordingly.
In this way, Windows write access exceptions to PE file resource section open the green light, you can write very wonderful vulnerability use code.
0x02 Direct Execution Non-executable memory
In my 2009 presentation, “Time Dimensions in Vulnerability Mining,” I described a relatively rare post-address reuse vulnerability for modules. For example, in A program, thread A calls the function of module X, and module X calls the function of module Y. The function of module Y takes a long time to return for some reason. If thread B can release module X before it returns, the return address of module Y’s function will be invalid when it returns. It was discovered that the vulnerability could be triggered by the Flash module in Opera, and a Chinese download tool had similar problems.
There are many other types of vulnerabilities that end up behaving in the same way as the above problem, where you can execute a fixed pointer but have no control over its value. In a DEP free environment, these vulnerabilities are not difficult to exploit, as long as the address where the code will be executed is sprayed. In a DEP environment, these vulnerabilities are generally considered impossible to exploit.
But if the following data is sprayed at the address where it is expected to be executed:
#! cpp typedef struct _THUNK3 { UCHAR MovEdx; // 0xba mov edx, imm32 LONG EdxImmediate; UCHAR MovEcx; // 0xb9 mov ecx, imm32 LONG EcxImmediate; // <- put your Stack Pivot here USHORT JmpEcx; // 0xe1ff jmp ecx } Thunk3;Copy the code
Even in a DEP environment, even though the heap-ejected memory region is definitely unexecutable, you’ll be surprised to see that the system still seems to execute these instructions and jump to the ecX address. By setting ecX to the appropriate value, you can jump to any address and perform the ROP chain.
That’s because Windows implemented a mechanism called ATL Thunk emulation to make certain older versions of the software compatible. When handling an execution access exception, the system kernel checks whether the code at the exception address conforms to the ATL Thunk feature. For ATL thunk code, the kernel simulates execution using the KiEmulateAtlThunk() function.
The ATL Thunk emulation mechanism checks whether the address you want to jump to is in a PE file, and on a CFG-enabled system determines whether the address you want to jump to passes the CFG test. At the same time, the ATL Thunk emulation mechanism over Windows DEP policy after Vista only applied to applications without IMAGE_DLLCHARACTERISTICS_NX_COMPAT. If an application builds with /NXCOMPAT specified, it is no longer compatible with ATL Thunk emulation. Many emulation programs support ATL Thunk emulation, such as many third-party applications and the 32-bit iexplore.exe. So a trick like CVE-2015-2425 in Hacking Team’s leaked emails can be used to exploit a successful memory grab with some kind of heap spray.
Using ATL Thunk emulation as part of the system’s exception handling process to directly execute unexecutable memory could help bring back vulnerabilities that might otherwise be considered untenable.
(Most of this article was completed in October 2014, and covers module addresses, symbolic information, and so on based on Windows Technical Preview 6.4.9841 x64 with Internet Explorer 11.)
0 x03 reference
- ROPs are for the 99%, CanSecWest 2014
- Bypassing Browser Memory Protections
- (CVE-2015-2425) “Gifts” From Hacking Team Continue, IE Zero-Day Added to Mix
- Time Dimensions in Vulnerability Mining, VARA 2009