欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

MS 17-010:NSA Eternalblue SMB 漏洞分析

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

环境

EXPLOIT:

Eternalblue-2.2.0.exe

TARGET:

win7 sp1 32bits

srv.sys 6.1.7601.17514

srvnet.sys 6.1.7601.17514

PATCH:

MS17-010

漏洞原理

srv.sys在处理SrvOs2FeaListSizeToNt的时候逻辑不正确导致越界拷贝。我们首先看下漏洞的触发点:

unsigned int __fastcall SrvOs2FeaToNt(int a1, int a2)
{
  int v4; // edi@1
  _BYTE *v5; // edi@1
  unsigned int result; // eax@1
  v4 = a1 + 8;
  *(_BYTE *)(a1 + 4) = *(_BYTE *)a2;
  *(_BYTE *)(a1 + 5) = *(_BYTE *)(a2 + 1);
  *(_WORD *)(a1 + 6) = *(_WORD *)(a2 + 2);
  _memmove((void *)(a1 + 8), (const void *)(a2 + 4), *(_BYTE *)(a2 + 1));
  v5 = (_BYTE *)(*(_BYTE *)(a1 + 5) + v4);
  *v5++ = 0;
  _memmove(v5, (const void *)(a2 + 5 + *(_BYTE *)(a1 + 5)), *(_WORD *)(a1 + 6)); //这里产生的越界覆盖
  result = (unsigned int)&v5[*(_WORD *)(a1 + 6) + 3] & 0xFFFFFFFC;
  *(_DWORD *)a1 = result - a1;
  return result;
}
发生越界的地方见上面第二个memmove。调试的时候可以这样下断点:

kd> u srv!SrvOs2FeaToNt+0x4d
srv!SrvOs2FeaToNt+0x4d:
9877b278 ff15e0a07698    call    dword ptr [srv!_imp__memmove (9876a0e0)]
9877b27e 0fb74606        movzx   eax,word ptr [esi+6]
9877b282 8d441803        lea     eax,[eax+ebx+3]
9877b286 83e0fc          and     eax,0FFFFFFFCh
9877b289 83c418          add     esp,18h
9877b28c 8bc8            mov     ecx,eax
9877b28e 2bce            sub     ecx,esi
9877b290 5f              pop     edi
//最后一次越界的拷贝的长度是0xa8
ba e1 srv!SrvOs2FeaToNt+0x4d ".if(poi(esp+8) != a8){gc} .else {}"
这么设断点的原因是最后一次越界的拷贝的长度是0xa8,断下来后可以发现:

kd> dd esp
99803b38  88c8dff9 a3fc203a 000000a8 88c8dff8
99803b48  a3fc2039 00000000 a3fb20d8 a3fc2035
99803b58  a3fd2030 99803b7c 9877b603 88c8dff0
99803b68  a3fc2035 88307360 a3fb20b4 a3fb2008
99803b78  a3fc2035 99803bb4 98794602 88c8dff0
99803b88  99803bbc 99803ba8 99803bac 88307360
99803b98  a3fb2008 00000002 a3fb20b4 a3fb20d8
99803ba8  00010fe8 00000000 00000000 99803c00
kd> !pool 88c8dff9
Pool page 88c8dff9 region is Nonpaged pool
*88c7d000 : large page allocation, tag is LSdb, size is 0x11000 bytes
        Pooltag LSdb : SMB1 data buffer, Binary : srv.sys
kd> !pool 88c8e009
Pool page 88c8e009 region is Nonpaged pool
 88c8e000 size:    8 previous size:    0  (Free)       ....
88c8e008 doesn't look like a valid small pool allocation, checking to see
if the entire page is actually part of a large page allocation...
*88c8e000 : large page allocation, tag is LSbf, size is 0x11000 bytes
        Pooltag LSbf : SMB1 buffer descriptor or srvnet allocation, Binary : srvnet.sys
kd> ? 88c7d000 +11000
Evaluate expression: -2000101376 = 88c8e000
kd> ? 88c8dff9 +a8
Evaluate expression: -2000101215 = 88c8e0a1 //这里明显越界了。
我们可以从上面的调试记录看到明显的越写拷贝操作。可以看到被覆盖的是SMB1的buffer是有srvnet.sys分配的。这里exploit精心布局好的,是通过pool喷射的将两个pool连接在一起的。覆盖后面的这个pool有啥用后面会提到。

有同学会说”这只是现象,漏洞真正的成因在哪里呢?”。往下看:

unsigned int __fastcall SrvOs2FeaListSizeToNt(int pOs2Fea)
{
  unsigned int v1; // edi@1
  int Length; // ebx@1
  int pBody; // esi@1
  unsigned int v4; // ebx@1
  int v5; // ecx@3
  int v8; // [sp+10h] [bp-8h]@3
  unsigned int v9; // [sp+14h] [bp-4h]@1
  v1 = 0;
  Length = *(_DWORD *)pOs2Fea;
  pBody = pOs2Fea + 4;
  v9 = 0;
  v4 = pOs2Fea + Length;
  while ( pBody < v4 )
  {
    if ( pBody + 4 >= v4
      || (v5 = *(_BYTE *)(pBody + 1) + *(_WORD *)(pBody + 2),
          v8 = *(_BYTE *)(pBody + 1) + *(_WORD *)(pBody + 2),
          v5 + pBody + 5 > v4) )
    {
      //
      // 注意这里修改了Os2Fea的Length,自动适应大小
      // 初始值是0x10000,最终变成了0x1ff5d

[1] [2] [3] [4] [5] [6] [7] [8]  下一页

环境 copyright 无奈人生

EXPLOIT:

copyright 无奈人生

Eternalblue-2.2.0.exe 内容来自无奈安全网

TARGET: 本文来自无奈人生安全网

win7 sp1 32bits

内容来自无奈安全网

srv.sys 6.1.7601.17514 copyright 无奈人生

srvnet.sys 6.1.7601.17514 内容来自无奈安全网

PATCH:

无奈人生安全网

MS17-010 www.wnhack.com

漏洞原理 本文来自无奈人生安全网

srv.sys在处理SrvOs2FeaListSizeToNt的时候逻辑不正确导致越界拷贝。我们首先看下漏洞的触发点: www.wnhack.com

unsigned int __fastcall SrvOs2FeaToNt(int a1, int a2)
{
  int v4; // edi@1
  _BYTE *v5; // edi@1
  unsigned int result; // eax@1
  v4 = a1 + 8;
  *(_BYTE *)(a1 + 4) = *(_BYTE *)a2;
  *(_BYTE *)(a1 + 5) = *(_BYTE *)(a2 + 1);
  *(_WORD *)(a1 + 6) = *(_WORD *)(a2 + 2);
  _memmove((void *)(a1 + 8), (const void *)(a2 + 4), *(_BYTE *)(a2 + 1));
  v5 = (_BYTE *)(*(_BYTE *)(a1 + 5) + v4);
  *v5++ = 0;
  _memmove(v5, (const void *)(a2 + 5 + *(_BYTE *)(a1 + 5)), *(_WORD *)(a1 + 6)); //这里产生的越界覆盖
  result = (unsigned int)&v5[*(_WORD *)(a1 + 6) + 3] & 0xFFFFFFFC;
  *(_DWORD *)a1 = result - a1;
  return result;
}
发生越界的地方见上面第二个memmove。调试的时候可以这样下断点:

无奈人生安全网

kd> u srv!SrvOs2FeaToNt+0x4d
srv!SrvOs2FeaToNt+0x4d:
9877b278 ff15e0a07698    call    dword ptr [srv!_imp__memmove (9876a0e0)]
9877b27e 0fb74606        movzx   eax,word ptr [esi+6]
9877b282 8d441803        lea     eax,[eax+ebx+3]
9877b286 83e0fc          and     eax,0FFFFFFFCh
9877b289 83c418          add     esp,18h
9877b28c 8bc8            mov     ecx,eax
9877b28e 2bce            sub     ecx,esi
9877b290 5f              pop     edi
//最后一次越界的拷贝的长度是0xa8

www.wnhack.com


ba e1 srv!SrvOs2FeaToNt+0x4d ".if(poi(esp+8) != a8){gc} .else {}"
这么设断点的原因是最后一次越界的拷贝的长度是0xa8,断下来后可以发现:

www.wnhack.com

kd> dd esp
99803b38  88c8dff9 a3fc203a 000000a8 88c8dff8
99803b48  a3fc2039 00000000 a3fb20d8 a3fc2035
99803b58  a3fd2030 99803b7c 9877b603 88c8dff0
99803b68  a3fc2035 88307360 a3fb20b4 a3fb2008
99803b78  a3fc2035 99803bb4 98794602 88c8dff0
99803b88  99803bbc 99803ba8 99803bac 88307360
99803b98  a3fb2008 00000002 a3fb20b4 a3fb20d8
99803ba8  00010fe8 00000000 00000000 99803c00
kd> !pool 88c8dff9
Pool page 88c8dff9 region is Nonpaged pool
*88c7d000 : large page allocation, tag is LSdb, size is 0x11000 bytes
        Pooltag LSdb : SMB1 data buffer, Binary : srv.sys
kd> !pool 88c8e009
Pool page 88c8e009 region is Nonpaged pool
 88c8e000 size:    8 previous size:    0  (Free)       ....
88c8e008 doesn't look like a valid small pool allocation, checking to see
if the entire page is actually part of a large page allocation...

无奈人生安全网


*88c8e000 : large page allocation, tag is LSbf, size is 0x11000 bytes
        Pooltag LSbf : SMB1 buffer descriptor or srvnet allocation, Binary : srvnet.sys
kd> ? 88c7d000 +11000
Evaluate expression: -2000101376 = 88c8e000
kd> ? 88c8dff9 +a8
Evaluate expression: -2000101215 = 88c8e0a1 //这里明显越界了。
我们可以从上面的调试记录看到明显的越写拷贝操作。可以看到被覆盖的是SMB1的buffer是有srvnet.sys分配的。这里exploit精心布局好的,是通过pool喷射的将两个pool连接在一起的。覆盖后面的这个pool有啥用后面会提到。 copyright 无奈人生

有同学会说”这只是现象,漏洞真正的成因在哪里呢?”。往下看: 无奈人生安全网

unsigned int __fastcall SrvOs2FeaListSizeToNt(int pOs2Fea)
{
  unsigned int v1; // edi@1
  int Length; // ebx@1
  int pBody; // esi@1
  unsigned int v4; // ebx@1
  int v5; // ecx@3
  int v8; // [sp+10h] [bp-8h]@3
  unsigned int v9; // [sp+14h] [bp-4h]@1
  v1 = 0;
  Length = *(_DWORD *)pOs2Fea;
  pBody = pOs2Fea + 4;
  v9 = 0;
  v4 = pOs2Fea + Length;
  while ( pBody < v4 )
  {
    if ( pBody + 4 >= v4
      || (v5 = *(_BYTE *)(pBody + 1) + *(_WORD *)(pBody + 2),
          v8 = *(_BYTE *)(pBody + 1) + *(_WORD *)(pBody + 2),
          v5 + pBody + 5 > v4) )
    {
      //
      // 注意这里修改了Os2Fea的Length,自动适应大小
      // 初始值是0x10000,最终变成了0x1ff5d

内容来自无奈安全网


www.wnhack.com

[1] [2] [3] [4] [5] [6] [7] [8]  下一页

无奈人生安全网

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。