首页
社区
课程
招聘
HEVD内核漏洞学习(2)-UAF
发表于: 2020-10-26 17:50 6360

HEVD内核漏洞学习(2)-UAF

2020-10-26 17:50
6360

这是Windows kernel exploit系列的第二部分 从UAF开始 因为之前有过pwn的经验 所以堆UAF的原理也是清楚 所以我也就直接从漏洞开始了

其实UAF跟其名字一样 释放后重利用 在内存块释放之后 其对应的指针没有被设置为NULL 但是在下次使用之前 有代码堆这块内存进行了修改 比如将内存指针修改为dangling pointer 从而执行我们的shellcode

我们来分析几个对堆块操作的函数

首先这个函数是分配一个非分页的池块(内存中的池分配机制是按块来的 假如每个块的大小是64bytes 需要分配70bytes的内存 就会分配两个块 虽然比较浪费内存 但速度快)并用'A'填充 并将池块编辑为"Hack"(可以在IDA中看到)

AllocateUaFObject

FreeUaFObject
这个函数是用来释放池块 图中是安全版本 所以将g_UseAfterFreeObjectNonPagedPool = NULL 而漏洞驱动中 未将此置为NULL

UseUaFObject
其实函数名已经很明显了 就是使用UAF对象 即就是使用刚才的g_UseAfterFreeObject

AllocateFakeObject
该函数分配fake对象 将对象分配到UAF对象所在的位置

我们对上面的函数分别下断点 来观察利用过程

然后执行exp WinDbg断下 然后单步执行到这里查看池的状态 已经被'A'占用

再次g 运行到第二个断点 单步执行到这里再次查看池的状态 我们的"HACK"已经是Free了 但没有置为NULL

再次g 运行到第三个断点处 将对象分配到UAF对象所在的位置

再次g 此时已经完成堆喷射 执行回调函数 我们再次观察池 可见callbake地址被覆盖为shellcode的地址 自此 我们就完成了利用

我们就根据上面的流程来利用编写exp 我们只要将自己申请的池块大小跟内核中池块大小相同 就有可能会利用它 只伪造一块的话肯定是不够的 我们可以通过在0day2上面学到的“堆喷射”技术 多伪造一些堆块来增加概率 然后释放的时候指向我们的shellcode即可利用漏洞

对于IO控制码 我们可以用IDA来查看IrpDeviceIoCtlHandler函数

最后我们发现利用成功了

其实在分析过程中我已经提到过就是补丁版本用完后将g_UseAfterFreeObjectNonPagedPool置为NULL了 导致无法利用

这次的UAF漏洞是在我看完漏洞战争之后的 这个也简单 容易理解

 
 
NTSTATUS AllocateUaFObjectNonPagedPool(VOID){
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PUSE_AFTER_FREE_NON_PAGED_POOL UseAfterFree = NULL;
    PAGED_CODE();
 
    __try
    {
        DbgPrint("[+] Allocating UaF Object\n");
 
        // Allocate Pool chunk
        UseAfterFree = (PUSE_AFTER_FREE_NON_PAGED_POOL)ExAllocatePoolWithTag(
            NonPagedPool,
            sizeof(USE_AFTER_FREE_NON_PAGED_POOL),
            (ULONG)POOL_TAG
        );
 
        if (!UseAfterFree)
        {
            // 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", sizeof(USE_AFTER_FREE_NON_PAGED_POOL));
            DbgPrint("[+] Pool Chunk: 0x%p\n", UseAfterFree);
        }
 
        // Fill the buffer with ASCII 'A'
        RtlFillMemory((PVOID)UseAfterFree->Buffer, sizeof(UseAfterFree->Buffer), 0x41);
 
        // Null terminate the char buffer
        UseAfterFree->Buffer[sizeof(UseAfterFree->Buffer) - 1] = '\0';
 
        // Set the object Callback function
        UseAfterFree->Callback = &UaFObjectCallbackNonPagedPool;
 
        // Assign the address of UseAfterFree to a global variable
        g_UseAfterFreeObjectNonPagedPool = UseAfterFree;
 
        DbgPrint("[+] UseAfterFree Object: 0x%p\n", UseAfterFree);
        DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
        DbgPrint("[+] UseAfterFree->Callback: 0x%p\n", UseAfterFree->Callback);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
    return Status;
}
NTSTATUS AllocateUaFObjectNonPagedPool(VOID){
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PUSE_AFTER_FREE_NON_PAGED_POOL UseAfterFree = NULL;
    PAGED_CODE();
 
    __try
    {
        DbgPrint("[+] Allocating UaF Object\n");
 
        // Allocate Pool chunk
        UseAfterFree = (PUSE_AFTER_FREE_NON_PAGED_POOL)ExAllocatePoolWithTag(
            NonPagedPool,
            sizeof(USE_AFTER_FREE_NON_PAGED_POOL),
            (ULONG)POOL_TAG
        );
 
        if (!UseAfterFree)
        {
            // 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", sizeof(USE_AFTER_FREE_NON_PAGED_POOL));
            DbgPrint("[+] Pool Chunk: 0x%p\n", UseAfterFree);
        }
 
        // Fill the buffer with ASCII 'A'
        RtlFillMemory((PVOID)UseAfterFree->Buffer, sizeof(UseAfterFree->Buffer), 0x41);
 
        // Null terminate the char buffer
        UseAfterFree->Buffer[sizeof(UseAfterFree->Buffer) - 1] = '\0';
 
        // Set the object Callback function
        UseAfterFree->Callback = &UaFObjectCallbackNonPagedPool;
 
        // Assign the address of UseAfterFree to a global variable
        g_UseAfterFreeObjectNonPagedPool = UseAfterFree;
 
        DbgPrint("[+] UseAfterFree Object: 0x%p\n", UseAfterFree);
        DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
        DbgPrint("[+] UseAfterFree->Callback: 0x%p\n", UseAfterFree->Callback);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
    return Status;
}
FreeUaFObjectNonPagedPool(
    VOID
)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
    PAGED_CODE();
 
    __try
    {
        if (g_UseAfterFreeObjectNonPagedPool)
        {
            DbgPrint("[+] Freeing UaF Object\n");
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Chunk: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
 
#ifdef SECURE
            //
            // Secure Note: This is secure because the developer is setting
            // 'g_UseAfterFreeObjectNonPagedPool' to NULL once the Pool chunk is being freed
            //
 
            ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);
 
            //
            // Set to NULL to avoid dangling pointer
            //
 
            g_UseAfterFreeObjectNonPagedPool = NULL; //漏洞版本未置NULL
#else
            //
            // Vulnerability Note: This is a vanilla Use After Free vulnerability
            // because the developer is not setting 'g_UseAfterFreeObjectNonPagedPool' to NULL.
            // Hence, g_UseAfterFreeObjectNonPagedPool still holds the reference to stale pointer
            // (dangling pointer)
            //
 
            ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);
#endif
 
            Status = STATUS_SUCCESS;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}
FreeUaFObjectNonPagedPool(
    VOID
)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
    PAGED_CODE();
 
    __try
    {
        if (g_UseAfterFreeObjectNonPagedPool)
        {
            DbgPrint("[+] Freeing UaF Object\n");
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Chunk: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
 
#ifdef SECURE
            //
            // Secure Note: This is secure because the developer is setting
            // 'g_UseAfterFreeObjectNonPagedPool' to NULL once the Pool chunk is being freed
            //
 
            ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);
 
            //
            // Set to NULL to avoid dangling pointer
            //
 
            g_UseAfterFreeObjectNonPagedPool = NULL; //漏洞版本未置NULL
#else
            //
            // Vulnerability Note: This is a vanilla Use After Free vulnerability
            // because the developer is not setting 'g_UseAfterFreeObjectNonPagedPool' to NULL.
            // Hence, g_UseAfterFreeObjectNonPagedPool still holds the reference to stale pointer
            // (dangling pointer)
            //
 
            ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);
#endif
 
            Status = STATUS_SUCCESS;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
 
    return Status;
}
NTSTATUS UseUaFObjectNonPagedPool(VOID){
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PAGED_CODE();
    __try
    {
        if (g_UseAfterFreeObjectNonPagedPool)
        {
            DbgPrint("[+] Using UaF Object\n");
            DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
            DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool->Callback: 0x%p\n", g_UseAfterFreeObjectNonPagedPool->Callback);
            DbgPrint("[+] Calling Callback\n");
 
            if (g_UseAfterFreeObjectNonPagedPool->Callback)
            {
                g_UseAfterFreeObjectNonPagedPool->Callback();
            }
            Status = STATUS_SUCCESS;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }
    return Status;
}
NTSTATUS UseUaFObjectNonPagedPool(VOID){
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PAGED_CODE();
    __try
    {
        if (g_UseAfterFreeObjectNonPagedPool)
        {
            DbgPrint("[+] Using UaF Object\n");
            DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
            DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool->Callback: 0x%p\n", g_UseAfterFreeObjectNonPagedPool->Callback);
            DbgPrint("[+] Calling Callback\n");
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-10-26 20:21 被Ring3编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 7
活跃值: (4331)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
2
6
2020-10-26 20:01
0
游客
登录 | 注册 方可回帖
返回
//