论坛首页 漏洞分析研究区 阅读主题

[原创]ms17-010 漏洞分析

427 浏览 4 回复
#1 楼主 2026-06-01 21:09:06
​ 近期重新分析了ms17-010漏洞,想写一个自己的工具,在重新分析的过程中,其实又发现了很多之前没有进行深究的问题,由于很多东西还没有弄明白,先记录一下自己的分析过程以及踩的坑,不由感慨漏洞分析和想要实际利用两者之间的差距确实挺大的。环境:win7 sp1 32bits srv.sys 6.1.7601.17514
srvnet.sys 6.1.7601.17514
nsa 工具集(使用教程)
PS:这两个文件在C:\Windows\System32\drivers下参考资料:748K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6J5k6i4y4W2j5i4u0U0K9q4)9J5k6h3y4Z5k6h3y4C8M7r3!0A6L8Y4c8Q4x3X3g2U0L8$3#2Q4x3V1j5J5x3o6p5%4i4K6u0r3k6i4c8W2M7X3&6S2L8r3u0D9N6h3g2Q4x3X3c8W2N6X3g2J5P5i4c8Z5K9h3&6Y4i4K6u0V1K9$3&6G2N6#2)9J5c8R3`.`.801K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1j5K6L8X3c8s2y4r3#2W2i4K6u0r3b7i4g2@1L8@1u0D9N6h3g2Q4x3X3c8y4f1K6p5%4i4K6u0V1x3o6p5H31c0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6H3j5i4m8W2M7W2)9J5k6i4y4W2k6h3u0#2k6#2)9J5k6h3!0J5k6#2)9J5c8U0t1^5x3q4)9J5c8R3`.`.本文将介绍以下的内容>> 漏洞完整利用流程介绍>> 漏洞溢出部分分析>> 漏洞触发部分的分析>> 漏洞的内存布局的分析​ 该漏洞主要是利用smb1和smb2的协议兼容问题,和windows在处理fealist结构体和ntfeallist结构体过程中大小计算错误导致的数据溢出漏洞。​ 在进行堆喷射过程中,为了实现非页内存的布局,又利用用了一个SMB_COM_SESSION_SETUP_ANDX 计算smbv1和smbv2结构体转化的漏洞,实现了任意大小的非页内存申请,从而间接利用系统的内存管理机制实现内存布局。​ 漏洞触发部分,在内存溢出和堆布局的基础上实现了对srvnet头部结构的覆盖,其中对MDL指针的覆盖,使得后续发送的srvnetbuff内容被保存到了特定可执行的内存地址(0xffdff000)中,于是在释放srvnet链接后,处理函数会执行0xffdff000地址处的shellcode,从而实现漏洞利用。​ 这部分的漏洞分析是大部分文章都有写的,主要成因是由于SrvOs2FeaListSizeToNt函数在进行fealist到ntfeallist的长度计算过程中进行了一个强制类型转换,导致了四个字节的长度只覆盖了低位的两个字节,数据在转换过程中大于申请的内存空间,从而实现溢出。此处就主要介绍一下为什么会出现四个字节转两个字节的情况?SMB协议中,使用一串的命令来代表执行的操作的,当传输的数据过大时,smb通常会有一个子命令进行传输,并用传输过程中的TID,UID,PID,MID来判断是哪一个命令的后续数据。例如,smbv1中的SMB_COM_NT_TRANSACT命令,在传输消息过大时,便会使用SMB_COM_NT_TRANSACT_SECONDARY来完成后续的数据传输。 而在smbv2中SMB_COM_TRANSACTION2 作为SMB_COM_NT_TRANSACT的扩展命令,两者的请求结构体十分相似,功能也差不多,但在计算消息内容长度TotalDataCount时,SMB_COM_TRANSACTION2使用的是USHORT类型(两字节),SMB_COM_NT_TRANSACT使用的是ULONG类型(四字节)。 NSA工具在利用该漏洞时,先传入了一个SMB_COM_NT_TRANSACT命令的头,后续内容利用相同TID, PID, UID, MID的SMB_COM_TRANSACTION2_SECONDARY进行传输的。没加补丁之前,windows仅通过TID, PID, UID, MID来识别命令是否一致,而消息命令的类型是由最后一个传入的命令类型确定的。这样就造成了传入NT_TRANSACT消息,但实际上是运行的却是TRANSACTION2命令的处理流程。 所以,在补丁修复中,除了修复SrvOs2FeaListSizeToNt的类型强转外,还同时在 ExecuteTransaction函数中添加了一个类型比较的判断。 用到的几个结构体的定义如下:trans2接受完数据后会通过dispatchtable调用srv!SrvSmbOpen2函数对接收到的数据进行处理,函数首先会读取接收到的transion数据,然后获取其中fealist结构体的部分,将fealist结构体转成Ntfealist结构体。在SrvOs2FeaListToNt函数中,首先是SrvOs2FeaListSizeToNt对于结构体长度的强转赋值,导致fealist的结构体长度是错误的,所以后续计算最后一个结构体指针的地址也是错误的。在后续循环转化ntfealist的过程中,循环是以fea结构体标志位和与最后一个结构体指针地址比较进行的条件判断,结构体标志位由用户传入,可控,指针地址错误的计算,可控,所以可以精准控制溢出字节。在SrvOs2FeaListSizeToNt函数中,实现了两个功能,一是计算ntfealist结构体的长度并用于申请后续空间,二是对fealist结构的长度进行重新赋值,防止由于该长度被用户输入控制导致错误,在实现第二个功能的时候,由于trans2消息的总长度为两个字节,所以在此处进行了强转导致了最终长度计算出错。MDL是windows内核中一个比较重要的结构,这个结构负责将用户空间中的内存通过MDL机制映射到系统地址空间。将I/O数据写入到指定的MDL指定虚拟地址中,在实际利用中client发送的数据会写入到指定的虚拟地址中,这样就可以传入可控的数据到指定的地址。pSrvNetWskStruct: 指向SrvNetWskStruct结构体,该结构体中存在一个函数指针HandlerFunction,该函数会在srvnet连接中断时进行调用;那么如果pSrvNetWskStruct指向的结构体是伪造的,那么就可以很顺利的触发命令执行。heap中可执行代码的固定地址由于我们知道倒数第二个Fea结构的value部分是f383,之后又拷贝了个a8的长度,所以这里是在value拷贝处下断点下面红线开始的部分为越界拷贝的那个ntfealist结构体,可以看到精准溢出的实际上是一个a8长度的字段: 越界前:越界后:精准覆盖的SRVNET_HEADER部分字段含义如下:其中需要关注的是偏移0x34处的指针,该指针正常情况下最终指向的是srv!SrvReceiveHandler

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-273824.htm
#2 2026-06-01 21:09:06
师傅带带带
#3 2026-06-01 21:09:06
这个漏洞17年想分析的,可惜现在对这些兴趣不大了。
#4 2026-06-01 21:09:06
少有的分析详细文章
#5 2026-06-01 21:09:06
堆块释放和占用情况我分析着和楼主不一样,堆块大小都差不多

请登录后参与讨论

立即登录 注册账号