• CVE-2016-0040


    CVE-2016-0040

    漏洞成因

    通过网上的资料可以了解到这是在nt!WmipReceiveNotifications函数中使用未经初始化的栈数据而导致的漏洞。为了了解为什么会使用未经初始化的栈数据,我们来对比一下补丁前后的代码变化:

    可以看到在补丁后,nt!WmipReceiveNotifications函数并没有修改,同时在补丁后的系统上运行exp发现并没有执行到nt!WmipReceiveNotifications,因此考虑到可能是上层的分发函数加了补丁,在BinDiff中观察上层函数的确进行了修改:

    可以看到补丁后对传入缓冲区的第一个成员进行了校验,如果为0,则不会调nt!WmipReceiveNotifications,在wrk阅读这两个函数的实现后发现被校验的这个成员为PWMIRECEIVENOTIFICATION->HandleCount,结合wrknt!WmipReceiveNotifications的实现可以总结出漏洞成因:

    • 这个未经初始化的栈变量里面储存的是WmipGuidObjectType类型的对象指针,这个栈变量是一个数组,但是由于我们从环三传来的WMIRECEIVENOTIFICATION的结构中我们将PWMIRECEIVENOTIFICATION->HandleCount置为0,而内核层没有对这种情况进行判断,导致在句柄计数为零的情况下nt!WmipReceiveNotifications中没有对这个栈数组进行赋值填充,并在随后的代码中引用位于其中的对象指针,而这个指针数据是之前存留在栈中的垃圾数据,如果内核栈中的数据能由我们控制,那么我们就有可能利用这个漏洞进行内核权限代码执行。
    • 从下面nt!WmipReceiveNotifications的代码实现中可以清晰看到漏洞的成因,当传入的ReceiveNotification结构中的HandleCount0时会跳过对ObjectArray的初始化,但在后续代码仍然可能发生对ObjectArray的使用,如果ObjectArray的值能够被控制,那我们将拥有一个任意地址任意写。
     NTSTATUS WmipReceiveNotifications(
    	PWMIRECEIVENOTIFICATION ReceiveNotification,
    	PULONG OutBufferSize,
    	PIRP Irp
     )
    {
    		
    	......
     
    	for (i = 0; (i < HandleCount); i++)
    	{
    	 
    		Status = ObReferenceObjectByHandle(HandleArray[i].Handle,
                                           WMIGUID_NOTIFICATION,
                                           WmipGuidObjectType,
                                           UserMode,
                                           &GuidObject,
                                           NULL);
     
    		......
    
    		ObjectArray[ObjectCount++].GuidObject = GuidObject;        
    
    		......			
    	}
    
    	if (ReceiveNotification->Action == RECEIVE_ACTION_CREATE_THREAD) 
    	{
    		GuidObject = ObjectArray[0].GuidObject;
            GuidObject->UserModeCallback = (PUSER_THREAD_START_ROUTINE)(ULONG_PTR)ReceiveNotification->UserModeCallback.Handle;
            GuidObject->EventQueueAction = RECEIVE_ACTION_CREATE_THREAD;
            GuidObject->UserModeProcess = UserModeProcess;
            GuidObject->StackSize = StackSize;
            GuidObject->StackCommit = StackCommit;
    		
    		......
    	}
    
    	......
    
    	return(Status);
    }
    

    漏洞利用

    • 内核栈喷射:在网上找到一篇j00ru《nt!NtMapUserPhysicalPages and Kernel Stack-Spraying Techniques》文章,可以通过NtMapUserPhysicalPages 从环三向内核栈中布置0x400 * siezof(ULONG_PTR)大小的数据,从而可以稳定的覆盖ObjectArray的位置,具体细节可以参考上面这篇文章。

    • 在上面的nt!WmipReceiveNotifications伪代码中我们可以看到任意写的值可以由我们控制的是ReceiveNotification->UserModeCallback.Handle,这个值可以由环三我们调用DeviceIoControl时控制。

    • 现在利用的思路是在Win7 sp1上通过泄露窗口tagWND->lpfnWndProc 的地址,然后通过NtMapUserPhysicalPages 向内核栈中大量喷射tagWND->lpfnWndProc 的地址,同时在环三调用DeviceIoControlReceiveNotification->UserModeCallback.Handle设置为环三的窗口过程,达到替换窗口过程的效果。

    利用效果

    参考

    https://bbs.pediy.com/thread-246433.htm

    https://j00ru.vexillium.org/2011/05/windows-kernel-stack-spraying-techniques/

  • 相关阅读:
    Linux Kernel Makefiles Kbuild en
    Android 源码结构分析
    Linux Charger IC 驱动移植总结
    Battery Charging Specification Revision 1.2 中文版本
    OpenCV 3.4.2 Windows系统下的环境搭建(附带opencv_contrib-3.4.2)
    OpenCV 经纬法将鱼眼图像展开
    shell 循环结构
    OpenCV之Mat类使用总结
    shell 条件结构之 if 语句使用总结
    OpenCV Error: Unspecified Error(The Function is not implemented)
  • 原文地址:https://www.cnblogs.com/DreamoneOnly/p/13163036.html
Copyright © 2020-2023  润新知