快捷搜索:  网络  后门  CVE  渗透  木马  扫描  黑客  as

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

违景

2018年5月15日,ESET表露了其拿获的PDF文档样本中的两枚0-day漏洞。其中CVE-2018-4990为Adobe PDF涉猎器的代码执行漏洞,而CVE-2018-8120则是Windows操作体系Win32k的内核提权漏洞,在获取代码执行权限后通过内核提权漏洞绕过Adobe PDF涉猎器的沙盒维护,完成任意代码执行。

360威胁情报中心在2018年5月25日已经发布了《CVE-2018-4990 Adobe Reader 代码执行漏洞行使阐发》(详见参考资料[1]),而其中的内核提权漏洞虽然已经有地下的漏洞行使代码,但仅仅是针对Windows 32位环境下的行使。由于大部分用户机器已是64位操作体系,所以泄露的行使代码风险有限。而在近日,有安全研究人员在GitHub上上传了针对Windows 7 64位环境下CVE-2018-8120的漏洞行使代码,经验证阐发该漏洞行使代码真实可用,考虑到漏洞相干的手艺细节以及验证程序已经地下,所以此漏洞接下来极有可能被行使来执行大规模的攻击。

漏洞阐发

在本文中我们试图通过地下的针对Windows 7 64位环境的内核提权POC对漏洞道理以及行使过程进行具体阐发,并记录全部阐发过程。若有阐发欠妥的地方敬请谅解。

阐发环境:阐发以及调试的过程将在 Windows 7 x64 为基础的环境中进行

样原先源:https://github.com/unamer/CVE-2018-8120

补丁比较

通过阐发安全公告补丁程序可以知道,本次漏洞首要修复了体系中的win32k.sys内核模块文件,我们将64位Windows 7中的win32k.sys文件与未打补丁的文件进行对比,发现本次针对 win32k.sys 的NtUserSetImeInfoEx函数做了下列修补:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

可以显然看到,补丁后的函数代码在函数中增添了对窗口站对象tagWINDOWSTATION的成员域spklList的值是否为0的校验,要是值为0则函数直接返归:

修补前的代码:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

修补后的代码:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

漏洞细节

根据以上对win32k.sys补丁先后改动的代码对比可知,漏洞发生在函数NtUserSetImeInfoEx中。NtUserSetImeInfoEx 是操作体系提供的接口函数,用于将用户进程定义的输入法扩大信息对象配置在与当前进程关联的窗口站中。

窗口站

窗口站是以及当前进程以及会话(session)相干联的一个内查对象,它包含剪贴板(clipboard)、原子表、一个或多个桌面(desktop)对象等。窗口站 tagWINDOWSTATION 结构体的定义以下:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

NtUserSetImeInfoEx执行过程阐发

知道了补丁代码修复的部分,我们来看下漏洞函数NtUserSetImeInfoEx的详细完成,此函数只有一个tagIMEINFOEX类型的参数:

image.pngCVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

收拾整理后的漏洞函数执行过程阐发以下:

l 函数先获取当前的窗口站rpwinsta,并从rpwinsta指向的窗口站对象中获取spklList成员

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

spklList 是指向关联的键盘布局 tagKL 对象链表首节点的指针。键盘布局 tagKL 结构体的定义以下:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

l 然后函数从首节点最先遍历键盘布局对象链表,直到节点对象的pklNext成员指归到首节点对象为止。函数判定每一个被遍历的节点对象的hkl成员是否与参数 ime_info_ex 指向的源输入法扩大信息对象的hkl成员相称

image.pngCVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

l 接下来函数判定目标键盘布局对象的piiex成员是否为空,且成员变量 fLoadFlag 值是否为 FALSE。要是是,则把参数 ime_info_ex 的数据拷贝到目标键盘布局对象的piiex成员中

image.pngCVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

函数的完成过程比较简单,在这里我们可以清楚的看到阐发过程的第2步中导致漏洞产生的缘故起因:

在遍历键盘布局对象链表 spklList 的时辰并没有判定 spklList 地址是否为 NULL,假设此时 spklList 为空的话,接下来对 spklList 走访的时辰将触发走访异常,导致体系 BSOD 的发生。

POC验证

我们使用PowerShell脚原先测试验证该漏洞,下列PowerShell脚本使用CreateWindowStation创建了一个窗口站,并调用函数 SetProcessWindowStation 将创建的窗口站与当前进程关联起来,然后打印出窗口站的HANDLE,最后调用 NtUserSetImeInfoEx 函数触发漏洞:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

打印出窗口站HANDLE后我们使用PCHunter找到窗口站的内核地址0xfffffA801a1c4270:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

在WinDbg中使用win32k!tagWINDOWSTATION结构类型查看创建的窗口站句柄0xfffffA801a1c4270地址:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

这时辰我们可以看到spklList 在创建的窗口站中默认初始化为空的。结合上面的我们对 NtUserSetImeInfoEx 函数的阐发可知,要是此时我们接着调用 NtUserSetImeInfoEx 函数的话, 就会导致体系 BSOD 的发生:

image.pngCVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

异常代码:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

总结全部漏洞成因:

l 当用户进程调用CreateWindowStation 等函数创建新的窗口站时,终极在内核会执行窗口站创建的操作。在该函数执行期间,新的窗口站对象的 spklList 成员并没有被初始化,将一直指向 NULL 地址。

l 而NtUserSetImeInfoEx并没有对窗口站对象的 spklList 成员做空指针判定,由于当前进程关联的窗口站对象的 spklList 成员指向 NULL 地址,而空地址地点的零页内存此时并没有映照,因此当内核函数 NtUserSetImeInfoEx 在试图走访零页内存时,将触发走访异常,导致BSOD 的发生。

Windows 7 x64环境下的漏洞行使

2018年5月20日,@unamer 在 github 上传了一份使用CVE-2018-8120针对Windows 七、Windows 2008 32位以及64位体系下的提权行使代码。此章节我们通过地下的样原先阐发Windows 7 x64环境下使用该漏洞的提权行使过程。

调配零页内存

由前面的阐发可知,由于代码设计欠妥,当内核中某个对象指针指向空地址如许的位于用户地址空间的内存地址时,用户进程中的行使代码将能够通过调配如许的内存页并进行奇奥的内存布局来完成任意内核代码执行的能力,从而完成提权操作。

而漏洞触发的时辰NtUserSetImeInfoEx 函数会把可控参数拷贝到零地址上,了解捏造地址空间分布知识的话都应该知道,在32位 Windows体系中,可用的捏造地址空间总计为 2^32 字节(4 GB)。通常低地址的2GB用于用户空间,高地址的2GB 用于体系内核空间。而在64位 Windows体系中,捏造地址空间的理论大小为 2^64 字节,但实际上仅使用一部分。范围从 0×000’00000000 至 0x7FF’FFFFFFFF 的 8 TB 用于用户空间,范围从 0xFFFF0800’00000000 至 0xFFFFFFFF’FFFFFFFF 的 248 TB 的部分用于体系空间。可以注意到空指针赋值分区,这一分区是进程地址空间中从0×00000000到0x0000FFFF的闭区间,保留该分区的目的是为了帮助程序员拿获对空指针的赋值。而要是进程中的线程试图读取或写入位于这一分区内的内存地址,则会诱发走访背规异常:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

捏造地址空间分部

而使用ZwAllocateVirtualMemory函数可以在指定进程的捏造空间中申请一块内存,该块内存默认将以64kb大小对齐。将BaseAdress配置为0时,体系会寻觅第一个未使用的内存块来调配,并不能在零页内存中调配空间。在AllocateType参数中有一个调配类型是MEM_TOP_DOWN,该类型表示内存调配从上向下调配内存。要是指定 BaseAddress为一个低地址,例如 1,同时指定调配内存的大小大于这个值 ,例如8192(一个内存页),如许调配成功后 地址范围就是0xFFFFE001(-8191)到 1把0地址包含在内了,此时再去尝试向 NULL指针执行的地址写数据,程序就不会异常了。通过这类方式我们发现在0地址调配内存的同时,也会在高地址(内核空间)调配内存。具体请参考[11]。

Bitmap GDI函数完成内核任意地址读/写

而行使近来几年提出的通过修改Bitmap GDI函数症结对象的方式则可以将有限的任意地址写漏洞转化为内核任意地址读/写。此手艺症结在当创建一个bitmap时,我们可以泄露出其在内核中的地址。这一泄露在Windows10的v1607版本以后才被打上补丁。

当创建一个bitmap时,一个结构被附加到了进程PEB的GdiSharedHandleTable成员中。GdiSharedHandleTable是一个GDICELL64结构体数组的指针:

image.pngCVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

我们可如下列方式找到Bitmap的内核地址:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

使用WinDbg来验证全部过程:

l 起首用下列PowerShell脚本创建一个Bitmap对象,并打印内查对象句柄,然后用工具找到这个的对象以便后面做对比

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

打印出Bitmap内查对象句柄:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

切换进程:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

获取GdiSharedHandleTable地址:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

获取Bitmap 句柄地址:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

可以看到地址fffff900`c1ca6000以及上面图片里用工具获取的一致,Bitmap内核地址有了,该怎么用呢?GDICELL结构的 pKernelAddress 成员指向 BASEOBJECT 结构,无非我们关心的是在这一头部以后,有一个特定的结构体,它的类型是由 wType 成员决定的:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

位图结构:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

pvScan0 成员就是我们需要行使的,因为GetBitmapBits 以及 SetBitmapBits 这两个API能操作这个成员。GetBitmapBits 允许我们在 pvScan0 地址上读任意字节,SetBitmapBits 允许我们在 pvScan0 地址上写任意字节。要是我们有一个漏洞(例如:CVE-2018-8120)可以修改一次内核地址, 把 pvScan0 改为我们想要操作的内核地址,如许是否是就完成了可以重复行使的内核任意读写呢?

有了这些基础知识,我们收拾整理出使用该要领并配合某个任意地址写的漏洞来将GetBitmapBits / SetBitmapBits改造成可以完成任意地址读写的行使函数,详细步骤:

l 创建2个位图(Manager/Worker)

l 使用句柄查找GDICELL64,分别计算两个位图的pvScan0 地址

l 使用漏洞将 WorkerpvScan0 偏移量地址写入 Manager 的 pvScan0 值

l 使用 Manager 上的SetBitmapBits 来选择地址

l 在 Worker 上使用GetBitmapBits/ SetBitmapBits来读取/写入上一步配置的地址

全部行使操作流程以下:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

行使Bitmap GDI完成CVE-2018-8120在Windows 7 x64环境下的漏洞行使

有了上述的所有基础知识,我们来看看行使程序是要是使用该手艺在Windows 7 64位环境下行使CVE-2018-8120完成提权攻击的。

第一步,起首行使ZwAllocateVirtualMemory调配基地址位于零页的内存块,以使零页实现映照:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

调用NtAllocateVirtualMemory函数成功在零地址上面调配了一块空间:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

第二步,创建创建2个位图(Manager/Worker)对象,黑客工具,并使用CVE-2018-8120漏洞将 WorkerpvScan0偏移量地址写入Manager 的 pvScan0 值,创建内核任意地址读写能力,详细操作以下:

l 创建两个bitmap对象

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

l 泄露出各自的内核地址,得到mpv 以及 wpv 两个指针:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

l 使用任意写来配置 mpv 去指向 wpv 的地址,完成可重用的内核任意读写

先要组织环境让函数运行到下面拷贝数据之处,还记得上面我们对 NtUserSetImeInfoEx 函数漏洞道理的阐发吗? NtUserSetImeInfoEx 函数从首节点最先遍历键盘布局对象链表,直到节点对象的pklNext成员指归到首节点对象为止。然后判定每一个被遍历的节点对象的 hkl 成员是否与参数 ime_info_ex 指向的源输入法扩大信息对象的 hkl 成员相称。为了触发后面的拷贝操作,我们需要跳过这个轮回

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

要跳过这个轮回很简单,我们让 pkl->hkl 以及 NtUserSetImeInfoEx 函数的参数地址相称就行了。下面的代码就是在零页地址地位伪造了一个以及 tagIMEINFOEX 结构体 spklList 成员类型同样的 tagKL 结构体,然后把它的 hkl 字段配置为 wpv 的地址。后面我们把 wpv 的地址放在 NtUserSetImeInfoEx 函数的参数 ime_info_ex 的第一个成员内里。如许就不会进入 while ( pkl->hkl != ime_info_ex ) 这个轮回了:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

然后再把 mpv 的地址放在零页内存地址偏移0×50 之处,NtUserSetImeInfoEx 函数会把它的参数( IMEINFOEX 结构)拷贝到目标键盘布局 tagKL 对象的 piiex 成员指向的输入法信息对象缓冲区中。在win7 x64下面这个字段的偏移就是 0×50:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

下列是调试时辰获取到的mpv 以及 wpv 的值:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

接着组织漏洞行使环境,调用CreateWindowStation 函数创建一个窗口站,调用 SetProcessWindowStation 函数把窗口站以及当前进程关联起来,接着组织一个 tagIMEINFOEX 结构,把 wpv 的地址放到它的 hkl 成员中,调用 NtUserSetImeInfoEx 后,NtUserSetImeInfoEx 函数就会把 wpv 的地址拷贝到 mpv 内里:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

在调试器内里我们可以看到 已经成功触发了NtUserSetImeInfoEx 的漏洞:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

当NtUserSetImeInfoEx 执行完后,我们的GDI内核任意读写的环境就已经组织好了:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

注意:NtUserSetImeInfoEx触发的拷贝数据长度是不可控的,me妹妹ove(piiex, &ime_info_ex, 0x160ui64); 代码内里可以看到是0×160的长度,也就是sizeof(tagIMEINFOEX),我们要在这个地方修改Worker Bitmap的 pvScan0的地址,就会把 SURFACE 结构内里的别的数据给笼盖掉。后面调用Gdi32 的 GetBitmapBits/SetBitmapBits 这两个函数就会不成功,因为这两个函数操作pvScan0 的方式是以及 SURFOBJ 结构的 lDelta、iBitmapFormat、iType、fjBitmap 还有 SURFACE 结构的 flags 字段相干的。关于该结构的具体信息可以参考[10]。

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

下列代码是需要修复成员的对应值:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

最后一步,使用 Gdi32 的GetBitmapBits/SetBitmapBits API调用来读写内核地址空间,完成任意代码执行:

下面的代码完成了替代HalDispatchTable 内里的 NtQueryIntervalProfile 函数为我们的提权ShellCode的地址,调用NtQueryIntervalProfile 以达到执行ShellCode的目的:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

终极在ShellCode中替代SYSTEM进程的token为当前进程的token,以完成提权:

CVE-2018-8120在Windows 7 x64环境下的漏洞行使阐发

参考

[1].https://ti.360.net/blog/articles/analysis-of-cve-2018-4990/

[2].https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8120

[3].https://msdn.microsoft.com/en-us/library/windows/hardware/ff569901(v=vs.85).aspx

[4].https://github.com/unamer/CVE-2018-8120

[5].https://github.com/FuzzySecurity/HackSysTeam-PSKernelPwn

[6].https://www.reactos.org/wiki/Techwiki:Win32k/SURFACE

[7].https://www.coresecurity.com/blog/abusing-gdi-for-ring0-exploit-primitives

[8].https://www.coresecurity.com/system/files/publications/2016/10/Abusing-GDI-Reloaded-ekoparty-2016_0.pdf

[9].https://xiaodaozhi.com/exploit/156.html

[10].https://xiaodaozhi.com/exploit/42.html

[11].http://blog.nsfocus.net/null-pointer-vulnerability-defense/

*

您可能还会对下面的文章感兴趣: