首页
社区
课程
招聘
[原创]HEVD内核漏洞学习(4)池溢出
发表于: 2020-10-30 15:13 5568

[原创]HEVD内核漏洞学习(4)池溢出

2020-10-30 15:13
5568

现在开始第五部分的池溢出部分 池的话跟堆有些相似 但又有不同 需要进一步了解的 看这里 有人翻译了 这里 亦或者说 这儿 emmmm 其实还有很多资料的

池是一种动态申请的内存结构 是在内核中存在的 池的大小在分配出来是一定的 如果程序没有对输入长度进行检查 就会导致溢出 此时我们就可以控制程序流程

这个函数主要是在调用RtlCopyMemory函数时 未对Size进行控制 导致溢出 溢出到下一个池块的位置 类似于前面的栈溢出

TriggerBufferOverflowNonPagedPool

我们给函数下断点 先计算下偏移 将断点下在RtlCopyMemory函数之前(其实也可以单步运行到就行。。)

然后查看池的状态

此时的返回地址为

单步执行后被覆盖

所以只要控制了这里 就可以 看起来确实是这样的 该如何做呢

需要注意的是 我们需要伪造Event结构体 伪造指针控制程序劫持流 然后进行池喷射增加命中概率

使用CreateEvent函数在内核中创建一个Event 我们查看一下_OBJECT_HEADER TypeIndex是一个索引 对象类型数组是ObTypeIndexTable 是OBJECT_TYPE数组

我们再去查看ObTypeIndexTable结构 在偏移0x28处为TypeInfo 进一步查看之后 发现在偏移0x38处存在全局回调指针

所以我们也就有了清晰的思路 首先通过池溢出将Event结构体的Typeindex覆盖为0 调用相应函数时将会从0内存处去寻找函数指针 我们在用户模式下可以控制0页内存 导致去找到CloseProcedure的值 我们将其覆盖为shellcode的地址即可

利用成功

安全版本中 计算了当前池的大小 导致不会产生溢出

池之前接触的很少 只是知道时内核中类似于堆的东西 所以在学习之前先学习了些池的东西 只了解了些跟这个漏洞有关的东东。。。。 需要学习的还有很多。。。

 
NTSTATUS
TriggerBufferOverflowNonPagedPool(
    _In_ PVOID UserBuffer,
    _In_ SIZE_T Size
)
{
    PVOID KernelBuffer = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
 
    PAGED_CODE();
 
    __try
    {
        DbgPrint("[+] Allocating Pool chunk\n");
 
        //
        // Allocate Pool chunk
        //
 
        KernelBuffer = ExAllocatePoolWithTag(
            NonPagedPool,
            (SIZE_T)POOL_BUFFER_SIZE,
            (ULONG)POOL_TAG
        );
 
        if (!KernelBuffer)
        {
            //
            // Unable to allocate Pool chunk
            //
 
            DbgPrint("[-] Unable to allocate Pool chunk\n");
 
            Status = STATUS_NO_MEMORY;
            return Status;
        }
        else
        {
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
            DbgPrint("[+] Pool Size: 0x%X\n", (SIZE_T)POOL_BUFFER_SIZE);
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelBuffer);
        }
 
        //
        // Verify if the buffer resides in user mode
        //
 
        ProbeForRead(UserBuffer, (SIZE_T)POOL_BUFFER_SIZE, (ULONG)__alignof(UCHAR));
 
        DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
        DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
        DbgPrint("[+] KernelBuffer: 0x%p\n", KernelBuffer);
        DbgPrint("[+] KernelBuffer Size: 0x%X\n", (SIZE_T)POOL_BUFFER_SIZE);
 
#ifdef SECURE
        //
        // Secure Note: This is secure because the developer is passing a size
        // equal to size of the allocated pool chunk to RtlCopyMemory()/memcpy().
        // Hence, there will be no overflow
        //
 
        RtlCopyMemory(KernelBuffer, UserBuffer, (SIZE_T)POOL_BUFFER_SIZE);
#else
        DbgPrint("[+] Triggering Buffer Overflow in NonPagedPool\n");
 
        //
        // Vulnerability Note: This is a vanilla pool buffer overflow vulnerability
        // because the developer is passing the user supplied value directly to
        // RtlCopyMemory()/memcpy() without validating if the size is greater or
        // equal to the size of the allocated Pool chunk
        //
 
        RtlCopyMemory(KernelBuffer, UserBuffer, Size);                    //漏洞点
#endif
 
        if (KernelBuffer)
        {
            DbgPrint("[+] Freeing Pool chunk\n");
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelBuffer);
 
            //
            // Free the allocated Pool chunk
            //
 
            ExFreePoolWithTag(KernelBuffer, (ULONG)POOL_TAG);
            KernelBuffer = NULL;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}
NTSTATUS
TriggerBufferOverflowNonPagedPool(
    _In_ PVOID UserBuffer,
    _In_ SIZE_T Size
)
{
    PVOID KernelBuffer = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
 
    PAGED_CODE();
 
    __try
    {
        DbgPrint("[+] Allocating Pool chunk\n");
 
        //
        // Allocate Pool chunk
        //
 
        KernelBuffer = ExAllocatePoolWithTag(
            NonPagedPool,
            (SIZE_T)POOL_BUFFER_SIZE,
            (ULONG)POOL_TAG
        );
 
        if (!KernelBuffer)
        {
            //
            // Unable to allocate Pool chunk
            //
 
            DbgPrint("[-] Unable to allocate Pool chunk\n");
 
            Status = STATUS_NO_MEMORY;
            return Status;
        }
        else
        {
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
            DbgPrint("[+] Pool Size: 0x%X\n", (SIZE_T)POOL_BUFFER_SIZE);
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelBuffer);
        }
 
        //
        // Verify if the buffer resides in user mode
        //
 
        ProbeForRead(UserBuffer, (SIZE_T)POOL_BUFFER_SIZE, (ULONG)__alignof(UCHAR));
 
        DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
        DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
        DbgPrint("[+] KernelBuffer: 0x%p\n", KernelBuffer);
        DbgPrint("[+] KernelBuffer Size: 0x%X\n", (SIZE_T)POOL_BUFFER_SIZE);
 
#ifdef SECURE
        //
        // Secure Note: This is secure because the developer is passing a size
        // equal to size of the allocated pool chunk to RtlCopyMemory()/memcpy().
        // Hence, there will be no overflow
        //
 
        RtlCopyMemory(KernelBuffer, UserBuffer, (SIZE_T)POOL_BUFFER_SIZE);
#else
        DbgPrint("[+] Triggering Buffer Overflow in NonPagedPool\n");
 
        //
        // Vulnerability Note: This is a vanilla pool buffer overflow vulnerability
        // because the developer is passing the user supplied value directly to
        // RtlCopyMemory()/memcpy() without validating if the size is greater or
        // equal to the size of the allocated Pool chunk
        //

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//