CVE-2016-7255:Virtual Memory, Page Tables, and One Bit
在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的开发者手册来了解有关映射和页表的内容。
键值位(译注:key bit,指具有特殊意义的bit,如下)会被后面的代码所使用。
读/写(R/W)位。 1号位 - 如果为0,则内存不允许写
用户/管理员(U/S)位。 2号位 - 如果为0,则不允许用户模式访问(ring 3)
不可执行(NX)位。 63号位 -如果为1,则内存不允许执行代码。
跟踪一个虚拟地址到它物理地址的映射过程
为了帮助大家理解如何映射一个虚拟地址到物理地址,我这里会使用windbg来展现映射过程。我这里使用的一个小程序,它的功能是在虚拟地址0x1000000上写入“A”。
虚拟地址:
虚拟地址转换到物理地址
在下面的例子中,我使用windbg作为内核调试器,然后把进程地址空间切换到用户进程的上下文中去。
!process 0 0 nameofexe.exe
.process /i
.reload /user
CR3寄存器用于查找PML4表的基地址
第一步是获取cr3寄存器的值:
“r cr3”0x1fddff000
这就是指向PML4表的物理地址。
使用虚拟地址的第47-39位* 8(每个地址是64位或8字节)来寻找页目录指针表的物理地址:0x1ff48867
页目录指针表(Page Directory Pointer Table,PDP)
现在使用PDP表的物理地址并将低12位(867)清零,这12个位会在页表(Page Table Entries table)中被引用。
0x1ff48000+虚拟地址的38-30位乘上8作为偏移,以找到页目录表(Page Directory Table)的物理地址,结果是0x19d90867。
页目录表(Page Directory Table)
清零11-0位,得到物理地址:0x19d90000。
0x19d90000 + 虚拟地址的29-21位* 8得到页表(page table)的物理地址:0x1f491867。
页表(Page Table)
清零第11-0位,获得物理地址0x1f491000
0x1f491000+虚拟地址的第20-12位*8获得物理页的物理地址:0x20692867
一个物理页中的偏移
清零第11-0位,得到物理地址:0x20692000
0x20692000+虚拟地址的第11-0位:0x2692000。在这种情况下,这表示一个物理页中的偏移,并且也表示该页的大小为4kb,0x0-0xfff是0-4095或是表示4kb。
windbg中的!pte命令会提供相同的信息:
!pte - windbg
在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的开发者手册来了解有关映射和页表的内容。
键值位(译注:key bit,指具有特殊意义的bit,如下)会被后面的代码所使用。
读/写(R/W)位。 1号位 - 如果为0,则内存不允许写
用户/管理员(U/S)位。 2号位 - 如果为0,则不允许用户模式访问(ring 3)
不可执行(NX)位。 63号位 -如果为1,则内存不允许执行代码。
跟踪一个虚拟地址到它物理地址的映射过程
为了帮助大家理解如何映射一个虚拟地址到物理地址,我这里会使用windbg来展现映射过程。我这里使用的一个小程序,它的功能是在虚拟地址0x1000000上写入“A”。
虚拟地址:
虚拟地址转换到物理地址
在下面的例子中,我使用windbg作为内核调试器,然后把进程地址空间切换到用户进程的上下文中去。
!process 0 0 nameofexe.exe
.process /i
.reload /user
CR3寄存器用于查找PML4表的基地址
第一步是获取cr3寄存器的值:
“r cr3”0x1fddff000
这就是指向PML4表的物理地址。
使用虚拟地址的第47-39位* 8(每个地址是64位或8字节)来寻找页目录指针表的物理地址:0x1ff48867 内容来自无奈安全网
页目录指针表(Page Directory Pointer Table,PDP)
现在使用PDP表的物理地址并将低12位(867)清零,这12个位会在页表(Page Table Entries table)中被引用。
0x1ff48000+虚拟地址的38-30位乘上8作为偏移,以找到页目录表(Page Directory Table)的物理地址,结果是0x19d90867。
页目录表(Page Directory Table)
清零11-0位,得到物理地址:0x19d90000。
0x19d90000 + 虚拟地址的29-21位* 8得到页表(page table)的物理地址:0x1f491867。
页表(Page Table)
清零第11-0位,获得物理地址0x1f491000 本文来自无奈人生安全网
0x1f491000+虚拟地址的第20-12位*8获得物理页的物理地址:0x20692867
一个物理页中的偏移
清零第11-0位,得到物理地址:0x20692000
0x20692000+虚拟地址的第11-0位:0x2692000。在这种情况下,这表示一个物理页中的偏移,并且也表示该页的大小为4kb,0x0-0xfff是0-4095或是表示4kb。
windbg中的!pte命令会提供相同的信息:
!pte - windbg
内容来自无奈安全网