在分布式系统架构中,事务一致性是保障数据可靠性的核心支柱。.NET框架提供的System.Transactions命名空间,通过TransactionManager类实现了分布式事务的统一管理,支持多个资源管理器参与同一事务,确保操作的原子性、一致性、隔离性与持久性。
TransactionManager.Reenlist方法作为分布式事务恢复机制的关键组成部分,负责在事务崩溃或网络中断等异常场景下,重新注册事务参与者,以恢复事务状态并完成后续的提交或回滚操作。
然而,该方法内部存在高危安全隐患,通过BinaryFormatter组件对未经验证的二进制输入数据进行反序列化,本文将从Reenlist方法的核心功能入手,深入剖析反序列化漏洞的形成原理,详细讲解攻击载荷的构造方法与漏洞利用流程,并给出针对性的防御方案,帮助读者全面理解该漏洞的危害与防护要点。本文内容节选自《.NET安全攻防指南》一书 第17章 .NET反序列化漏洞插件,感兴趣的读者可进一步阅读本书获取更多安全研究内容。
原价258元,现限量优惠,数量有限!点击京东链接打开手机京东APP即可下单购买。在 .NET 框架中,System.Transactions.TransactionManager 负责管理分布式事务,允许多个资源管理器参与同一个事务,并保证它们的一致性。其中,TransactionManager.Reenlist方法用于在事务崩溃或中断后重新注册事务的参与者,确保事务状态得以恢复。
例如,当数据库事务因网络中断而未能正确提交,事务管理器可在系统恢复后重新注册该事务,并尝试提交或回滚操作。然而,该方法的 byte[] 参数为二进制序列化数据。使用 BinaryFormatter 进行反序列化,这为漏洞提供了一个利用点:如果传入恶意序列化数据,则可能导致代码执行漏洞。
BinaryFormatter是.NET框架中用于对象序列化与反序列化的核心组件,其设计初衷是为了实现.NET对象的快速序列化与传输。
但该组件存在一个致命的安全缺陷:在反序列化过程中,会自动创建指定类型的实例并执行其构造函数、序列化回调方法,如OnDeserialized等代码。这意味着,若能够控制反序列化的输入数据,构造恶意的序列化对象,就可以诱导BinaryFormatter在反序列化过程中执行任意恶意代码。
所以,微软官方已明确将BinaryFormatter标记为不安全组件,并在.NET 5及以上版本中限制其使用,同时推荐使用Protobuf等更安全的序列化方案。
在 TransactionManager.Reenlist 方法内部,核心处理逻辑如下,首先创建 MemoryStream:该方法首先使用 MemoryStream 读取传入的二进制数据,随后,从流中读取一个 32 位整数,并检查其值是否为 1。如果不满足,则不会进入后续处理逻辑。当 num == 1 时,进入 ReenlistTransaction 进行事务恢复。该方法最终调用 BinaryFormatter 进行反序列化,从而加载事务对象。
手动构造BinaryFormatter的恶意序列化载荷难度较高,需深入理解.NET对象的序列化格式与各类恶意 gadgets。在实际安全研究中,通常使用开源工具ysoserial.net来快速生成各类序列化漏洞的攻击载荷。
ysoserial.net是一款专门针对.NET序列化漏洞的载荷生成工具,支持生成基于BinaryFormatter等多种序列化组件的恶意载荷,内置了大量成熟的gadget链,比如TextFormattingRunProperties、TypeConfuseDelegate等。
针对本次漏洞,我们选择TextFormattingRunProperties gadget链生成恶意载荷,该gadget链兼容性强,可在多个.NET Framework版本中生效。生成载荷的命令如下:
ysoserial.exe -f BinaryFormatter -g TextFormattingRunProperties -o base64 -c calc
上述命令将生成一个 Base64 编码的恶意载荷,该载荷在反序列化时会触发 如图所示。calc.exe 执行,生成的攻击载荷
图yso生成BinaryFormatter载荷
然后对payload进行解码得到二进制数据serializedData,将额外的信息添加到之前的事务注册数据中,具体实现代码如下所示。
byte[] serializedData = Convert.FromBase64String(payload);byte[] newSerializedData =newbyte[serializedData.Length +5]; serializedData.CopyTo(newSerializedData,5);newSerializedData[0]=1;TestMe myTransactionEnlistment =newTestMe();TransactionManager.Reenlist(Guid.NewGuid(), newSerializedData, myTransactionEnlistment);
最后调用TransactionManager.Reenlist方法重新注册事务参与者触发反序列化漏洞。
Reenlist方法通过创建一个MemoryStream对象来读取传入的序列化数据,然后使用binaryReader从流中读取一个32位整数值,并将其存储在变量num中,并且检查整数值是否为1,也就是说第一位字节码必须是1,因此在重组事务数据时使用了newSerializedData[0]=1,如图所示。
图重组事务数据第1位字节码
接着调用oletxTransactionManager.ReenlistTransaction方法,用于有效性检查和获取相关资源,便于重新注册事务,如图所示。
图ReenlistTransaction方法重新注册事务
从图上调试显示进入核心方法oletxResourceManager.Reenlist,内部调用了BinaryFormatter格式化器formatter,用于反序列化恢复事务对象信息,也因此加载恶意的攻击载荷触发了反序列化漏洞。调试运行时如图所示。
图运行时反序列化启动本地计算器
本文围绕TransactionManager.Reenlist方法的反序列化漏洞展开,从方法功能、漏洞原理、攻击利用到防御方案进行了全面解析。该漏洞的核心成因是使用了不安全的BinaryFormatter组件对未经验证的输入数据进行反序列化,攻击者通过构造恶意载荷并绕过简单校验,即可执行任意代码。
免责声明:此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。任何未经授权的网络渗透、入侵或对他人网络破坏的活动而造成的直接或间接后果和损失,均由使用者为自身的行为负责并承担全部的法律和连带责任,与本号及作者无关,请务必遵循相关法律法规。本文所提供的工具仅用于学习和本地安全研究和测试,禁止用于其他方面。
针对TransactionManager.Reenlist方法的反序列化漏洞,需从组件替换、输入校验、版本升级等多个维度构建防御体系,彻底阻断攻击路径。
以下是具体的防御方案,最根本的防御措施是替换BinaryFormatter这一不安全组件。对于需要序列化/反序列化的场景,推荐使用以下安全的序列化方案:
System.Text.Json:.NET Core 3.0及以上版本内置的序列化组件,仅支持预定义类型的序列化,不支持任意类型的反序列化,安全性更高;
Protobuf(Protocol Buffers):谷歌开源的序列化框架,采用二进制编码,具有高效、紧凑、类型安全的特点,需预先定义数据结构,可有效防止恶意类型注入;
MessagePack:基于二进制的高效序列化格式,支持多种编程语言,同样需要预定义数据结构,安全性优于BinaryFormatter。
建议微软在.NET Core 3.0及以上版本、.NET 5及以上版本中,对组件进行了安全优化,从源头修复了该漏洞。因此,对于使用旧版本.NET Framework的应用,建议尽快升级到.NET Core 3.1、.NET 6或更高版本,以获得官方的安全保障。
以上知识点已收录于新书《.NET安全攻防指南》,并且有完整详细的介绍,如下图所示。全书共计25章,总计1010页,分为上下册,横跨.NET Web代码审计与红队渗透两大领域。
上册深入剖析.NET Web安全审计的核心技术,帮助读者掌握漏洞发现与修复的精髓;
下册则聚焦于.NET逆向工程与攻防对抗的实战技巧,揭秘最新的对抗策略与技术方法。原价258元,现限量优惠,数量有限!点击京东链接打开手机京东APP即可下单购买。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




还没有评论,来说两句吧...