标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2020-2763]   作者: 闲云野鸡 发表于: [2020-10-15]

本文共 [42] 位读者顶过

前言

驱动程序就是一个.sys模块,也有少见的dll,这种程序都运行在内核层[出自:jiwo.org]
内核层有着非常高的权限, 可以得到很多信息, 也可以修改很多信息. 但是在内核层中无法创建界面, 无法便捷地输出信息. 因此, 这就需要携手用户层的程序来功能完成信息的获取与修改, 信息的展示.
内核层驱动主要负责在内核中获取信息, 而用户层程序负责发出指令, 让内核层获取/修改特定数据, 并将内核层驱动程序执行结果显示到界面.
但是用户层程序是不能直接调用内核成的代码的. Windows给开发者预留了一个接口: 符号链接与CreateFile

在内核中, 驱动对象可以创建设备对象, 而设备对象是可以别命名的, 设备对象也可以创建符号链接. 而符号链接又可以在用户层中通过CreateFile打开, 这样一来, 用户层通过和内核层就可以连接起来,用户层调用DeviceIoControl后就能将要处理的数据交给驱动处理

当然,不是所有驱动都使用符号链接和用户层进行通信,有很多驱动不是以这种方式和用户进行数据交换,本文讨论的驱动攻击面仅针对与符号链接形式进行用户通信为前提

挖掘方式和目标对象选取

由于我是在windwows平台上选取的驱动,所以挖掘方式一般通过逆向,后面我会介绍一些我逆向总结的一些经验,关于fuzz工具,我在这里推荐一个驱动FUZZ工具:https://github.com/k0keoyo/kDriver-Fuzzer,我一般通过此工具来遍历符号链接,也有时对单个IOCTL进行FUZZ

目标对象选取:杀毒软件,声卡驱动,显卡驱动,网卡驱动,电脑优化软件,虚拟光驱,监控软件,强加密软件或其他所有管理硬件资源的软件,当然,在和硬件有关的驱动里有相当大部分启动与否依赖于硬件,没有该硬件无法安装驱动

开始搞事情

当我将确定好目标然后把软件下载下来之后,运行软件,查看软件是否有驱动,我将通过火绒剑或者PCHunter或者PowerTool等工具来定位驱动

在某些少数情况下,软件运行后,软件目录下存在驱动,但是驱动没有加载,原因可能因为目标软件的功能没有运行因此驱动也未加载,您可以对软件目标功能进行测试进而让驱动启动

当我确定好目标有哪些驱动后,我将提取目标驱动提取到IDA中进行分析,寻找驱动的符号链接,确定用户层是否有机会对该驱动进行通信,进而寻找漏洞 下面我将介绍一些我平时寻找符号链接的方式

寻找 IoCreateSymbolicLink函数

下图为对此函数按下X交叉引用
在这里插入图片描述

当我完成这步操作后,不同的驱动会有两种情况出现:

1: 符号链接名保存在变量里直接显示

2:符号链接名保存在变量里并被加密,仅使用ida静态分析看不出所以然来,我将通过windbg恢复快照重新安装软件并对IoCreateSymbolicLink打下断点,当驱动运行后,断点应该命中,再使用kd命令查看参数并显示,它将显示字符串,这意味着我找到了符号链接

前面说过,符号链接又可以在用户层中通过CreateFile打开,当通过CreateFile打开符号链接后,用户从就能通过DeviceIoControl向驱动传输数据进行通讯,因此还有一种方式定位符号链接,在用户程序里可以通过追踪DeviceIoControl,在DeviceIoControl中,第一个参数代表着驱动句柄,该句柄通过CreateFile打开,在CreateFile中,它的第一个参数代表着符号链接名,因此一样可以通过ida静态追踪函数引用和windbg对DeviceIoControl打下断点的办法定位符号链接

当我得到驱动对应的符号链接后,我将使用kDriver-Fuzzer -s功能来遍历当前电脑所有可用的符号链接,并打开保存结果的文件,在文件内搜索得到的符号链接名得到它在文件中的位置,Validate Driver后面紧跟着即符号链接名,然后查看后面是否有But no privilege,check if Administrator, or try another Driver字样,如果有,则代表该符号链接需要超级管理员权限才能够通信,很遗憾,这时候我会选择换个目标,因为我的最后的目标是提权,反之如果该符号链接不需要超级管理员权限就可以通信,我会继续往后分析

简单介绍下WDM驱动和用用户层通信的三种缓冲区传递方式
从用户层传递下来的参数保存在IRP结构和IO_STACK_COMPLATE结构中. 其中, 用户输入/输出缓冲区保存在IRP结构中, IRP结构保存有三种缓冲区.

这三种缓冲区分别是:
        irp->UserBuffer- 这是默认的缓冲区,该缓冲区是用户空间的内存, 在内核层中使用用户空间是很危险的,在这种方式下可以传递任意地址的数据当作缓冲区,即使是无效的内存,比如0或0xffffffff,
        irp->AssociatedIrp.SystemBuffer- 在创建设备对象之后,将设备对象的Flags字段加上DO_BUFFERED_IO标志就会使用这种方式, 使用这种方式时, 系统会将用户空间的数据拷贝一份到内核空间. 在这种方式下只能传递用户态地址,比如在32位下,只能传递0x8000000以下的地址,并且该地址内存还要有效
        irp->MdlAddress -- 在创建设备对象之后, 将设备对象的Flags字段加上DO_DIRECT_IO标志就会使用这种方式. 使用这种方式的优点是被读写的空间仍然是用户领空的, 只不过被内存描述符重新锁定了, 这样做比第一种安全且高效,想要获取缓冲区, 就需要调用函数:MmGetSystemAddressForMdlSafe,在这种方式下只能传递用户态地址,比如在32位下,只能传递0x8000000以下的地址,并且该地址内存还要有效
        无论传递的是哪种方式, 在内核层中都可以通过irp->AssociatedIrp.SystemBuffer来获取到输入缓冲区.

确定缓冲区类型需要找到驱动的IOCTL处理函数,因为不同的IOCTL代表着不同的缓冲区处理方式,而寻找IOCTL我都会使用IofCompleteRequest交叉引用跟踪函数调用,因为IOCTL处理函数最后都会调用IofCompleteRequest,该函数功能则是代表驱动处理一个请求完毕

驱动的IOCTL处理函数特征比较简单,如下图所示,根据不同的IOCTL调用不同的处理方式

如果驱动大小比较小,可以直接从入口函数找到IOCTL处理函数

当我找到IOCTL处理函数后,我会使用IDA插件https://github.com/FSecureLABS/win_driver_plugin
来确定IOCTL处理数据缓冲区的类型
Ctrl + Alt + D =>解码当前选择整数

可以看见当前处理缓冲区类型为METHOD_NEITHR,在我所碰过的驱动中,绝大多数都是用METHOD_BUFFERED方式来处理缓冲区内容

如果您的windbg版本在1703以上,也可以使用!ioctldecode命令来解释IOCTL
在这里插入图片描述

当我确定好IOCTL类型和处理函数位置后,我将进行逆向分析处理过程,在这里4处内容引起了我的兴趣,它们分别是InBuff,InBuffLen,OutBuff,OutBuffLen,我在平时逆向中,也是逆向驱动处理这部分数据的流程和逻辑。
在这里插入图片描述在驱动中每一个IOCTL对应着一个处理过程,分析尽量把每个IOCTL分析完,因为每个IOCTL都可能出现漏洞,如下图所示。

在我挖过所有的驱动漏洞当中,大部分漏洞都是本地拒绝服务漏洞,而产生原因则是因为空指针引用,即访问0地址内存,如下图所示,该代码IOCTL为12344,在没有判断输入缓冲区是否为0的情况下直接获取输入缓冲区到v18,接着直接取V18地址

如果编写代码如下图所示

DeviceIoControl(g_hDriver, 12344, 0, 0, 0, 0, &dw, NULL); 

用户层调用DeviceIoControl之后 驱动会执行对IOCTL12344处理的地方,这里也是非常有意思,也是我无意间实验到的,我没有传递给任何数据交给驱动处理,仅仅是打开驱动设备,传递给了IOCLT参数然后调用DeviceIoControl,因为我没有传递数据输入缓冲区,所以在执行v18 = v3->AssociatedIrp.MasterIrp后,v18为0,然后在*(_DWORD *)&v18->Type = dword_16030执行后,引发bsod
在这里插入图片描述

在有部分驱动中,虽然符号链接不需要超级管理员权限便可以通信,但是驱动在处理IOCTL时仅针对保护的进程通信,所以我们在逆向的过程中要先写个程序看看在处理IOCTL时能否成功断下,不然到时候分析完了,写程序断不下来就得不偿失了

最后我再分享一些ida看的数据和对应用户中传递给的参数对应关系 如下图所示
在这里插入图片描述

我是一个接触二进制漏洞不久的菜鸡,此文意在总结爬坑经验和挖掘漏洞过程,如有错误,请多多斧正。

评论

暂无
发表评论
 返回顶部 
热度(42)
 关注微信