漏洞描述

漏洞发生在KiTrap06函数中, 当“BOP”发生时,此函数就会取出CONTEXT结构里保存的环境,返回到NtVdmControl函数,最后回到ntvdm.exe的用户态部分进行处理。但是因为任何进程都可以读写ntvdm.exe进程地址空间中保存的CONTEXT结构中的数据,而KiTrap06并未验证环境结构的有效性,导致可以修改保存在CONTEXT结构里的返回地址和代码段选择子,进而在内核态执行用户态提供的代码来进行本地权限提升。

漏洞分析

NtVdmControl函数的调用参数为VdmStartExecution,也就是0时,就会向V86模式切换。通过调用VdmpStartExecution函数把要执行的V86代码的环境改写内核堆栈中的TrapFrame结构,这样在系统调用KiSystemService返回时并不会返回到NtVdmControl函数里,而是切换进了V86模式。

参考

NTSTATUS
NTAPI
VdmpStartExecution(VOID)
{
    ....
   // 此函数会改写KiFastCallEntry建立的陷阱帧
    VdmSwapContext(VdmFrame, &VdmTib->MonitorContext,&VdmContext);
     ....
    return VdmFrame->Eax;
}

而在nt!VdmSwapContexts函数中会修改KiFastCallEntry创建的陷阱帧(trap frame)。 将trap frame修改为我们的VdmTib.VdmContext.

参考

nt!VdmSwapContexts(PKTRAP_FRAME TrapFrame,PCONTEXT MonitorContext, PCONTEXT VdmContext) {

TrapFrame->SegCs = VdmContext->SegCs;
TrapFrame->HardwareSegSs = VdmContext->SegSs;
TrapFrame->Eax = VdmContext->Eax;
TrapFrame->Ebx = VdmContext->Ebx;
TrapFrame->Ecx = VdmContext->Ecx;
TrapFrame->Edx = VdmContext->Edx;
TrapFrame->Esi = VdmContext->Esi;
TrapFrame->Edi = VdmContext->Edi;
TrapFrame->Ebp = VdmContext->Ebp;
TrapFrame->HardwareEsp = VdmContext->Esp;
TrapFrame->Eip = VdmContext->Eip;

TrapFrame->SegCs |= RPL_MASK;
TrapFrame->HardwareSegSs |= RPL_MASK;
  /\*Check for bogus CS \*/
  if(TrapFrame->SegCs < KGDT_R0_CODE) {
   /\* Set user-mode \*/
   TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
  }
}

DOS环境模拟代码通过一串无效的操作码\xc4\xc4\xXX\xXX,微软称为“BOP”,来传递请求到VDM进程里。传递过程由内核的第6号中断,也就是处理无效操作码的异常处理程序KiTrap06来完成。通过判断引发异常的操作码为“BOP”,内核会分派到虚拟机监控进程ntvdm.exe中。

漏洞发生于异常处理程序KiTrap06分派运行于V86下的代码产生的“BOP”到监控进程ntvdm.exe的过程中。内核处理虚拟机控制的系统调用NtVdmControl的过程中,会把当前系统环境保存在ntvdm.exe的地址空间中保存线程信息的VDM_TIB结构中的CONTEXT结构里。该结构在Windows2000下位于EPROCESS(ntvdm.exe)->VdmObjects->VdmTib->MonitorContext,也就是(((EPROCESS+0x1dc)+0x98)+0xa04),在其它Windows NT系列里位于fs:[0xf18]->MonitorContext,也就是((fs:[0xf18])+0xa04)。

当“BOP”发生后,就会取出CONTEXT结构里保存的环境,返回到NtVdmControl函数,最后回到ntvdm.exe的用户态部分进行处理。但是因为任何进程都可以读写ntvdm.exe进程地址空间中保存的CONTEXT结构中的数据,而KiTrap06并未验证环境结构的有效性,导致可以修改保存在CONTEXT结构里的返回地址和代码段选择子,进而在内核态执行用户态提供的代码来进行本地提升权限。

参考

1 2