关于此次condrv.sys拒绝服务漏洞分析
2021-01-22 12:51:05 Author: www.secpulse.com(查看原文) 阅读量:258 收藏

针对本次浏览器输入\\.\globalroot\device\condrv\kernelconnect导致主机拒绝服务的情况,查明原因是由于condrv驱动的疏忽,在IRP_MJ_CREATE中判断调用源并拒绝后没有对IRP进行正常的完成请求流程操作。导致调用者仍然获得到condrv的设备对象,随后关闭该对象的时候进入IRP_MJ_CLEANUP分发函数,尝试释放资源,但在创建的时候由于被拒绝所以没有分配任何资源,导致释放资源时访问空指针最后系统BSOD

定位到IRP_MJ_CREATE分发函数CdpDispatchCreate

image.png 

可以看到将我们访问的目录遍历查找CdpObjecetCreationTable表,类似的目录有很多,出现漏洞的目录为KernelConnect

image.png 

由此看出KernelConnect对应的IRP_MJ_CREATE分发函数为CdCreateKernelConnection

image.png 

Follow CdCreateKernelConnection~

image.png 

发现有判断IRP的请求模式,如果请求来自应用层返回STATUS_ACCESS_DENIED,看似逻辑正确。

但是有没有发现漏了什么,,,

没错,漏了IoCompleteRequest来完成IRP并且没有设置IoStatus,返回到上方的CdpDispatchCreate也并没有进行完成IRP。就这样一个请求被传回了调用者,而IoStatus.Status字段没有填充,或许初始为0STATUS_SUCCESS),这可能导致允许了这次请求。而触发这次漏洞的原因是由于调用者因此次请求而成功拿到了此文件对象,但是此时condrv没有对这个文件对象中的资源进行任何的初始化。

随后使用对象完毕后关闭该对象并且回收的时候出现了以下两行代码,FsContext没有进行初始化,是一个悬空指针随后悲剧上演。

image.png 

Chrome访问\\.\globalroot\device\condrv\kernelconnect时的调用堆栈

触发此漏洞的R3函数为GetFileAttributeExWR0函数为CdpDispatchCleanup

image.png 

其实无论任何程序,尝试使用以下代码都可以造成BSOD

image.png 

image.png 

随后自写相同逻辑的驱动证明此问题确实会导致Cleanup的请求被发起

image.png

测试驱动代码:

#include <ntddk.h>
 
VOID DriverUnload(PDRIVER_OBJECT DrvObj);
VOID InitIrp(PDRIVER_OBJECT DrvObj);
NTSTATUS InitMainDevObj(PDEVICE_OBJECT* OutDevObj, PDRIVER_OBJECT DrvObj, PUNICODE_STRING DevName);
 
NTSTATUS IrpDisphDefault(PDEVICE_OBJECT DevObj, PIRP Irp);
NTSTATUS IrpDisphCleanup(PDEVICE_OBJECT DevObj, PIRP Irp);
NTSTATUS IrpDisphCreate(PDEVICE_OBJECT DevObj, PIRP Irp);
NTSTATUS IrpDisphClose(PDEVICE_OBJECT DevObj, PIRP Irp);
 
NTSTATUS DriverEntry(PDRIVER_OBJECT DrvObj, PUNICODE_STRING RegPath)
{
    DECLARE_CONST_UNICODE_STRING(DevName, L"\\Device\\FileAttributesTest");
    DrvObj->DriverUnload = DriverUnload;
    KdPrint(("函数 %ws 执行\n", __FUNCTIONW__));
    InitIrp(DrvObj);
    InitMainDevObj(NULL, DrvObj, (PUNICODE_STRING)&DevName);
    return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT DrvObj)
{
    PDEVICE_OBJECT pDeviceNode = DrvObj->DeviceObject;
    PDEVICE_OBJECT pDeleteNode ;
    while (pDeviceNode)
    {
        pDeleteNode = pDeviceNode->NextDevice;
        IoDeleteDevice(pDeviceNode);
        pDeviceNode = pDeleteNode;
    }
}
NTSTATUS InitMainDevObj(PDEVICE_OBJECT* OutDevObj, PDRIVER_OBJECT DrvObj, PUNICODE_STRING DevName)
{
    PDEVICE_OBJECT CreatedDevice;
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    Status = IoCreateDevice(DrvObj, 0, DevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &CreatedDevice);
    if (!NT_SUCCESS(Status))
        return Status;

    CreatedDevice->Flags |= DO_BUFFERED_IO;
    CreatedDevice->Flags &= ~DO_DEVICE_INITIALIZING;
    if(OutDevObj)
        *OutDevObj = CreatedDevice;

    return STATUS_SUCCESS;
}
VOID InitIrp(PDRIVER_OBJECT DrvObj)
{
    for (DWORD32 dwMajorIndex = 0; dwMajorIndex <= IRP_MJ_MAXIMUM_FUNCTION; ++dwMajorIndex)
        DrvObj->MajorFunction[dwMajorIndex] = IrpDisphDefault;
 
    DrvObj->MajorFunction[IRP_MJ_CREATE] = IrpDisphCreate;
    DrvObj->MajorFunction[IRP_MJ_CLEANUP] = IrpDisphCleanup;
    DrvObj->MajorFunction[IRP_MJ_CLOSE] = IrpDisphClose;
}
NTSTATUS IrpDisphDefault(PDEVICE_OBJECT DevObj, PIRP Irp)
{
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
    return STATUS_INVALID_DEVICE_REQUEST;
}
 
NTSTATUS IrpDisphCleanup(PDEVICE_OBJECT DevObj, PIRP Irp)
{
    KdPrint(("函数 %ws 执行\n", __FUNCTIONW__));
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    return STATUS_SUCCESS;
}
NTSTATUS IrpDisphCreate(PDEVICE_OBJECT DevObj, PIRP Irp)
{
    if (Irp->RequestorMode)
    {
        KdPrint(("函数 %ws 执行\n", __FUNCTIONW__));//此处遗漏
        //Irp->IoStatus.Information = 0;
        //Irp->IoStatus.Status = STATUS_ACCES·S_DENIED;
        return STATUS_ACCESS_DENIED;
    }

    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    return STATUS_SUCCESS;
}
NTSTATUS IrpDisphClose(PDEVICE_OBJECT DevObj, PIRP Irp)
{
    KdPrint(("函数 %ws 执行\n", __FUNCTIONW__));
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    return STATUS_SUCCESS;
}

本文作者:玄道

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/151714.html


文章来源: https://www.secpulse.com/archives/151714.html
如有侵权请联系:admin#unsafe.sh