未加星标

【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

字体大小 | |
[网络安全 所属分类 网络安全 | 发布者 店小二05 | 时间 | 作者 红领巾 ] 0人收藏点击收藏
【技术分享】windows PsSetLoadImageNotifyRoutine的0day漏洞 2017-09-13 16:07:07 阅读:485次 点赞(0) 收藏 来源: breakingmalware.com
【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞 作者:anhkgg
【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

译者:anhkgg

预估稿费:190RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


介绍

在研究windows内核过程中,我们关注了一个很感兴趣的内容,就是PsSetLoadImageNotifyRoutine,像他名字一样就是提供模块加载通知的。

事情是这样的,内核中为加载的PE文件注册了一个回调通知之后,可能会收到一个非法的模块名字。

在对这个问题进行挖掘之后,看起来是一个偶然的问题其实是因为windows内核自己的代码错误引起的。

这个缺陷存在于从Windows 2000到最新的Windows 10发布版本的所有版本中。


优点:模块加载通知

如果你是个开发驱动的安全厂商,你需要知道系统什么时候加载了模块。通过Hook来完成,可以….但是可能会有很多安全和实现的缺陷。

微软是这么介绍windows2000的PsSetLoadImageNotifyRoutine的。这个机制会在一个PE文件被加载到虚拟内存中(不管是内核态还是用户态)通知内核中注册过回调的驱动,。

深入背后:

下面这几种情况会调用到会地哦啊通知例程:

加载驱动

启动新进程(进程可执行文件/系统DLL:ntdll.dll(对于Wow64进程会有两种不同的文件))

动态加载PE镜像-导入表,LoadLibrary,LoadLibraryEx,NtMapViewOfSection


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

图1:在ntoskrnl.exe中所有对PsSetLoadImageNotifyRoutine的调用

在调用已注册的通知回调时,内核提供一些参数来正确标志加载的PE镜像。参数可以看下面的回调函数原型定义:

VOID(*PLOAD_IMAGE_NOTIFY_ROUTINE)( _In_opt_PUNICODE_STRINGFullImageName,//Theimagename _In_HANDLEProcessId,//AhandletotheprocessthePEhasbeenloadedto _In_PIMAGE_INFOImageInfo//Informationdescribingtheloadedimage(baseaddress,size,kernel/user-modeimage,etc) );

唯一的出路:

实际上,这是WDK文档化的唯一用于监视PE加载到内存的的方法。

另外一种微软推荐的方式,是使用文件系统mini-filter回调(IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION)。NtCreateSection为了能够区分section object是不是一个加载的可执行镜像的一部分,会检查是否存在SEC_IMAGE标志。然而,文件系统mini-filter不会接收这个标志,因此不能区分section object是不是加载PE镜像创建的。


缺陷:错误的模块参数

唯一标志加载的PE文件的参数是FullImageName。

然而,在前面描述的所有场景中,内核使用的另外一种格式的FullImageName。

第一看的时候,我们注意到获取进程可执行文件全路径和系统DLL的环境变量(没有卷名)时,其他动态加载的用户态PE提供的路径也没有卷名。

更让人担忧的是不仅是路径没有了卷名,有时候路径完全是畸形的,可能指向了一个不同的或者不存在的文件。


RTFM

和所有研究人员/开发人员一样,我们做的第一件事就是去看文档,保证对这个东西理解正确了。

根据MSDN的描述,FullImageName表示文件在磁盘的路径,用来标记可执行文件。没有提到可能存在不合法或者不存在的路径。

文档中提高了路径可能是空:在进程创建期间如果操作系统无法获取镜像的完整路径,这个参数可以为空。也就是说,如果这个参数不是空的,那么内核就会认为这是正确的参数而接收。


甚于拼写错误的文档

仔细阅读文档是,我们注意到另一件事,MSDN中显示的函数原型是错误的。参数Create根据描述完全像是跟这个机制没有关系,在WDK中的函数原型完全没有这个参数。很讽刺的就是,使用MSDN提供的原型会导致栈溢出崩溃。


面纱的下面

nt!PsCallImageNotifyRoutines会调用已注册回调函数的。它仅仅是将它调用者传来的UNICODE_STRING指针作为FullImageName参数传给回调函数。在nt!MiMapViewOfImageSection映射一个image的section时,UNICODE_STRING是section表示的FILE_OBJECT的FileName字段。


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

图2 传给回调的FullImageName实际是FILE_OBJECT的FileName字段

FILE_OBJECT通过SECTION->SEGMENT->CONTROL_AREA来获取。这些都是内部未文档的内核结构体。内存管理器在映射文件到内存中的时候创建了这些结构,只要文件已经映射了,都会在内部使用这些结构。


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

图3 调用nt!PsCallImageNotifyRoutines之前nt!MiMapViewOfImageSection获取FILE_OBJECT

每一个映射的镜像只有一个SEGMENT。意味着同样一个镜像在同一个进程中或者跨进程间同时存在的多个section会使用同一个SEGMENT和CONTROL_AREA。这就解释了为什么FullImagename在同一个PE文件同时加载到不同进程可以作为PE文件的标志了。


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

图4 文件映射内部结构(简化版)


继续RTFM

为了弄明白FileName是如何设置和管理的,我们回到文档中,发现MSDN禁止使用它。因为这个值只在初始化进程的IRP_MJ_CREATE请求时是有效的,在文件系统开始处理IRP_MJ_CREATE请求时不考虑是有效的值,但是在文件系统处理完IPR_MJ_CREATE之后FILE_OBJECT确实在使用它。

很明显,NTFS驱动拥有这个UNICODE_STRING(FILE_OBJECT.FileName)的所有权

使用内核调试器调试中,我们发现ntfs!NtfsUpdateCcbsForLcbMove 是负责重命名的一个操作。在看这个函数时我们推断出在IRP_MJ_CREATE请求中文件系统驱动只是创建了一个FILE_OBJECT.FileName的浅拷贝,然后单独维护它。这也就意味着只是拷贝了buffer的地址,而没有拷贝内容。


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞

图5 ntfs!NtfsUpdateCcbsForLcbMove更新文件名字值


刨根问底

如果新路径长度没有超过MaximumLength,共享的buffer内容会被覆盖,FILE_OBJECT.FileName的Legnth字段不会更新,内核可以拿到这个值给回调函数,如果新路径长度超过了MaximunLength,会分配一块新内存,然后回调函数就会拿到过去的值。

尽管我们已经找到了这个bug的原因,但是还是有些事没有弄清楚。比如为什么在image所有句柄(SECTION和FILE_OBJECT中的)关闭之后我们依然可以看到这些畸形的路径。如果文件所有的句柄真的关了,下次这个PE镜像会被打开加载到一个新的FILE_OBJECT中,会创建没有引用的新的路径。

然而,FullImageName依然只想这个老的UNICODE_STRING。这表示句柄计数为0了FILE_OBJECT并没有关闭,意味着引用计数肯定是高于0的。我们也通过调试器确认了这个事情。


最后

内核中引用计数泄露基本是不可能了,我们只有把疑惑指向了:缓存管理器。这可能是一种缓存行为,文件系统驱动维护文件名,但缺引起可能拿到非法的文件名的严重错误。


影响

此时,我们确实已经弄清楚了引起这个问题的原因,但是我们疑惑的是这个bug为什么还存在?有没有什么好的解决方案?

下我们下一篇文章中,我们会努力找到这些问题的答案。


注意

我们大部分分析都在Windows 7 SP1 X86中,系统打了全补丁。这些发现在Windows XP Sp3,Windows 7 SP1 X64, Windows 10 (Redstone)X86/X64(全补丁)系统版本中也验证了。


【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞
【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞 本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://breakingmalware.com/documentation/windows-pssetloadimagenotifyroutine-callbacks-good-bad-unclear-part-1/

本文网络安全相关术语:网络安全工程师 网络信息安全 网络安全技术 网络安全知识

主题: WindowsSDN安全厂商360TIGM载通CTI微软UT
分页:12
转载请注明
本文标题:【技术分享】Windows PsSetLoadImageNotifyRoutine的0day漏洞
本站链接:http://www.codesec.net/view/564025.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 网络安全 | 评论(0) | 阅读(70)