POPKORN规模化流行的Windows内核驱动程序

渗透技巧 2年前 (2023) admin
286 0 0

POPKORN_ Popping Windows Kernel Drivers At Scale

CCFB 2022年 ACSAC

贡献

提出了POPKORN的设计和实现,它是一个灵活、轻量级和可扩展的框架,通过结合污点分析和目标符号执行来检测各种Windows驱动程序中的API滥用漏洞。在一个包含212个签名的Windows内核驱动的数据集上评估了POPKORN,并展示了它在自动发现真实内核驱动中的高严重性漏洞方面的有效性。POPKORN总共发现38个独特的bug,经人工验证为可利用。38个可利用的bug中有31个是先前未知的漏洞( 0天),可以导致非法越权。对Windows内核驱动中的一类逻辑错误进行了深入分析。我们关注在利用导致本地权限提升的缺陷时常见的API函数,展示了用于驱动交互的调度接口如何允许用户模式输入在没有适当检查的情况下到达关键接收器。

此项目的的困难点

  1. 无源码与文档,需要逆向分析
  2. 内核API函数建模困难,函数多,无法为每个函数提供一个符号分析模型
  3. 路径爆炸

输入点

设置为DeviceIoControl

污点

POPKORN规模化流行的Windows内核驱动程序

从上述数据中统计得出MmMapIoSpace,ZwOpenProcess,ZwMapViewOfSection三个函数可以被用于提升权限

架构

全框架视图

POPKORN规模化流行的Windows内核驱动程序

污点分析

分析到sink函数的时,目标设备标记为易受攻击设备,然后检查参数,如果参数有直接或间接从用户缓冲区加载,则报警。这些参数可以从用户层控制,所以可以修改 step1: 定义调度处理handler DeviceIoControl 并且记录驱动初始化成功后的一个状态 step2: 找到驱动程序支持的32位整数输入/输出控制段码,通常称为IOCTL码。

把irp结构符号化,

step3: POPKORN符号执行DeviceIoControl处理程序,并集成了漏洞检测引擎,以检测是否达到上述三个污点函数。

我们的系统首先创建与IoControlCode的符号表达式以及输入和输出缓冲区的内容和长度。然后,这些信息被用来创建一个IRP结构符号,与从成功的DriverEntry执行中恢复的DeviceObject一起,被用作DeviceIoControl处理程序的输入参数。

如果达到污点函数后,检查参数,是否读取了用户层传递的参数,如果有,给出一份报告。报告大致内容如下 那些污点函数被触发,用户态进程可以控制的参数,以及用户态程序达到污点函数传递的数据,(IoControlCode,缓冲区长度和内容)

技术细节

项目基于angr,angr本身只有用户层,额外增加了对windows driver的实现,针对angr的simprocedures,需要实现一个windows 内核api的函数符号摘要,文章选择了如下几个符号作为摘要IoCreateDevice,IoCreateSymbolicLink,RtlInitUnicodeString,RtlCopyUnicodeString,ExAllocatePool, ZwOpenSection, and ExAllocatePoolWithTag。simprocedures实现例子

>>> from angr import Project, SimProcedure
>>> project = Project('examples/fauxware/fauxware')

>>> class BugFree(SimProcedure):
...    def run(self, argc, argv):
...        print('Program running with argc=%s and argv=%s' % (argc, argv))
...        return 0

# this assumes we have symbols for the binary
>>> project.hook_symbol('main', BugFree())

# Run a quick execution!
>>> simgr = project.factory.simulation_manager()
>>> simgr.run()  # step until no more active states
Program running with argc=<SAO <BV64 0x0>> and argv=<SAO <BV64 0x7fffffffffeffa0>>
<SimulationManager with 1 deadended>

最后,POPKORN实施了组合措施来对抗路径爆炸。首先,我们跟踪生成状态的数量,当达到10000个符号化状态(在angr中称为SimStates)的阈值时停止执行。此外,我们仅通过对内核函数实现符号摘要而不是模拟其具体实现,将分析范围缩小到驱动函数。因此,不创建无关内核代码中的状态,减少了分析的代码量。

实验数据

POPKORN规模化流行的Windows内核驱动程序

27个驱动产生38个威胁报告,手动验证后假阳性0%,38个全中。假阴性验证时,用popkorn去验证已知漏洞,得到假阴性<33%

真实漏洞分析

文中给出两个漏洞例子的分析 MmMapIoSpace漏洞分析

void *__fastcall mmapiospace_func(void *inbuf){  
 // mapping addr from input buffer 
 base_addr = MmMapIoSpace( 
     *(void**)(inbuf+0), // start addr, 
     *(size_t*)(inbuf+8), // number of bytes 
 MmNonCached); // Caching Behavior 
    
 if (base_addr) 
 { 
  // allocating a memory descriptor list 
  // (MDL) to map virtual buffer 
  mdl_ptr = IoAllocateMdl(base_addr,
                         *(size_t*)(inbuf+8),0,0,0);
  if (mdl_ptr) 
     { 
         // pages are being mapped in UserMode(1) 
         mapped_start_addr = MmMapLockedPages(mdl_ptr, 1); 
         *(void**)outbuf = mapped_start_addr; 
         // freeing allocations 
         IoFreeMdl(mdl_ptr); 
         MmUnmapIoSpace(base_addr, inbuf_size); 
         return SUCCESS; 
     } 
 } 
}

4-7行是将物理地址映射到一个虚拟空间中,后续的IoAllocateMdl等是为了将此内存返回给用户态空间 如果能指定inbuf地址,那么用户态就可以控制物理地址信息,从而达到越权。ZwOpenSection漏洞分析

void *__fastcall zwmapviewofsection_func(void *inbuf) 

    void *SectionHandle; 
    HANDLE *ProcessHandle = *(HANDLE *)&inbuf[0]; 
    SIZE_T CommitSize = *(size_t*)inbuf[1]; 
    PVOID BaseAddress = 0
    ULONG_PTR ViewSize = CommitSize; 
    struct _OBJECT_ATTRIBUTES ObjectAttributes; 
    struct _UNICODE_STRING DestinationString; 
    
    RtlInitUnicodeString(&DestinationString, 
                         "\Device\PhysicalMemory"); 
    ObjectAttributes.ObjectName = &DestinationString; 
    
    // Mapping the privileged SectionHandle to "PhysicalMemory" 
    success = ZwOpenSection( &SectionHandle, 
                            DesiredAccess, &ObjectAttributes); 
    if(success){ 
        return ZwMapViewOfSection( SectionHandle, 
                                  ProcessHandle, BaseAddress, 0, CommitSize, 0
                                  ViewSize, ViewShare, 00x40u); 
    } 
}

ZwOpenSection从物理设备打开一个特权区句柄(读/写),然后用ZwMapViewOfSection可以将任意物理地址映射到ProcessHandle进程中

于现有工具对比

对比sdv和dv,sdv是静态检查,dv是动态检查,sdv需要源码,两者都是通过规则集,下断言等方式。聚焦于正确使用windows api. 效果总结就是比dv好

POPKORN规模化流行的Windows内核驱动程序

总结

如果文章所描述的是真实的,那么我们也可以尝试将目标函数与漏洞类型缩小,使用angr写一个window kernel driver模块来执行符号执行。也能出一些成果。或者是使klee,s2e这种其他的符号执行引擎来替换angr


原文始发于微信公众号(EchoSec安全团队):POPKORN规模化流行的Windows内核驱动程序

版权声明:admin 发表于 2023年3月24日 上午10:22。
转载请注明:POPKORN规模化流行的Windows内核驱动程序 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...