|Informative Information for the Uninformed|
If a vulnerability occurs in the context of a system worker thread, it may be possible to cause the thread to restart execution at its entry point without any major adverse side effects. This avoids the issue of having to restore normal execution for the context of the current call frame. To accomplish this, the StartAddress must be extracted from the calling thread's ETHREAD structure. Due to the fact that this relies on the use of undocumented fields, it follows that portability could be a problem. The following table shows the offsets to the StartAddress routine for different operating system versions:
A payload that implements this approach that should be compatible with all of the above described offsets is shown below4.5:
00000000 6A24 push byte +0x24 00000002 5B pop ebx 00000003 FEC7 inc bh 00000005 648B13 mov edx,[fs:ebx] 00000008 FEC7 inc bh 0000000A 8B6218 mov esp,[edx+0x18] 0000000D 29DC sub esp,ebx 0000000F 01D3 add ebx,edx 00000011 803D7002DFFF01 cmp byte [0xffdf0270],0x1 00000018 7C07 jl 0x21 0000001A 8B03 mov eax,[ebx] 0000001C 83EC2C sub esp,byte +0x2c 0000001F EB06 jmp short 0x27 00000021 8B430C mov eax,[ebx+0xc] 00000024 83EC30 sub esp,byte +0x30 00000027 FFE0 jmp eax
This implementation works by first obtaining the current thread context through fs:0x124. Once obtained, a check is performed to see which operating system the payload is running on by looking at the NtMinorVersion attribute of the KUSER_SHARED_DATA structure. The reason this is necessary is because the offsets needed to obtain the StartAddress of the thread and the offset that is needed when restoring the stack are different depending on which operating system is being used. After resolving the StartAddress and adjusting the stack pointer to reflect what it would have been when the function was originally called, all that's required is to transfer control to the StartAddress.
This approach, at least in this specific implementation, may be closely tied to vulnerabilities that occur in system worker thread routines, specifically those that start at nt!ExpWorkerThread. However, the principals could be applied to other system worker threads if the illustrated implementation proves limited. It is also important to realize that since this method depends on undocumented version-specific offsets, it is highly likely that it may not be portable to new versions of the kernel. This approach should also be compatible with Windows 2003 Server SP0/SP1, but the offsets are likely to be different and have not been obtained or tested at this point.