首页
论坛
专栏
课程

[原创][10] HEVD 内核漏洞之TypeConfusing

5天前 533

[原创][10] HEVD 内核漏洞之TypeConfusing

5天前
533

0x00 前言

本篇是HEVD系列的最后一篇学习文章,这段时间,通过阅读前人文章,自己分析源码,调试文件,小有收获。分享出来,希望对和我一样的初学者有所帮助。

感谢前人的付出与分享,让新手能很快的上手,握爪。

实验环境:Win10专业版+VMware Workstation 15 Pro+Win7 x86 sp1

实验工具:VS2015+Windbg+KmdManager+DbgViewer

0x01 漏洞原理

本片介绍类型混淆漏洞,类型混淆,顾名思义,通过分析代码逻辑,使得原先不可利用的类型变量或者缓冲区,修改其类型后,使其变得可以利用。

先来看看漏洞函数:

NTSTATUS TriggerTypeConfusion(
    _In_ PUSER_TYPE_CONFUSION_OBJECT UserTypeConfusionObject
)
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PKERNEL_TYPE_CONFUSION_OBJECT KernelTypeConfusionObject = NULL;

    PAGED_CODE();

    __try
    {
        //
        // Verify if the buffer resides in user mode
        //

        ProbeForRead(
            UserTypeConfusionObject,
            sizeof(USER_TYPE_CONFUSION_OBJECT),
            (ULONG)__alignof(UCHAR)
        );

        //
        // Allocate Pool chunk
        //

        KernelTypeConfusionObject = (PKERNEL_TYPE_CONFUSION_OBJECT)ExAllocatePoolWithTag(
            NonPagedPool,
            sizeof(KERNEL_TYPE_CONFUSION_OBJECT),
            (ULONG)POOL_TAG
        );

        if (!KernelTypeConfusionObject)
        {
            //
            // 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(KERNEL_TYPE_CONFUSION_OBJECT));
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject);
        }

        DbgPrint("[+] UserTypeConfusionObject: 0x%p\n", UserTypeConfusionObject);
        DbgPrint("[+] KernelTypeConfusionObject: 0x%p\n", KernelTypeConfusionObject);
        DbgPrint("[+] KernelTypeConfusionObject Size: 0x%X\n", sizeof(KERNEL_TYPE_CONFUSION_OBJECT));

        KernelTypeConfusionObject->ObjectID = UserTypeConfusionObject->ObjectID;
        KernelTypeConfusionObject->ObjectType = UserTypeConfusionObject->ObjectType;

        DbgPrint("[+] KernelTypeConfusionObject->ObjectID: 0x%p\n", KernelTypeConfusionObject->ObjectID);
        DbgPrint("[+] KernelTypeConfusionObject->ObjectType: 0x%p\n", KernelTypeConfusionObject->ObjectType);


#ifdef SECURE
        //
        // Secure Note: This is secure because the developer is properly setting 'Callback'
        // member of the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer
        // of 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as
        // parameter
        //

        KernelTypeConfusionObject->Callback = &TypeConfusionObjectCallback;
        Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject);
#else
        DbgPrint("[+] Triggering Type Confusion\n");

        //
        // Vulnerability Note: This is a vanilla Type Confusion vulnerability due to improper
        // use of the 'UNION' construct. The developer has not set the 'Callback' member of
        // the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer of
        // 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as
        // parameter
        //

        Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject);
#endif

        DbgPrint("[+] Freeing KernelTypeConfusionObject Object\n");
        DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
        DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject);

        //
        // Free the allocated Pool chunk
        //
		
        ExFreePoolWithTag((PVOID)KernelTypeConfusionObject, (ULONG)POOL_TAG);
        KernelTypeConfusionObject = NULL;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }

    return Status;
}
明显的,可以看到在漏洞函数中,不安全的版本中不恰当地使用了内核结构体联合体,未重新初始化联合体中的callback成员,导致直接默认使用ObjectType的值,当,ObjectType指向恶意代码,则被利用。
typedef struct _KERNEL_TYPE_CONFUSION_OBJECT
{
    ULONG_PTR ObjectID;
    union
    {
    	ULONG_PTR ObjectType;
    	FunctionPointer Callback;
    };
} KERNEL_TYPE_CONFUSION_OBJECT, *PKERNEL_TYPE_CONFUSION_OBJECT;

0x02 漏洞利用

Ring3 用户结构体成员objectType赋值为payload地址。

typedef struct _USER_TYPE_CONFUSION_OBJECT {
	ULONG_PTR objectID;  //对象ID
	ULONG_PTR objectType;//对象类型   赋值为payload地址
} USER_TYPE_CONFUSION_OBJECT, *PUSER_TYPE_CONFUSION_OBJECT;
DeviceIoControl进入驱动
DeviceIoControl(hFile,
                        HACKSYS_EVD_IOCTL_TYPE_CONFUSION,
                        (LPVOID)UserTypeConfusionObject,
                        sizeof(USER_TYPE_CONFUSION_OBJECT),
                        NULL,
                        0,
                        &BytesReturned,
                        NULL);

上面构造的结构体传入驱动程序,驱动程序用申请的_KERNEL_TYPE_CONFUSION_OBJECT结构内存进行接收。

而在处理callback成员时,不进行初始化,当内核中调用callback函数时,则内核执行利用代码。

NTSTATUS
TypeConfusionObjectInitializer(
    _In_ PKERNEL_TYPE_CONFUSION_OBJECT KernelTypeConfusionObject
)
{
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();

    DbgPrint("[+] KernelTypeConfusionObject->Callback: 0x%p\n", KernelTypeConfusionObject->Callback);
    DbgPrint("[+] Calling Callback\n");

    KernelTypeConfusionObject->Callback();

    DbgPrint("[+] Kernel Type Confusion Object Initialized\n");

    return Status;
}
具体利用代码可参考这里,利用结果如下:

0x03 漏洞反思

安全版本中,提到了及时初始化回调函数成员的方法。

        KernelTypeConfusionObject->Callback = &TypeConfusionObjectCallback;
        Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject);
题外话:最近学习中,刚好看到一个类型混淆的利用,在18-8174中,Vbs脚本里通过精心构造内存,将0x08 BSTR混淆为0x200C array类型实现内存任意读写,感兴趣的童鞋可以研究下。

0x04 后记

基础部分先到这里啦,后面有新的成果,还会接着分享。继续前进,冲冲冲






[招聘]欢迎市场人员加入看雪学院团队!

最后于 5天前 被Saturn丶编辑 ,原因:
最新回复 (2)
wmslecz 5天前
2
0
大佬这一波操作,作为小白,只能膜拜啊。
Saturn丶 3 5天前
3
0
wmslecz 大佬这一波操作,作为小白,只能膜拜啊。
大佬说笑了,入门入门,轻踩
游客
登录 | 注册 方可回帖
返回