详细分析漏洞描述
Microsoft Windows 7 SP1、Windows Server 2008 SP2和Windows Server 2008 R2 SP1都是美国微软(Microsoft)公司的产品。Microsoft Windows 7 SP1是一套供个人电脑使用的操作系统;Windows Server 2008 SP2是一套服务器操作系统。R2 SP1是它的升级版。
Microsoft Windows中存在提权漏洞,该漏洞源于Win32k组件NtUserSetImeInfoEx函数内部SetImeInfoEx函数的没有正确的处理内存中的空指针对象。攻击者可利用该空指针漏洞在内核模式下以提升的权限执行任意代码。
技术分析分配零页内存技术
平时用malloc、new之类的函数会在RtlAllocateHeap已经分配好的堆中申请一块出来,内存不够的时候才会使用ZwAllocateVirualMemory,使用ZwAllocateVirualMemory分配内存的时候参数BaseAdress指定为0时系统会寻找第一个未使用的内存,并且指定参数为0时会分配失败,但参数AllocateType可以指定MEM_TOP_DOWN类型,表示从上向下分配内存。如果指定参数BaseAddress为1,同时指定分配的内存页大小小于一个内存页的长度(如小于8192),分配成功之后地址范围就是 0xFFFFE001(-8191)到 1把0地址包含在内。如果现在直接向0xFFFFE001写入数据会发生异常,因为从0x80000000-0xffffffff是供系统内核空间使用的内存,但是可以直接向0指针地址写入数据。POC首先创建了一个零页内存地址用来存放数据结构。
HMValidateHandle 内核对象tagWND地址泄露技术
攻击者可以使用HMValidateHandle 功能来泄漏一个内核结构tagWND在内核中的地址,这种技术应该属于内核信息泄漏范围。接着创建了一个窗口,然后使用HMValidateHandle 功能查找tagWND在内核中的地址。其接收变量类型PTHRDESKHEAD(tagWND的第一个参数)在下面讲。
构造NtUserSetImeInfoEx带有攻击性的参数
NtUserSetImeInfoEx有一个参数,是一个tagIMEINFOEX结构,这个结构是输入法的扩展信息。这个参数是通过把前面泄漏的tagWND的内核对象覆盖到构造的带攻击性的tagIMEINFOEX参数。tagWND参数有0xB0的字节,tagIMEINFOEX有0x158的字节,覆盖过程中为了避免拷贝与tagWND对象无关的越界内存中,使用RegisterClassExW注册窗口时指定总长度超过tagIMEINFOEX长度的大小。
内核对象tagWND的第一个参数是THRDESKHEAD类型变量head,head->pSelf指向一个在内核全局存在的窗口对象。tagWND->THRDESKHEAD的成员h指定了所属进程的窗口句柄。
tagWND->lpfnWindowProc包含了与该窗口相关联的窗口消息处理。为了在用户的上下文中执行该函数,内核会选择降低权限,也能提升权限,这个行为由tagWND->bServerSideProc标记。下面是NtUserSetImeInfoEx函数内部对参数进行拷贝,并展示了各种结构对应的关系。
tagWND->_THRDESKHEAD的成员head,_THRDESKHEAD->h指向窗口对象句柄,偏移0x14的成员bServerSideProc被标记,意味着提权。
tagIMEINFOEX的hkl指向输入法的窗口对象句柄,第二个成员为tagIMEINFO。
tagIMEINFO接着上面的对象展示,与tagWND类型一致。
tagWND的消息过程的成员lpfnWndProc在偏移0x60的地方,指向了由用户层VirtualAlloc分配的一段可读可写可执行的地址。
看下这个地方对消息的处理,lpfnWndProc指向的消息处理函数是一段shellcode,被拷贝到了应用层申请的可执行的代码内存中。可以看到对消息ID号0x9F9F进行了处理,也就是用户层使用函数SendMessage对窗口发送一个消息ID为0x9F9F,并且经过标记前面的bServerSideProc提权之后这段shellcode将在内核执行。
NtUserSetImeInfoEx函数内部调用了GetProcessWindowStation函数,得到当前进程所在窗口站的句柄。
窗口站句柄是应用层使用CreateWindowStation创建了一个窗口站,并将窗口站与当前进程相关联。
最后NtUserSetImeInfoEx在内部调用了SetImeInfoEx函数,SetImeInfoEx是这个样子。
CVE-2018-8120漏洞的原因就在NtUserSetImeInfoEx内部的SetImeInfoEx函数。SetImeInfoEx漏洞的原因就是没对窗口站对象tagWINDOWSTATION的成员spklList做空指针判断,使其指向了攻击者分配的零页内存,同时spklList指向一个tagKL对象。并把零页内存的对象tagKL的成员hkl与NtUserSetImeInfoEx第一个参数指向同一个窗口对象句柄,那么就跳过了链表的循环逻辑。
这部分的攻击代码,因为类型是DWORD,使用偏移×4就是相关结构的偏移地址。
经过一段精心构造之后,最后把输入法扩展拷贝到了系统内核的处理列表。
零页内存相关数据。
最后使用SendMessage发送了一个消息,成功提权进入了内核执行任意代码,并把4号进程的Token拷贝到当前进程成功的进行了提权操作。
提权操作使用了EPROCESS等一些内核结构的偏移地址。
从Win8开始,对零页内存分配做了缓解措施,让用户进程无法对零页内存分配成功。以后的零页内存防护也只是保证了不会在零页内存分配空间,缓解分配零页内存空间来利用漏洞。用零页内存分配导致的空指针漏洞也只是众多空指针漏洞类型中的一种。通过零页内存保护机制并不能缓解所有的空指针漏洞。
作者:乖巧小墨宝
链接:https://www.jianshu.com/p/14a90fc70853
共同学习,写下你的评论
评论加载中...
作者其他优质文章