首页 » 网站建设 » phpdcom设置装备摆设技巧_若何运用NET托管的DCOM实现权限提升

phpdcom设置装备摆设技巧_若何运用NET托管的DCOM实现权限提升

访客 2024-12-08 0

扫一扫用手机浏览

文章目录 [+]

翻译:华为未然实验室

预估稿费:200RMB

phpdcom设置装备摆设技巧_若何运用NET托管的DCOM实现权限提升

投稿办法:发送邮件至linwei#360.cn,或上岸网页版在线投稿

phpdcom设置装备摆设技巧_若何运用NET托管的DCOM实现权限提升
(图片来自网络侵删)

序言

影响互操作技能的漏洞是一类较为有趣的安全漏洞,这是由于这些漏洞常日会影相应用该技能的任何运用程序,无论运用程序实际实行什么操作。
同样,在很多情形下,开拓职员难以在不该用该技能的情形下推出缓解方法,但有时候却做不到。

我创造.NET的组件工具模型(COM)互操作性层存在此类漏洞,这使.NET跨权限边界用于分布式COM(DCOM)实质上是不屈安的。
本文将描述一些可对此进行滥用的方法,首先是得到提升的权限,然后是一个远程代码实行漏洞。

背景知识

回顾.NET的历史可以知道,很多其早期根本是试图制作一个更好的COM版本。
这使微软很看重确保,虽然.NET本身可能不是COM,但其必须能够与COM互操作。
因此,.NET可以用于实现和利用COM工具。
比如,不用在COM工具上调用QueryInterface,你只须要将工具投射到兼容COM的接口上。
以C#实现进程外COM做事器很大略,如下所示:

客户端现在可利用其CLSID(由COMClass上的Guid属性定义)连接到COM做事器。
实际上这很大略,由于.NET中的大量核心类被标记为COM可见,并注册为任何COM客户端(纵然未以.NET编写)可用。

为了使这统统都有效,.NET运行时向开拓职员隐蔽了大量的样板。
有几种机制可影响此样板互操作性代码,比如InterfaceType属性,其定义COM接口是源自IUnknown还是IDispatch,但大多数情形下,你得到的是所给予的。

开拓职员可能没故意识到的一点是,不仅是您指定的接口从.NET COM工具导出,运行时还会添加一些“管理”接口。
这些接口通过将.NET工具包装在COM可调用包装器(CCW)中来实现。

我们可以列举CCW所暴露的接口。
以System.Object为例,下表展示了支持的接口及每个接口实现的办法(在运行时动态实现或在运行时内部静态实现)。

_Object接口指的是System.Object类的COM可见表示,其是所有.NET工具的根,其必须动态天生,由于其依赖于被暴露的.NET工具。
另一方面,IManagedObject由运行时本身实现,且实现在所有CCW中共享。

我从2013年开始关注.NET暴露的COM攻击面,彼时我正在研究IE沙箱逃逸。
您可以在沙箱之外访问的COM工具之一是.NET ClickOnce支配代理(DFSVC),其原来因此.NET实现,这可能并不足为奇。
我实际上创造了两个问题,不是在DFSVC本身,而是在由所有.NET COM工具暴露的_Object接口。
_Object接口如下所示(以C++)。

第一个bug(导致CVE-2014-0257)在于GetType方法。
该方法返回一个可用于访问.NET反射API的COM工具。
由于返回的_Type COM工具正在做事器中运行,以是您可以调用一系列方法,从而可访问Process.Start方法,您可以调用该方法实现沙箱逃逸。
如欲理解更多细节,请查看我编写并放在Github上的PoC。
微软通过阻挡通过DCOM访问反射API办理了此问题。

第二个问题更奇妙,是.NET互操作特性(大概没有人认为是安全隐患)的副产品。
加载.NET运行时须要相称多的额外资源,因此,对付本机COM客户端调用.NET COM做事器上的方法,默认是让COM和CCW管理通信,纵然这样有损性能。
微软可以选择利用COM封送器逼迫.NET在客户端加载,但这样彷佛有点过分,更别说客户端乃至可能没有安装兼容的.NET版本了。

当.NET与COM工具交互时,其会创建反向CCW——运行时可调用包装器(RCW)。
这是一个.NET工具,实在现COM接口的运行时版本,并将其编组到COM工具。
现在COM工具完备有可能实际上是用.NET编写的,乃至可能在相同的运用程序域中。
如果.NET无所作为,可能对性能造成双倍影响,在RCW中编组,以调用一个COM工具,这实际上是一个托管工具的CCW。

考试测验从CCW“展开”托管工具并获取一个真正的.NET工具是很好的。
这是这段中的油滑鬼使坏的地方,IManagedObject接口,如下所示:

当.NET运行时得到一个COM工具时,其将通过一个过程来确定其是否可以从其CCW“展开”工具,并避免创建一个RCW。
该过程被记录,但总而言之,运行时将实行以下操作:

1. 调用COM工具上的QueryInterface来确定其是否实现IManagedObject接口。
如果没有,则返回得当的RCW。

2. 调用接口上的GetObjectIdentity。
如果GUID与每次运行时GUID(在运行时启动时天生)匹配,且AppDomain ID与当前的AppDomain ID匹配,则在运行时表中查找CCW值,并提取指向真实管理工具的指针并将其返回。

3. 调用接口上的GetSerializedBuffer。
运行时将检讨.NET工具是否可序列化,如果可以,则其将工具通报给BinaryFormatter :: Serialize,并将结果打包到二进制字符串(BSTR)中。
这将返回给客户端,客户端现在将考试测验通过调用BinaryFormatter :: Deserialize将缓冲区反序列化到工具实例。

第2和3步彷佛都是坏主张。
比如,在第2步中时,每运行时GUID不能被猜到,如果您可以访问同一进程中的任何其他工具(例如由做事器本身暴露的COM工具),则您可以调用工具上的GetObjectIdentity,并将GUID和AppDomain ID重播回做事器。
这并没有给您带来太多好处,CCW值只是一个数字不是一个指针,以是,你最多能提取已经有CCW的工具。

相反,真正棘手的是第3步。
无论什么措辞(比如Java、PHP、Ruby,等等),任意反序列化都是危险的,.NET亦不例外。
显然这是我们可以利用的一个问题,我们先从权限提升角度看一看。

提升权限

我们如何让以.NET编写的COM做事器进行任意反序列化?我们须要做事器考试测验为通过COM暴露的可序列化.NET工具创建RCW。
如果一样平常而言可以做到这一点的话是很好的,便是这么凑巧,在标准_Object接口上存在一个我们可以通报任何工具的函数,Equals方法。
Equals的目的是比较两个工具的等同性。
如果我们将.NET COM工具通报给做事器的Equals方法,则运行时必须考试测验将其转换为RCW,以便托管实现可以利用它。
在这一点上,运行时须要有所帮助,并检讨其是否真的是一个CCW包装的.NET工具。
做事器运行时调用GetSerializedBuffer,导致做事器进程中的任意反序列化。

这是我第二次利用ClickOnce支配代理(导致CVE-2014-4073)。
利用这一点的技巧是将序列化的Hashtable发送到包含IHashCodeProvider接口的COM实现的做事器。
当Hashtable运行其自定义反序列化代码时,其须要重修其内部散列构造,其通过在每个密钥上调用IHashCodeProvider :: GetHashCode来实现。
通过添加一个可序列化的Delegate工具,作为个中一个密钥,我们将把它通报给客户端。
通过以本地代码编写客户端,通过IManagedObject的自动序列化将不会在将委托传回给我们时发生。
委托工具卡在做事器进程内,但CCW暴露给我们,我们可以调用。
调用委托会导致在做事器高下文中实行指定的函数,这样我们能以做事器权限启动新进程。
由于这一样平常都有效,以是我还编写了一个工具来为任何.NET COM做事器完成此事情,请见github。

微软本可以通过变动IManagedObject :: GetSerializedBuffer的行为来修复CVE-2014-4073,但是没有。
相反,微软以本机代码重写了代理。
还发布了一篇博客文章,警告开拓职员.NET DCOM的危险。
然而,他们并没有弃用任何API以在.NET中注册DCOM工具,因此除非开拓职员的安全意识极高,并且恰巧阅读了微软的安全博客,否则他们可能不会意识到这是一个问题。

这类bug到本日一贯存在,比如,当我最近收到一个新的事情条记本电脑时,我做了我常日会做的事情,列举安装了什么OEM“增值”软件,看看是否有什么可以利用。
结果表明,作为音频驱动程序包的一部分安装了由杜比编写的COM做事。
经由几分钟的检讨,基本上列举COM做事器的可访问接口,我创造其是用.NET编写的(IManagedObject的存在总是一个大的赠品)。
我启动了我的利用工具,在不到5分钟的韶光内,实现了在本地系统中的代码实行。
现在已作为CVE-2017-7293被修复。
由于.NET DCOM基本上不屈安,杜比唯一可以做的因此本地代码重写做事。

攻击Caller

找到IManagedObject bug类的一个新实例让我开始关注其其他影响。
首先要强调的是,做事器本身并无漏洞,只有当我们能逼迫做事器充当回调攻击运用程序的DCOM客户端时,该漏洞才能被利用。
通过托管COM互操作调用DCOM工具的任何.NET运用程序都该当有类似的问题,而不仅仅是做事器。
DCOM可能有什么常见的用例,特殊是在当代企业环境中?

我首先想到的是Windows Management Instrumentation(WMI)。
当代版本的Windows可以利用WS-Management(WSMAN)协议连接到远程WMI实例,但由于遗留缘故原由,WMI仍旧支持DCOM传输。
WMI的一个用例是扫描企业机器是否有恶意行为。
这种复苏的缘故原由之一是Powershell(在.NET中实现)具有易于利用的WMI支持。
如果PS或者.NET考试测验访问网络中受影响的事情站,那么或许PS或.NET本身随意马虎受到此种攻击?

查看MSDN后可知,.NET通过System.Management命名空间支持WMI。
这从.NET的开始就一贯存在。
其支持对WMI的远程访问,考虑到类的年代,其先于WSMAN,因此险些可以肯定在后台利用DCOM。
在PS前端,通过诸如Get-WmiObject之类的cmdlet支持WMI。
PS版本3(在Windows 8和Server 2008中引入)添加了一组新的cmdlet,包括Get-CimInstance。
阅读干系链接可知,引入CIM cmdlet、支持WSMAN的缘故原由显而易见,并且链接明确指出“旧”WMI cmdlet利用DCOM。

WMI cmdlets:

优点:比较WsMan Cmdlets供应更好的任务抽象,输出是一个.NET工具

缺陷:利用非标准DCOM协议,不适用于非Windows

在这一点上,我们可以直接进入.NET和PS类库的RE,但有一个更大略的方法。
通过不雅观察到WMI做事器的DCOM RPC流量,可能能够看到.NET客户端是否查询IManagedObject。
Wireshark已经有一个DCOM解析器,为我们节省了很多麻烦。
出于测试目的,我设置了两个虚拟机,一个是用Windows Server 2016(作为域掌握器),另一个是用Windows 10(作为域上的客户端)。
然后我从客户真个域管理员发出一个大略的WMI PS命令‘Get-WmiObject Win32_Process -ComputerName dc.network.local’, 同时利用Wireshark监控网络。
以下图片显示了我不雅观察到的内容:

屏幕截图显示了来自PS客户端(192.168.56.102)的DC做事器上WMI DCOM工具(192.168.56.50)的初初创立要求。
我们可以看到其在查询IWbemLoginClientID接口,这是初始化过程的一部分(如MS-WMI中所述)。
然后,客户端考试测验要求其他几个接口; 尤其是其要求IManagedObject。
这险些肯定表明利用PS WMI cmdlet的客户端是有漏洞的。

为了测试这是否真的是一个漏洞,我们须要一个假的WMI做事器。
彷佛这是一个很大的寻衅,但是我们须要做的便是修正winmgmt做事的注册,以指向我们的假实现。
只要该做事随后用CLSID {8BC3F05E-D86B-11D0-A075-00C04FB68820}注册一个COM类,COM启动器将启动做事,并为任何客户端供应我们的假WMI工具的实例。
回顾我们的网络捕获,结果是对IManagedObject的查询没有发生在主类上,而是在从IWbemLevel1Login :: NTLMLogin返回的IWbemServices工具上。
但是没紧要,其只是添加了一些额外的样板代码。
为了确保其有效,我们将实现以下代码,其将见告反序列化代码来查找一个名为Badgers的未知程序集。

如果我们成功注入序列化流,那么我们可以预期PS进程考试测验查找Badgers.dll文件,并利用我们创造的Process Monitor。

链接解串器

当利用反序列化实现本地权限提升时,我们可以确保我们可以连接到做事器并运行任意代理。
在RCE案例中我们没有这样的担保。
如果WMI客户端启用了默认Windows防火墙规则,那么我们险些肯定无法连接到委托工具所做的RPC端点。
我们还须要被许可通过网络登录到运行WMI客户真个机器,我们的受攻击机器可能无法登录到域,或者企业策略可能会阻挡除所有者外的任何人登录到客户端机器。

因此,我们须要一个轻微不同的操持,不是通过暴露一个新的委托工具来主动攻击客户端,相反,我们将给它通报一个字节流(反序列化时会实行所需的操作)。
在空想的天下中,我们会创造一个可以为我们实行任意代码的可序列化类。
可悲的是(据我所知)没有这样的类存在。
因此,我们须要找到一系列“Gadget”类,这些类链接在一起可实行所需的效果。

以是在这种情形下,我方向于编写一些快速剖析工具,.NET支持相称不错的反射API,因此找到基本信息(比如一个类是否可序列化或一个类支持哪个接口)很随意马虎做到。
我们还须要一个要检讨的程序集的列表,我知道的最快的方法是利用作为.NET SDK一部分安装的gacutil实用程序(并随Visual Studio一起安装)。
运行命令gacutil / l> assemblies.txt来创建可以加载和处理的程序集名称列表。
对付第一遍,我们将探求可序列化且个中有委托的任何类,这些可能是实行操作时实行任意代码的类。
利用我们的程序集列表,我们可以编写一些如下所示的大略代码来找到这些类,为每个程序集名称字符串调用FindSerializableTypes:

在我的系统中,该剖析只产生了大约20个类,个中许多类实际上是在不分布在默认安装中的F#库中。
但一个类确实引起了我的把稳——System.Collections.Generic.ComparisonComparer<T>。
您可以在参考源中找到该实现,但其很大略,全貌如下:

这个类包装了一个Comparison<T>委托——利用两个通用参数(相同类型),并返回一个整数,调用委托来实现IComparer <T>接口。
虽然类是内部的,但其创建通过Comparer<T>::Create静态方法暴露。
这是链的第一部分,通过这个类和一些序列化代理的推拿,我们可以将IComparer<T>::Compare链接到Process::Start,并得到创建的任意进程。
现在我们须要链的下一部分,用任意的参数来调用该比较器工具。

比较器工具在通用.NET凑集类中被大量利用,许多这些凑集类也有自定义反序列化代码。
在这种情形下,我们可以滥用SortedSet <T>类,反序列化利用内部比较器工具重修其凑集以确定排序顺序。
通报给比较器的值是凑集中的条款,这完备在我们的掌握之下。
我们来写一些测试代码来检讨其是否和我们预期的一样有效:

有关这个代码唯一奇怪的是TypeConfuseDelegate。
这是一个长期存在的问题,.NET代理并不总是逼迫实行其类型署名,特殊是返回值。
在这种情形下,我们创建一个两个条款标多播代理(按顺序运行多个单个代理的委托),将一个委托设置为返回一个int的String :: Compare,将另一个设置为返回Process类实例的Process::Start。
纵然在反序列化和调用两种单独的方法时这也有效。
然后其将返回创建的作为整数的进程工具,这意味着其会将指针返回到进程工具的实例。
以是我们终极得到如下链条:

虽然这是一个非常大略的链,但它有一些问题,因此对付我们的用场其不太空想:

1. Comparer <T> :: Create方法和相应的类仅在.NET 4.5中引入,涵盖Windows 8及更高版本,但不涵盖Windows 7。

2. 漏洞利用部分依赖于代理的返回值的类型稠浊。
虽然其只是将Process工具转换为一个整数,但这有点不太空想,可能会故意想不到的副浸染。

3. 启动一个流程略显喧华,从内存加载我们的代码更好。

以是我们须要找到更好的东西。
我们须要一些至少在.NET 3.5上有效的东西,这是Windows 7上Windows Update会自动更新到的版本。
此外,其不应该依赖于未定义的行为或从DCOM通道外部加载我们的代码,例如通过HTTP连接。
这对我彷佛是个寻衅。

改进链条

在查看可序列化的其他一些类时,我在System.Workflow.ComponentModel.Serialization命名空间中把稳到了一些。
该命名空间包含属于Windows Workflow Foundation的一部分的类,其是用于构建实行管道以实行一系列任务的一组库。
这一点有点意思,事实证明,我之前利用过核心功能——作为Windows Powershell中代码完全性的一个绕过。

这使我找到了ObjectSerializedRef类。
这看起来很像一个将反序列化任何工具类型的类。
而不仅仅是序列化的。
如果是这样的话,那么这是一个用于建立功能更强大的反序列化链的非常强大的原语。

查看实现后可知,该类被用作通过ActivitiySurrogateSelector类暴露的序列化替代。
这是.NET序列化API的一个特性,您可以在序列化过程中指定“代理选择器”,其将用代理类更换工具。
当流反序列化时,此代理类包含足够的信息来重修原始工具。
一个用例是处理非可序列化类的序列化,但是ObjectSerializedRef超出了特定的用例,并许可您反序列化任何内容。
按顺序进行的测试:

ObjectSurrogate类似乎没任何问题。
这个类完备毁灭了确保不可信的BinaryFormatter流的任何希望,其可以从.NET 3.0得到。
任何没有标记为可序列化的类现在都是目标。
在反序列化过程中调用一个任意委托很大略,由于开拓职员不会做任何事情来戒备这种攻击办法。

现在选择一个目标来建立我们的反序列化链。
我本可以选择进一步磋商Workflow类,但是API是恐怖的(实际上在.NET 4中,微软用一个新的、轻微更好一些的API代替了旧的)。
相反,我会选择一个非常易于利用的目标,措辞集成查询(LINQ)。

LINQ作为核心措辞特性在.NET 3.5中引入。
一种类似于SQL的新语法引入了C#和VB编译器,以跨可列举工具实行查询,比如列表或字典。
基于长度过滤名称列表并返回大写列表的语法示例如下:

您也可以不将LINQ视作查询语法,而是视作在.NET中实行列表推导的一种方法。
将“select”视为等同于“map”,将“where” 视为等同于“filter”可能更故意义。
查询语法下是在System.Linq.Enumerable类中实现的一系列方法。
您可以利用正常的C#语法而不是查询措辞编写,如果这样做,则前面的例子变成如下所示:

方法(如Where)须要两个参数、一个列表工具(这在上面的例子中是隐蔽的)及一个委托来调用列举列表中的每个条款。
委托常日由运用程序供应,但是没有什么可以阻挡您利用系统方法更换委托。
要记住的主要事情是在列举列表之前不会调用委托。
这意味着我们可以利用LINQ方法构建一个列举列表,利用ObjectSurrogate进行序列化(LINQ类本身不是可序列化的),然后,如果我们能逼迫反序列化列表被列举,其将实行任意代码。

利用LINQ作为原语,我们可以创建一个列表,当列举时,该列表按以下顺序将字节数组映射到该字节数组中的一个类型的实例:

唯一棘手的部分是第2步,我们想提取一个特定的类型,但我们唯一真正的选择是利用Enumerable.Join方法,这须要投契取巧才能使其有效。
一个更好的选择是利用Enumerable.Zip,但这只在.NET 4中引入。
以是,我们将获取加载的程序集中的所有类型,并全部创建,如果我们只有一个类型,那么这不会有什么差异。
以C#实现是若何的?

C#实现中唯一不明显的部分是Assembly :: GetTypes的委托。
我们须要的是一个接管一个Assembly工具并返回一个Type工具的列表的委托。
然而,由于GetTypes是一个实例方法,默认是捕获Assembly类并将其存储在委托工具内,这将导致一个不吸收参数并返回一个Type列表的委托。
我们可以通过利用反射API为实例成员创建一个开放委托来办理这个问题。
一个开放的委托不存储工具实例,而是将其作为额外的Assembly参数公开,这正是我们想要的。

利用我们的列举列表,我们可以让程序集加载及让我们自己的代码实行,但是我们如何列举列表启动链?为此,我考试测验找到一个当调用ToString(一个很常见的方法)时会列举列表的类。
这在Java中很大略,险些所有的凑集类都有这个确切的行为。
可悲的是,彷佛.NET在这方面与Java不同。
以是我修正了我的剖析工具,以考试测验探求可以帮我们达到目的的小工具。
长话短说,我通过三个单独的类创造了一个从ToString到IEnumerable的链。
该链如下所示:

我们完成了吗?还没有,还差一步,我们须要在反序列化期间调用任意工具上的ToString。
当然,如果我不是已经有一个方法来完成,我不会选择ToString。
在这末了一个案例中,我会回到滥用Hashtable。
在Hashtable类的反序列化期间,其将重修其密钥集,我们对此已有理解,由于这是我利用本地EoP的序列化的方法。
如果两个密钥相同,则反序列化将会失落败,Hashtable会抛出非常,导致运行以下代码:

该密钥被通报到值数组中的GetResourceString,以及对资源字符串的引用。
资源字符串以及通报到String.Format的密钥被查找。
天生的资源字符串具有格式化代码,因此当String.Format碰着非字符串值时,其调用工具上的ToString将其格式化。
这导致在反序列化期间调用ToString,从而会踢掉事宜链,从而引发我们从内存中加载任意.NET组件并在WMI客户真个高下文中实行代码。

您可以查看我添加到问题跟踪器的最新PoC中的终极实现。

结论

微软通过确保System.Management类从不直接为WMI工具创建RCW修复了RCE(远程代码实行)问题。
但是,此修复程序不会影响.NET中任何其他DCOM的利用,因此特权.NET DCOM做事器仍旧存在漏洞,其他远程DCOM运用程序也可能受到攻击。

此外,这该当是一个教训,切勿利用.NET BinaryFormatter类反序列化不受信赖的数据。
无论如何这样做也是危险的,但开拓职员彷佛放弃了制作安全的可序列化类的任何希望。
ObjectSurrogate的存在实际上意味着,运行时中的每个类都是可序列化的,无论原始开拓职员希望与否。

末了一个想法,您该当始终对中间件的安全性履行持疑惑态度,尤其是当您不能检讨其所作所为时。
IManagedObject的问题是与生俱来的,难以移除,以是精确修复很难。

相关文章

php为无色透明技巧_水货钻石其实也还行

从各种钻石中,可以看到大大小小的“包裹体” 图片来源:参考文献包裹体的种类多样。比钻石形成更早的包裹体,叫“原生包裹体”;与钻石同...

网站建设 2024-12-19 阅读0 评论0

phpstudy发送gbk技巧_php的文件上传

这里首先声明一下这一章的内容比较多,比较难,你要抱着和自己去世磕的态度。细微之处不放过,多敲多练是王道。 学习就像爬山,得一步一步...

网站建设 2024-12-19 阅读0 评论0