CVE-2020-16898漏洞复现及分析

 

作者:prowes5@360GearTeam

0x00 漏洞概述

2020年10月13日,微软发布了关于TCP/IP远程代码执行漏洞的通告。漏洞编号危CVE-2020-16898,漏洞等级:严重。漏洞评分:9.8(后更新为8.8)。

这个问题是由于Windows错误的处理了ICMPv6 Router Advertisement包,从而造成了堆栈溢出。攻击者可以构造特定的ICMPv6 Router Advertisement数据包,发送到远程主机,从而达到任意远程代码执行的效果。

 

0x01 漏洞影响版本

Windows 10 Version 1709 for 32-bit Systems

Windows 10 Version 1709 for ARM64-based Systems

Windows 10 Version 1709 for x64-based Systems

Windows 10 Version 1803 for 32-bit Systems

Windows 10 Version 1803 for ARM64-based Systems

Windows 10 Version 1803 for x64-based Systems

Windows 10 Version 1809 for 32-bit Systems

Windows 10 Version 1809 for ARM64-based Systems

Windows 10 Version 1809 for x64-based Systems

Windows 10 Version 1903 for 32-bit Systems

Windows 10 Version 1903 for ARM64-based Systems

Windows 10 Version 1903 for x64-based Systems

Windows 10 Version 1909 for 32-bit Systems

Windows 10 Version 1909 for ARM64-based Systems

Windows 10 Version 1909 for x64-based Systems

Windows 10 Version 2004 for 32-bit Systems

Windows 10 Version 2004 for ARM64-based Systems

Windows 10 Version 2004 for x64-based Systems

Windows Server 2019

Windows Server 2019 (Server Core installation)

Windows Server, version 1903 (Server Core installation)

Windows Server, version 1909 (Server Core installation)

Windows Server, version 2004 (Server Core installation)

 

0x02漏洞复现验证

复现环境:

靶机:

Windows10 1909

攻击机:

系统:Ubuntu 18.04

组件版本:Python3.6.9,scapy2.4.4

网络:攻击机和靶机需在同一内网下且数据包可以到达。

验证结果:

 

0x03 漏洞分析

RDNSS中length字段是以组为单位显示的,默认情况下为奇数。当这个字段为偶数时,会导致tcpip.sys出现解析错误。

rfc5006中定义了RDNSS包的各字段作用、大小和偏移。

 0                   1                   2                   

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|     Type      |     Length    |           Reserved            |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|                           Lifetime                            |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|                                                               |

:            Addresses of IPv6 Recursive DNS Servers            :

|                                                               |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type:

8-bit,RDNSS类型为25

length:

8-bit无符号整数。主要代表option的长度,一组代表8个字节。RDNSS数据包头部为八字节,而IPv6为16字节。即最小为24字节,8字节一组,Length最小为3。如果有多个IPv6地址,则每次Length加2。所以Length默认情况下是奇数。

Reserved:

16-bit,保留字段。

Lifetime:

32-bit无符号整数。RDNSS地址用于解析的最长时间。当为0xffffffff时,表示无穷大。

先看一下正常的数据包,可以看到相关的一些字段信息,且Length为奇数

之后看一下攻击的数据包,这里wireshark会根据Length的长度解析数据包,Length为4会认为第一个Option包为20byte,而IPv6地址为16字节,而\x01\x02\x03\x04\x05\x06\x07\x08只有八个字节,所以会把下一个Option的前八字节认为是IPv6地址的后八字节,也就是这里的102:304:506:708:1926:4242:4242:4242。而Option是根据Length解析的,是从\x19\x26这里开始,所以这里的数据就会被重复解析。

接下来详细分析下漏洞

漏洞点存在于tcpip!Ipv6pHandleRouterAdvertisement,直接在该函数中下断点。

  while ( 1 )

  {

    v27 = *(v9 + 24);

    v192 = 0;

    if ( v27 < 2 )

      break;

    v28 = NdisGetDataBuffer(v9, 2i64, &v192, 1i64, 0);// 获取具体option字段内数据

    v27 = *(v9 + 24);

    length = 8 * v28[1];//实际长度,v28[1]为数据包中的length字段

    if ( length && length <= v27 )              // length bytes<=0x150

    {

      v25 = *v28;

      v30 = 1;

    }

    else

    {

      v30 = 0;

    }

    if ( !v30 )

      break;

    switch ( v25 )                              // type

    {

      case 1u:

        if ( (*(*(v11 + 40) + 36i64) & 0x210) == 16 )

        {

          if ( length != v177 + 2i64 )

          {

            *v7 = 21;

            goto LABEL_276;

          }

          v32 = *(v9 + 16) + 2;

          if ( v32 >= *(*(v9 + 8) + 40i64) )

          {

            NdisAdvanceNetBufferDataStart(v9, 2i64, 0i64, 0i64);

          }

          else

          {

            *(v9 + 40) += 2;

            *(v9 + 24) = v27 - 2;

            *(v9 + 16) = v32;

          }

          length -= 2;

          v21 += 2;

          v190 = NdisGetDataBuffer(v9, length, &v265, 1i64, 0);

        }

        break;

      case 3u:

        memset(&Dst, 0, 0x20ui64);

        if ( length != 32 || *(NdisGetDataBuffer(v9, 32i64, &Dst, 1i64, 0) + 2) > 0x80u )

        {

          *v7 = 23;

          goto LABEL_276;

        }

        break;

      case 5u:

        v206 = 0i64;

        if ( length != 8 )

        {

          *v7 = 22;

          goto LABEL_276;

        }

        v185 = _byteswap_ulong(*(NdisGetDataBuffer(v9, 8i64, &v206, 1i64, 0) + 4));

        break;

      case 0x18u:

        v253 = 0i64;

        v254 = 0i64;

        v255 = 0i64;

        if ( length > 0x18u

          || (v147 = *(NdisGetDataBuffer(v9, length, &v253, 1i64, 0) + 2), v147 > 0x80u)

          || v147 > 0x40u && length < 0x18u

          || v147 && length < 0x10u )

        {

          *v7 = 24;

          goto LABEL_276;

        }

        break;

      case 0x19u:

        if ( *(v11 + 404) & 0x40 && length < 0x18u )// length bytes

          *v7 = 25;

        break;

      default:

        if ( v25 == 0x1F && *(v11 + 404) & 0x40 && length < 0x10u )

        {

          *v7 = 26;

LABEL_276:

          v27 = *(v9 + 24);

          goto LABEL_33;

        }

        break;

    }

    if ( *v7 != 28 )

      goto LABEL_276;

    if ( length )

    {

      v31 = length + *(v9 + 16);

      if ( v31 >= *(*(v9 + 8) + 40i64) )

      {

        NdisAdvanceNetBufferDataStart(v9, length, 0i64, 0i64);

      }

      else

      {

        *(v9 + 40) += length;

        *(v9 + 24) -= length;

        *(v9 + 16) = v31;

      }

    }

    v21 += length;

  }

往下调试可以看到,这里有一个循环来处理数据包。而0x18选项这里是对长度有限制条件的。首先会获取每个option内数据的大小进行验证,读取第一个Option数据,获取Option中的Length字段为\x04,4*8=0x20字节,从Option头相加0x20字节,会直接跳到下一个\x19\x26,从而跳过长度限制。

while ( 1 )

{

  ...

  if ( *v78 == 0x18 )

  {

     v80 = 8 * v78[1];

     v256 = 0i64;

     v257 = 0i64;

     v258 = 0i64;

     v249 = 0i64;

     v250 = 0i64;

     v156 = NdisGetDataBuffer(v72, v79, &v256, 1i64, 0);

     _mm_storeu_si128(&v264, _mm_load_si128(&_xmm));

     v184 = *(&v264 + ((*(v156 + 3) >> 3) & 3));

     if ( v184 != -1 )

     {

        v157 = *(v156 + 2);

        v158 = _byteswap_ulong(*(v156 + 4));

        v159 = 2 * v158;

        if ( (2 * v158) >> 1 != v158 )

           v159 = -1;

        CopyPrefix(&v249, v156 + 8, *(v156 + 2), 16i64);

        v172 = v184;

        LOBYTE(v170) = v157;

        IppUpdateAutoConfiguredRoute(v11, Buf2, v68, &v249, v170);

        v76 = v179;

        if ( v67 <= v159 )

           v159 = v67;

        v67 = v159;

     }

     goto LABEL_115;

   }

   if ( *v78 == 0x19 )

   {

      if ( *(v11 + 404) & 0x40 )          // 可能是系统设置那里

      {

        Ipv6pUpdateRDNSS(v11, v72, Buf2, v199, &v180);

        goto LABEL_310;

      }

    }

...

}

这部分中Ipv6pUpdateRDNSS这个函数是最重要的部分。在这个函数中,会计算具体IPv6的个数,而计算IPv6的个数是通过(Length-1)/2来实现的。

所以会导致错误的指向了之前的数据了,也就是\x01\x02这个部分。

这里补充一下关于相关的一些结构体和函数的一些知识。

关于NdisGetDataBuffer 函数

PVOID NdisGetDataBuffer(

  PNET_BUFFER NetBuffer,

  ULONG       BytesNeeded,

  PVOID       Storage,

  UINT        AlignMultiple,

  UINT        AlignOffset

);

参数:

NetBuffer:

指向NET_BUFFER结构的指针。

BytesNeeded:

请求的数据的连续字节数。

Storage:

[可选]指向缓冲区的指针,如果调用者未提供缓冲区,则为NULL。缓冲区的大小必须大于或等于BytesNeeded中指定的字节数 。如果该值为非NULL,并且请求的数据不连续,则NDIS将请求的数据复制到Storage指示的区域 。

AlignMultiple:

对齐倍数,以2的幂表示。例如2、4、8、16等。如果 AlignMultiple为1,则没有对齐要求。

AlignOffset

与对齐倍数的偏移量(以字节为单位)。

用途:

NdisGetDataBuffer 函数通过 NET_BUFFER ->CurrentMdlOffset 字段来记录要访问数据起始地址相对于_MDL->MappedSystemVa 的偏移。

关于_NET_BUFFER

0: kd> dt ndis!_NET_BUFFER

   +0x000 Next             : Ptr64 _NET_BUFFER

   +0x008 CurrentMdl       : Ptr64 _MDL

   +0x010 CurrentMdlOffset : Uint4B

   +0x018 DataLength       : Uint4B

   +0x018 stDataLength     : Uint8B

   +0x020 MdlChain         : Ptr64 _MDL

   +0x028 DataOffset       : Uint4B

   +0x000 Link             : _SLIST_HEADER

   +0x000 NetBufferHeader  : _NET_BUFFER_HEADER

   +0x030 ChecksumBias     : Uint2B

   +0x032 Reserved         : Uint2B

   +0x038 NdisPoolHandle   : Ptr64 Void

   +0x040 NdisReserved     : [2] Ptr64 Void

   +0x050 ProtocolReserved : [6] Ptr64 Void

   +0x080 MiniportReserved : [4] Ptr64 Void

   +0x0a0 DataPhysicalAddress : _LARGE_INTEGER

   +0x0a8 SharedMemoryInfo : Ptr64 _NET_BUFFER_SHARED_MEMORY

   +0x0a8 ScatterGatherList : Ptr64 _SCATTER_GATHER_LIST

关于_MDL

0: kd> dt ndis!_MDL

   +0x000 Next             : Ptr64 _MDL

   +0x008 Size             : Int2B

   +0x00a MdlFlags         : Int2B

   +0x00c AllocationProcessorNumber : Uint2B

   +0x00e Reserved         : Uint2B

   +0x010 Process          : Ptr64 _EPROCESS

   +0x018 MappedSystemVa   : Ptr64 Void

   +0x020 StartVa          : Ptr64 Void

   +0x028 ByteCount        : Uint4B

   +0x02c ByteOffset       : Uint4B

第一次调用Ipv6pUpdateRDNSS函数之前:

0: kd> dt ndis!_NET_BUFFER @r14

   +0x000 Next             : (null) 

   +0x008 CurrentMdl       : 0xffff9a04`9ae4c350 _MDL

   +0x010 CurrentMdlOffset : 0x10

   +0x018 DataLength       : 0x150

   +0x018 stDataLength     : 0x150

   +0x020 MdlChain         : 0xffff9a04`9c40a180 _MDL

   +0x028 DataOffset       : 0x70

   +0x000 Link             : _SLIST_HEADER

   +0x000 NetBufferHeader  : _NET_BUFFER_HEADER

   +0x030 ChecksumBias     : 0

   +0x032 Reserved         : 0

   +0x038 NdisPoolHandle   : 0xffff9a04`9aba28c0 Void

   +0x040 NdisReserved     : [2] (null) 

   +0x050 ProtocolReserved : [6] 0x00000160`00000000 Void

   +0x080 MiniportReserved : [4] (null) 

   +0x0a0 DataPhysicalAddress : _LARGE_INTEGER 0x0

   +0x0a8 SharedMemoryInfo : (null) 

   +0x0a8 ScatterGatherList : (null) 

0: kd> dt ndis!_MDL 0xffff9a04`9ae4c350

   +0x000 Next             : 0xffff9a04`9ae4c7d0 _MDL

   +0x008 Size             : 0n56

   +0x00a MdlFlags         : 0n4

   +0x00c AllocationProcessorNumber : 0x9a04

   +0x00e Reserved         : 0xffff

   +0x010 Process          : (null) 

   +0x018 MappedSystemVa   : 0xffff9a04`9ae4c390 Void

   +0x020 StartVa          : 0xffff9a04`9ae4c000 Void

   +0x028 ByteCount        : 0x30

   +0x02c ByteOffset       : 0x390

0: kd> db 0xffff9a04`9ae4c390+0x10

ffff9a04`9ae4c3a0  19 04 00 00 ff ff ff ff-5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ

ffff9a04`9ae4c3b0  5a 5a 5a 5a 5a 5a 5a 5a-01 02 03 04 05 06 07 08  ZZZZZZZZ........

ffff9a04`9ae4c3c0  00 d0 09 02 43 63 50 63-9a 74 0e 74 7b 4b cd b6  ....CcPc.t.t{K..

ffff9a04`9ae4c3d0  fe 02 04 00 ff ff 00 00-90 c3 88 a0 04 9a ff ff  ................

ffff9a04`9ae4c3e0  60 09 80 02 00 00 00 00-60 09 c0 02 00 00 00 00  `.......`.......

ffff9a04`9ae4c3f0  60 09 c0 02 00 00 00 00-19 19 f3 02 00 00 00 00  `...............

ffff9a04`9ae4c400  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c410  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

第一次调用Ipv6pUpdateRDNSS函数之后

0: kd> dt ndis!_NET_BUFFER @r14

   +0x000 Next             : (null)

   +0x008 CurrentMdl       : 0xffff9a04`9ae4c350 _MDL

   +0x010 CurrentMdlOffset : 0x28

   +0x018 DataLength       : 0x138

   +0x018 stDataLength     : 0x138

   +0x020 MdlChain         : 0xffff9a04`9c40a180 _MDL

   +0x028 DataOffset       : 0x88

   +0x000 Link             : _SLIST_HEADER

   +0x000 NetBufferHeader  : _NET_BUFFER_HEADER

   +0x030 ChecksumBias     : 0

   +0x032 Reserved         : 0

   +0x038 NdisPoolHandle   : 0xffff9a04`9aba28c0 Void

   +0x040 NdisReserved     : [2] (null)

   +0x050 ProtocolReserved : [6] 0x00000160`00000000 Void

   +0x080 MiniportReserved : [4] (null)

   +0x0a0 DataPhysicalAddress : _LARGE_INTEGER 0x0

   +0x0a8 SharedMemoryInfo : (null)

   +0x0a8 ScatterGatherList : (null)

0: kd> dt ndis!_MDL 0xffff9a04`9ae4c350

   +0x000 Next             : 0xffff9a04`9ae4c7d0 _MDL

   +0x008 Size             : 0n56

   +0x00a MdlFlags         : 0n4

   +0x00c AllocationProcessorNumber : 0x9a04

   +0x00e Reserved         : 0xffff

   +0x010 Process          : (null)

   +0x018 MappedSystemVa   : 0xffff9a04`9ae4c390 Void

   +0x020 StartVa          : 0xffff9a04`9ae4c000 Void

   +0x028 ByteCount        : 0x30

   +0x02c ByteOffset       : 0x390

0: kd> db 0xffff9a04`9ae4c390+0x28

ffff9a04`9ae4c3b8  01 02 03 04 05 06 07 08-00 d0 09 02 43 63 50 63  ............CcPc

ffff9a04`9ae4c3c8  9a 74 0e 74 7b 4b cd b6-fe 02 04 00 ff ff 00 00  .t.t{K..........

ffff9a04`9ae4c3d8  90 c3 88 a0 04 9a ff ff-60 09 80 02 00 00 00 00  ........`.......

ffff9a04`9ae4c3e8  60 09 c0 02 00 00 00 00-60 09 c0 02 00 00 00 00  `.......`.......

ffff9a04`9ae4c3f8  19 19 f3 02 00 00 00 00-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c408  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c418  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c428  00 00 00 00 00 00 00 00-20 77 00 9f 04 9a ff ff  ........ w....

可以看到现在已经将\x01\x02当做下一个Option的头部。而\x02位于Length字段,\x01无这个Type,所以会跳过0x10个字节。直接跳到下一个\x19\x04这部分。

之后再一次调用了Ipv6pUpdateRDNSS。

调用前:

0: kd> dt ndis!_NET_BUFFER @r14

   +0x000 Next             : (null) 

   +0x008 CurrentMdl       : 0xffff9a04`9ae4c7d0 _MDL

   +0x010 CurrentMdlOffset : 8

   +0x018 DataLength       : 0x128

   +0x018 stDataLength     : 0x128

   +0x020 MdlChain         : 0xffff9a04`9c40a180 _MDL

   +0x028 DataOffset       : 0x98

   +0x000 Link             : _SLIST_HEADER

   +0x000 NetBufferHeader  : _NET_BUFFER_HEADER

   +0x030 ChecksumBias     : 0

   +0x032 Reserved         : 0

   +0x038 NdisPoolHandle   : 0xffff9a04`9aba28c0 Void

   +0x040 NdisReserved     : [2] (null) 

   +0x050 ProtocolReserved : [6] 0x00000160`00000000 Void

   +0x080 MiniportReserved : [4] (null) 

   +0x0a0 DataPhysicalAddress : _LARGE_INTEGER 0x0

   +0x0a8 SharedMemoryInfo : (null) 

   +0x0a8 ScatterGatherList : (null) 

0: kd> dt ndis!_MDL 0xffff9a04`9ae4c7d0

   +0x000 Next             : 0xffff9a04`9ae4c8f0 _MDL

   +0x008 Size             : 0n56

   +0x00a MdlFlags         : 0n4

   +0x00c AllocationProcessorNumber : 0xffff

   +0x00e Reserved         : 0xffff

   +0x010 Process          : (null) 

   +0x018 MappedSystemVa   : 0xffff9a04`9ae4c810 Void

   +0x020 StartVa          : 0xffff9a04`9ae4c000 Void

   +0x028 ByteCount        : 0x30

   +0x02c ByteOffset       : 0x810

0: kd> db 0xffff9a04`9ae4c810+0x8

ffff9a04`9ae4c818  19 04 00 00 ff ff ff ff-5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ

ffff9a04`9ae4c828  5a 5a 5a 5a 5a 5a 5a 5a-18 22 5a 5a 5a 5a 5a 5a  ZZZZZZZZ."ZZZZZZ

ffff9a04`9ae4c838  5a 5a 5a 5a 5a 5a 5a 5a-00 19 09 02 41 6c 65 70  ZZZZZZZZ....Alep

ffff9a04`9ae4c848  9a fe 7b 74 7b 4b cd b6-d0 a1 c9 99 04 9a ff ff  ..{t{K..........

ffff9a04`9ae4c858  20 01 22 01 00 00 00 00-70 d2 fe 9f 04 9a ff ff   .".....p.......

ffff9a04`9ae4c868  c0 08 65 9a 04 9a ff ff-a0 0f 00 00 00 00 00 00  ..e.............

ffff9a04`9ae4c878  00 00 00 00 00 00 00 00-fa ad db ba fa ad db ba  ................

ffff9a04`9ae4c888  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

调用之后。可以看到这部分执行之后已经指向了\x18\x22。

0: kd> dt ndis!_NET_BUFFER @r14

   +0x000 Next             : (null) 

   +0x008 CurrentMdl       : 0xffff9a04`9ae4c7d0 _MDL

   +0x010 CurrentMdlOffset : 0x20

   +0x018 DataLength       : 0x110

   +0x018 stDataLength     : 0x110

   +0x020 MdlChain         : 0xffff9a04`9c40a180 _MDL

   +0x028 DataOffset       : 0xb0

   +0x000 Link             : _SLIST_HEADER

   +0x000 NetBufferHeader  : _NET_BUFFER_HEADER

   +0x030 ChecksumBias     : 0

   +0x032 Reserved         : 0

   +0x038 NdisPoolHandle   : 0xffff9a04`9aba28c0 Void

   +0x040 NdisReserved     : [2] (null) 

   +0x050 ProtocolReserved : [6] 0x00000160`00000000 Void

   +0x080 MiniportReserved : [4] (null) 

   +0x0a0 DataPhysicalAddress : _LARGE_INTEGER 0x0

   +0x0a8 SharedMemoryInfo : (null) 

   +0x0a8 ScatterGatherList : (null) 

0: kd> dt ndis!_MDL 0xffff9a04`9ae4c7d0

   +0x000 Next             : 0xffff9a04`9ae4c8f0 _MDL

   +0x008 Size             : 0n56

   +0x00a MdlFlags         : 0n4

   +0x00c AllocationProcessorNumber : 0xffff

   +0x00e Reserved         : 0xffff

   +0x010 Process          : (null) 

   +0x018 MappedSystemVa   : 0xffff9a04`9ae4c810 Void

   +0x020 StartVa          : 0xffff9a04`9ae4c000 Void

   +0x028 ByteCount        : 0x30

   +0x02c ByteOffset       : 0x810

0: kd> db 0xffff9a04`9ae4c810+0x20

ffff9a04`9ae4c830  18 22 5a 5a 5a 5a 5a 5a-5a 5a 5a 5a 5a 5a 5a 5a  ."ZZZZZZZZZZZZZZ

ffff9a04`9ae4c840  00 19 09 02 41 6c 65 70-9a fe 7b 74 7b 4b cd b6  ....Alep..{t{K..

ffff9a04`9ae4c850  d0 a1 c9 99 04 9a ff ff-20 01 22 01 00 00 00 00  ........ .".....

ffff9a04`9ae4c860  70 d2 fe 9f 04 9a ff ff-c0 08 65 9a 04 9a ff ff  p.........e.....

ffff9a04`9ae4c870  a0 0f 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c880  fa ad db ba fa ad db ba-00 00 00 00 00 00 00 00  ................

ffff9a04`9ae4c890  00 00 00 00 00 00 00 00-03 00 00 00 01 00 00 00  ................

ffff9a04`9ae4c8a0  50 c8 e4 9a 04 9a ff ff-10 e3 10 2d 00 f8 ff ff  P..........-....

Type为0x18时,会调用NdisGetDataBuffer函数,Length为0x22,也就是0x22*8=0x110个字节。对于NdisGetDataBuffer函数来说,当数据包是分片发送时,会被暂时存放到一个的栈空间内,也就是该函数的第三个参数。而当前的栈空间是不够的,所以导致了栈溢出,由于内核中存在GS保护,每次在函数结束时会验证函数初始阶段存放的Cookie值。如果Cookie值被修改则会报错,而BSOD正是这个原因。

 

0x04 漏洞危害

该漏洞基本可以稳定导致远程主机BSOD,条件受限于必须在同一内网下并且会对RDNSS包进行处理。对于远程代码执行,光靠这一个漏洞基本不可能达到代码执行的目的,内核中的保护很多,对于GS保护来说,需要与一个内存泄露的漏洞组合利用才能导致远程代码执行。

 

0x05 漏洞修复方案

通用修复建议

下载最新的补丁包进行更新修复,链接如下。

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898

临时修复建议

可以通过禁用ICMPv6 RDNSS来缓解。

先获取对应接口的接口号

netsh int ipv6 show int

之后关闭RDNSS

netsh int ipv6 set int 5 rabaseddnsconfig=disable

 

0x06 参考链接

  1. https://blog.quarkslab.com/beware-the-bad-neighbor-analysis-and-poc-of-the-windows-ipv6-router-advertisement-vulnerability-cve-2020-16898.html
  2. https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16898
  3. https://cert.360.cn/report/detail?id=771d8ddc2d703071d5761b6a2b139793
(完)