[原创]MS17 您所在的位置:网站首页 怎么用永恒之蓝攻击敌人 [原创]MS17

[原创]MS17

2023-12-14 08:27| 来源: 网络整理| 查看: 265

MS17-010漏洞分析一、漏洞信息1. 漏洞简述 漏洞名称:“永恒之蓝”漏洞 漏洞编号:MS17-010,CVE-2017-0143/0144/0145/0146/0147/0148 漏洞类型:缓冲区溢出漏洞 漏洞影响:信息泄露 CVSS评分:9.3(High) 利用难度:Medium 基础权限:不需要 2. 组件概述

SMB(Server Message Block)是一个协议名,它能被用于Web连接和客户端与服务器之间的信息沟通。其目的是将DOS操作系统中的本地文件接口“中断13”改造为网络文件系统。

 

SMB1.0协议由于在文件共享传输过程中存在的传输效率低以及传输空间小等缺陷被人们所摒弃。为了更好的实现网络中文件的共享过程,在SMB1.0的基础上开发了新的网络文件传输协议,并将其命名为SMB2.0。该协议在实现了文件共享传输的基本功能的基础上对文件传输的效率、文件缓存的空间以及文件并发传输等问题进行改进,使得在局域网或更高配置的网络环境下,文件传输过程的速度和效率等得到了很大的提升。

4. 漏洞影响

Windows Vista SP2; Windows Server 2008 SP2 and R2 SP1; Windows 7 SP1; Windows 8.1; Windows Server 2012 Gold and R2; Windows RT 8.1; and Windows 10 Gold, 1511, and 1607; and Windows Server 2016

 

以上系统打开445号端口都容易受到影响。

5. 解决方案 禁用 SMBv1

对于客户端操作系统:

打开“控制面板”,单击“程序”,然后单击“打开或关闭 Windows 功能”。 在 Windows 功能窗口中,清除SMB1.0/CIFS 文件共享支持复选框,然后单击确定关闭窗口。 重新启动系统。

对于服务器操作系统:

打开服务器管理器,然后单击管理菜单并选择删除角色和功能。 在功能窗口中,清除SMB1.0/CIFS 文件共享支持复选框,然后单击确定关闭窗口。

重新启动系统。

更新Windows系统补丁

官方文档链接

二、漏洞复现1. 环境搭建

实验中需要用到三个机器,分别是调试机,靶机(被调试机),攻击机

调试机环境:主机Windows 10x64专业版 1909 靶机(被调试机)环境:Windows 7x86 SP1 靶机(被调试机)配置:192.168.44.132:445 攻击机环境:Windows XPx86 SP3 攻击机配置:192.168.44.152 1. 双机内核调试

首先需要用调试机调试靶机,具体实现双机调试请看这里。

2. 安装并配置fuzzbunch

另外需要在攻击机安装fuzzbunch实现永恒之蓝漏洞:

安装Python 2.6

安装PyWin32需要以管理员权限进行安装

下载fuzzbunch

在shadowbroker-master的子目录windows中新建listeningposts文件夹,同时修改FuzzyBunch.xml文件内容,设置相应的ResourcesDir和LogDir参数值,修改结果如下图所示。(路径根据实际情况而定)

3. 靶机环境配置

打开靶机445端口,具体打开方法点这里

关闭防火墙:控制面板-系统和安全-Windows防火墙-打开或关闭Windows防火墙-全部选择关闭防火墙。

2. 复现过程

在攻击机中启动命令行,进入fuzzbench的Windows文件夹,用python启动fuzzbench:

 

 

启动后设置靶机IP-设置击机IP-重定向no-log地址确认(无误直接回车)-0+回车(创建新的项目)-为项目命名-设置路径(Yes)-:

 

 

使用永恒之蓝建立后门:

1use Eternalblue

之后一直回车到出现设置靶机系统版本,本次复现靶机为Win7,所以选择1:

 

 

 

下一项模式选择1,FB模式:

 

 

接下来一直回车即可,即可看到插件运行,并成功利用永恒之蓝漏洞在靶机系统中留下后门:

 

三、漏洞分析1. 基本信息 漏洞文件:srv.sys 漏洞函数:srv!SrvOs2FeaListToNt 漏洞对象:为NtFeaList分配的缓冲区 2. 背景知识1. SrvOs2FeaListToNt()函数

SrvOs2FeaListToNt()函数用于将FEA list转化为NTFEA list,需要分配在内核地址大非分页池分配缓冲区来存放转化后的NTFEA list,因此需要先计算转化后的NTFEA list的大小,计算大小是通过srv!SrvOs2FeaListSizeToNt()函数进行的,这个函数被SrvOs2FeaListToNt()调用。

2. 0xffdff000系统预留地址空间

0xffdff000处地址是系统预留的地址空间,用于存放时钟,版本,配置等信息,其分配的权限为可执行:

12345kd> !pte 0xffdff000                    VA ffdff000PDE at C0603FF0            PTE at C07FEFF8contains 000000000018A063  contains 00000000001E3163pfn 18a       ---DA--KWEV  pfn 1e3       -G-DA--KWEV 3. 详细分析1. 静态分析1. Ida分析

使用Ida打开srv.sys

 

首先按shift + F1,再按insert键导入两个结构:

12345struct _FEA{BYTE fEA;   //标记位BYTE cbNAME;  //记录名称长度USHORT cbValue;  //记录值的长度}FEA; 1234struct _FEALIST{ULONG cbList;  //记录Fea List总长度_FEA list[1];}FEALIST, *PFEALIST;

查看srv!SrvOs2FeaListSizeToNt()函数源码,右键a1,使用_FEALIST结构覆盖:

123456789101112131415161718192021222324252627282930int __stdcall SrvOs2FeaListSizeToNt(_FEALIST *FeaList){  _FEALIST *v1; // eax  char *v2; // edi  _FEA *v3; // esi  int v4; // ebx  int v6; // [esp+Ch] [ebp-4h]   v1 = FeaList;                                 // a1  v6 = 0;                                       // NtFeaList的大小  v2 = (char *)FeaList + FeaList->cbList;       // 获取指向表结尾的指针v2  v3 = FeaList->list;                           // 指向表的开始  if ( FeaList->list < (_FEA *)v2 )             // 表的开始指针应该在结尾指针之前  {    while ( &v3[1] < (_FEA *)v2 )               // 从FeaList表的第一个元素开始,遍历整个表    {      v4 = v3->cbValue + v3->cbNAME;            // 获取当前FEA的长度      if ( &v3[1].cbNAME + v4 > (BYTE *)v2 )    // 检查下一个FEA是否有效        break;      if ( RtlSizeTAdd(v6, (v4 + 12) & 0xFFFFFFFC, &v6) < 0 )// 增加NtFeaList的大小,每次12字节        return 0;      v3 = (_FEA *)((char *)v3 + v4 + 5);       // 下一个FEA,加5意思是每个FEA后面有5字节的NULL      if ( v3 >= (_FEA *)v2 )        return v6;      v1 = FeaList;                             // 重置v1    }    LOWORD(v1->cbList) = (_WORD)v3 - (_WORD)v1;  //此处发生计算错误  }  return v6;}

LOWORD(v1->cbList) = (_WORD)v3 - (_WORD)v1; 这句代码中存在一处错误,cbList长度本为4字节,这里却被强制转换为2字节,导致赋值过程中无视高2字节的内容,只赋值了低2字节的内容。

2. 补丁Diff

原来的SrvOs2FeaListSizeToNt()函数中的C代码:

1LOWORD(v1->cbList) = (_WORD)v3 - (_WORD)v1;

修补后:

1*(DWORD*)(v1->cbList) = v3 - (_DWORD)v1;

(v1->cbList)数据类型由WORD变为了DWORD

2. 动态分析

将Windbg(需要配置好符号文件)连接靶机进行内核调试,连接成功Windbg会显示:

 

 

运行前先设置几个断点来采集运行过程中涉及的关键数据:

12345678910bp srv!SrvSmbOpen2+0x79 ".printf \"feasize: %p indatasize: %p fealist addr: %p\\n\",edx,ecx,eax;g;"// 获取Fea大小和indata大小bp srv!SrvOs2FeaListToNt+0x10 ".printf \"feasize before: %p\\n\",poi(edi);r $t0 = @edi;g;"bp srv!SrvOs2FeaListToNt+0x15 ".printf \"NTFEA size: %p feasize after: %p\\n\",eax,poi(@$t0);g;"// FEA List大小的前后变化,以及NTFEA List大小bp srv!SrvOs2FeaListToNt+0x99 ".printf \"NEXT: FEA: %p NTFEA: %p\\n\",esi,eax;g;"bp srv!SrvOs2FeaToNt+04d ".printf \"MOV2: dst: %p src: %p size: %p\\n\",ebx,eax,poi(esp+8);g;"// 查看被分配的池bp srv!SrvOs2FeaListToNt+0xd5// 查看服务器返回的值

设置好断点后,在攻击机运行脚本,开始攻击

 

这时,Windbg会记录下攻击过程中的数据:

 

 

整理一下:

123456feasize: 00010000indatasize: 000103d0fealist addr: a1f050d8feasize before: 00010000NTFEA size: 00010fe8feasize after: 0001ff5d

可以看到经过某处指令后feasize由00010000变为0001ff5d,这就是代码LOWORD(v1->cbList) = (_WORD)v3 - (_WORD)v1;产生的错误计算,其原因请看下面对应的汇编指令:

 

此时esi和eax寄存器的值:

 

FeaEnd: esi = a4217035h

 

FeaStart: eax = a42070d8h

 

FeaSize: [eax] = 00010000

12sub esi, eax  mov word ptr[eax], si

经过sub指令后esi的值为ff5d,而在给[eax]赋值的时候使用WORD类型,导致了eax内容变成了0001ff5d。

 

继续查看内存池的数据:

1234567891011121314151617NEXT: FEA: a1f050dc NTFEA: 85da4008MOV2: dst: 85da4011 src: a1f050e1 size: 00000000NEXT: FEA: a1f050e1 NTFEA: 85da4014MOV2: dst: 85da401d src: a1f050e6 size: 00000000 ......NEXT: FEA: a1f05ca3 NTFEA: 85da5c4cMOV2: dst: 85da5c55 src: a1f05ca8 size: 00000000NEXT: FEA: a1f05ca8 NTFEA: 85da5c58MOV2: dst: 85da5c61 src: a1f05cad size: 00000000NEXT: FEA: a1f05cad NTFEA: 85da5c64MOV2: dst: 85da5c6d src: a1f05cb2 size: 0000f383NEXT: FEA: a1f15035 NTFEA: 85db4ff0MOV2: dst: 85db4ff9 src: a1f1503a size: 000000a8 srv!SrvOs2FeaListToNt+0xd5:8949263a be0d0000c0      mov     esi,0C000000Dh

分配的起始地址为85da4008,正常分配的结束地址为85da4008h + 00010fe8h = 85db4ff0h,到了Windbg中显示的最后一块池时,发生了错误,并返回STATUS_INVALID_PARAMETER(0xC000000D),查看85db4ff0h中的内容后发现这片地址属于srvnet.sys分配的池。而这个池中存在一个很关键的数据,这个数据是一个地址,当靶机系统再接受数据的时候会将数据复制到这个地址+0x80的地方。

 

这个关键的地址位于_MDL结构中的MappedSystemVa成员,这个结构在srvnet池分配开始的地址+3c,我们在Windbg中找到这个结构:

12345678910kd> dt 85db503C _MDLnt!_MDL   +0x000 Next             : 0xffffffff _MDL   +0x004 Size             : 0n96   +0x006 MdlFlags         : 0n4100   +0x008 Process          : (null)    +0x00c MappedSystemVa   : 0xffdfef80 Void   +0x010 StartVa          : (null)    +0x014 ByteCount        : 0xffd00010   +0x018 ByteOffset       : 0xffffffff

可以看到此时的这个结构的MappedSystemVa成员已经被覆盖为0xffdfef80,当靶机再次接受数据时,会向0xffdf80+0x80也就是在刚才介绍中提到的系统预留的一片可执行空间0xffdff000,此时攻击机获得一次写入shellcode的机会。那么程序是如何执行这部分shellcode的呢?

 

当靶机接受完这部分数据后,还会调用srvnet!SrvNetWskReceiveComplete这个函数,巧了,刚好这个函数会调用到写入的shellcode,就此,成功劫持了靶机的执行流。

 

查看0xffdff000地址空间内容如图所示:

 

 

0xffdff1f1处为shellcode的开始。

三、缓解措施 关闭445端口 更新补丁 四、参考文献

360 核心安全技术博客:NSA Eternalblue SMB 漏洞分析

 

看雪:MS17-010 SMB 远程命令执行漏洞利用分析

 

CSDN:【漏洞分析】MS17-010:深入分析“永恒之蓝”漏洞

[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2021-9-6 07:54 被Sal_Tay编辑 ,原因: #漏洞分析 #缓冲区溢出 #Windows


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有