.NET高级代码审计(第五课) .NET Remoting反序列化漏洞
0x00 前言
最近几天国外安全研究员Soroush Dalili (@irsdl)公布了.NET Remoting应用程序可能存在反序列化安全风险,当服务端使用HTTP信道中的SoapServerFormatterSinkProvider类作为信道接收器并且将自动反序列化TypeFilterLevel属性设置为Full的时候会造成反序列化漏洞,从而实现远程RCE攻击,本文笔者从原理和代码审计的视角做了相关介绍和复现,并且归纳成.NET反序列化漏洞系列课程中的第五课

0x01 .NET Remoting概念
.NET Remoting是一种分布式应用解决方案,它允许不同AppDomain(应用程序域)之间进行通信,这里的通信可以是在同一个进程中进行或者一个系统中的不同进程间进行的通信。.NET Remoting框架也提供了多种服务,包括激活和生存期支持,以及负责与远程应用程序进行消息传输的通道。应用程序可在重视性能的场景下使用二进制数据传输,在需要与其他远程处理框架进行交互的场景下使用 XML 数据传输。在从一个AppDomain向另一个AppDomain传输消息时,所有的XML数据都使用 SOAP 协议,总体看.NET Remoting有以下三点优势:

0x02 .NET Remoting信道和协议
信道是Server和Client进行通信用的,在.NET Remoting中提供了三种信道类型,

IpcChannel提供了使用Windows进程间通信(IPC)系统在同一计算机上的应用程序域之间传输消息的机制。在同一计算机上的应用程序域之间进行通信时,IPC信道比TCP或HTTP信道要快得多。但是IPC只在本机应用之间通信。所以,在客户端和服务端在同一台机器时,我们可以通过注册IpcChannel来提高Remoting的性能。但如果客户端和服务端不在同一台机器时,我们不能注册IPCChannel,在此不多介绍。
TcpChannel提供了基于Socket 的传输工具,使用Tcp协议来跨越Remoting边界传输序列化的消息流。默认使用二进制格式序列化消息对象,具有更高的传输性能,适用于局域网。

HttpChannel提供了一种使用Http协议,使其能在Internet上穿透防火墙传输序列化消息流,HttpChannel类型使用Soap格式序列化消息对象,因此它具有更好的互操作性。适用于广域网,如图

0x03 攻击原理
研究漏洞之前先普及下HttpChannel的相关基础知识,HttpChannel类使用 SOAP 协议在远程对象之间传输消息,并且符合SOAP1.1的标准,所有的消息都是通过SoapFormatter传递,此格式化器会将消息转换为 XML数据并进行序列化,同时向数据流中添加所需的SOAP标头。如果指定了二进制格式化程序,则会创建二进制数据流。随后,将使用 HTTP 协议将数据流传输至目标URI。HttpChannel分类如图

下面是从微软文档里摘取定义服务端的代码片段:

每行代码分别实现了创建服务端通道并且绑定本地端口9090;注册服务端通道;以及通过访问URI为RemoteObject.rem的地址调用远程的对象,在.NET Remoting中有个激活方式的概念,表示在访问远程类型的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。代码中引入了服务端激活的WellKnown方式,看下图

WellKnown理解为知名对象的激活,服务器应用程序在激活对象实例之前会在统一资源标识符(URI)上来发布这个类型。然后该服务器进程会为此类型配置一个WellKnown对象,并根据指定的端口或地址来发布对象,它的激活分为SingleTon模式 、SingleCall模式,SingleTon类所代表的类型规定每个AppDomain只能存在一个实例,当SingleTon类型加载到AppDomain的时候,CLR调用它的静态构造器去构造一个SingleTon对象,并将它的引用保存到静态字段中,而且该类也没有提供任何的公共构造器方法,这就防止了其他任何代码构造该类的其他实例。具体到这两种模式各有区别,都可以触发漏洞,因不是重点所以不做过多介绍。
3.1、远程对象
图中的RemoteObject类,这是一个远程对象,看下微软官方的定义

RemoteObject继承自MarshalByRefObject类,MarshalByRefObject类(按引用封送)支持远程处理的应用程序中跨应用程序域(AppDomain)边界访问对象,同一应用程序域中的对象直接通信。不同应用程序域中的对象的通信方式有两种:跨应用程序域边界传输对象副本、通过代理交换消息,MarshalByRefObject类本质上通过引用代理交换消息来跨应用程序域边界进行通信的对象的基类。
3.2、服务端
创建服务端的信道分为HttpServerChannel、HttpChannel,其中HttpServerChannel类有多个重载方法,需要知道和漏洞相关的两个重载是发生在参数IServerChannelSinkProvider,它表示服务端远程消息流的信道接收器

IServerChannelSinkProvider派生出多个类,例如BinaryServerFormatterSinkProvider、SoapServerFormatterSinkProvider类,如下图

SoapServerFormatterSinkProvider类实现了这个接口,并使用SoapFormatter格式化器序列化对象,如下图

SoapFormatter格式化器实现了System.Runtime.Serialization.IFormatter接口,IFormatter接口包括了Serialize、Deserialize方法,提供了序列化对象图的功能。

在序列化的时候调用格式化器的Serialize方法,传递对流对象的引用和想要序列化的对象图引用的两个参数,流对象可以是从System.IO.Stream类派生出来的任意对象,比如常见的MemoryStream、FileStream等,简单的说就是通过格式化器的Serialize方法可将对象图中所有对象都被序列化到流里去,通过Deserialize方法将流反序列化为对象图。

介绍完SoapFormatter之后回过头来继续看SoapServerFormatterSinkProvider类,它有一个重要的属性TypeFilterLevel,表示当前自动反序列化级别,支持的值为Low(默认)和FULL。

当取值为Low的时候,代表.NET Framework 远程处理较低的反序列化级别,只支持基本远程处理功能相关联的类型,而取值为Full的时候则支持所有类型在任意场景下远程处理都支持,所以取值为Full的时候,存在着严重的安全风险。

梳理一下HTTP信道攻击的前置条件,第一步实例化SoapServerFormatterSinkProvider类并且设置TypeFilterLevel属性为Full;第二步实例化HttpServerChannel/HttpChannel类,

使用下列三种重载方法实现传入参数SoapServerFormatterSinkProvider
- 满足攻击者需求的第1个攻击重载方法是public HttpServerChannel(IDictionary properties, IServerChannelSinkProvider sinkProvider);
这里笔者用VulnerableDotNetHTTPRemoting项目中的VulnerableDotNetHTTPRemotingServer类来改写官方Demo 。IDictionary集合存放当前通道的配置信息,如图

- 满足攻击者需求的第2个攻击重载方法是public HttpServerChannel(string name, int port, IServerChannelSinkProvider sinkProvider);

- 满足攻击者需求的第3个攻击方法是位于HttpChannel类下的 public HttpChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider, IServerChannelSinkProvider serverSinkProvider)

VulnerableDotNetHTTPRemoting项目中用到就是第三种攻击方法,由于.NET Remoting客户端在攻击中用途不大,故笔者不做赘述。
0x04 打造Poc
国外研究者发现Microsoft.VisualStudio.Text.UI.Wpf.dll 中的Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties类实现了ISerializable接口,这个接口可以对序列化/反序列化的数据进行完全的控制,并且还避免了反射机制, 但有个问题Microsoft.VisualStudio.Text.UI.Wpf.dll需要安装VisualStudio ,在非开发主机上不会安装,但研究者后来发现Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties类在Windows默认安装的Microsoft.PowerShell.Editor.dll里也同样存在,反编译得到源码,

实现了ISerializable接口,ISerializable只有一个方法,即 GetObjectData,如果一个对象的类型实现了ISerializable接口,会构造出新的System.Runtime.Serialization.SerializationInfo对象,这个对象包含了要为对象序列化的值的集合。

GetObjectData方法的功能是调用SerializationInfo类型提供的SetType方法设置类型转换器,使用提供的AddValue多个重载方法来指定要序列化的信息,针对要添加的每个数据,都要调用一次AddValue,GetObjectData添加好所有必要的序列化信息后会返回到类型解析器,类型解析器获取已经添加到SerializationInfo对象的所有值,并把他们都序列化到流中,代码逻辑实现部分参考如下

TextFormattingRunProperties类中的ForegroundBrush属性支持XAML数据,攻击者可以引入《.NET高级代码审计(第一课) XmlSerializer反序列化漏洞》同样的攻击载荷,如下

又因为SoapServerFormatterSinkProvider类用SoapFormatter格式化器处理数据,所以客户端提交的数据肯定是SOAP消息,SOAP是基于XML的简易协议,让应用程序在HTTP上进行信息交换用的。为了给出标准的SOAP有效负载,笔者参考微软官方给的Demo

结合Soroush Dalili (@irsdl)给出的有效载荷,元素a1指向的命名空间正是TextFormattingRunProperties类所在空间地址

在<a1:TextFormattingRunProperties></a1:TextFormattingRunProperties>元素内添加了属性ForegroundBrush,在ForegroundBrush元素内带入ResourceDictionary,这样SOAP消息的攻击载荷主体就完成了。@irsdl给出的有效载荷如下

由于.NET Remoting只支持SOAP 1.1,所以要指定SOAPAction,说来也奇怪这个SOAPAction的值是个URI,但是这个URI不必对应实际的位置。SOAPAction Header选项在SOAP1.2版本已经移除。另外一点图上请求URI中的扩展名是rem,如果生产环境部署在IIS里,默认调用.NET应用模块IsapiModule来处理HttpRemoting,所以在白盒审计或者黑盒渗透的时候遇到rem扩展名,就得考虑可能开启了.NET Remoting应用。

还有一处需要注意,HTTP请求有个扩展方法M-POST,其中的其中的M表示Mandatory(必须遵循的,强制的),如果一个HTTP请求包含至少一个强制的扩充声明,那么这个请求就称为强制的请求。强制请求的请求方法名字必须带有“M-”前缀,例如,强制的POST方法称为M-POST,这样的请求方式或许能更好的躲避和穿透防护设备。

0x05 代码审计
5.1、SoapServerFormatterSinkProvider
从SoapServerFormatterSinkProvider类分析来看,需要满足属性TypeFilterLevel的值等于TypeFilterLevel.Full,可触发的通道包括了HttpChannel类、HttpServerChannel类,这个攻击点的好处在于发送HTTP SOAP消息,可很好的穿透防火墙。

5.2、BinaryServerFormatterSinkProvider
从BinaryServerFormatterSinkProvider类分析来看,也需要满足属性TypeFilterLevel的值等于TypeFilterLevel.Full,可触发的通道包括了TcpChannel类、TcpServerChannel类,这个攻击点可反序列化二进制文件,笔者由于时间仓促,暂时不做分析跟进,有兴趣的朋友可自行研究。
0x06 复盘
笔者将VulnerableDotNetHTTPRemoting项目部署到虚拟机,运行Server端,打开了本地端口1234

Burpsuite请求后成功弹出计算器,感谢Soroush Dalili (@irsdl)的分享。

0x07 总结
.NET Remoting技术已经出来很多年了,现在微软主推WCF来替代它,在开发中使用概率越来越低,从漏洞本身看只要没有设置SoapServerFormatterSinkProvider类属性TypeFilterLevel=Full就不会产生反序列化攻击(默认就是安全的)最后.NET反序列化系列课程笔者会同步到 https://github.com/Ivan1ee/ 、https://ivan1ee.gitbook.io/ ,后续笔者将陆续推出高质量的.NET反序列化漏洞文章,欢迎大伙持续关注,交流,更多的.NET安全和技巧可关注实验室公众号。

.NET高级代码审计(第五课) .NET Remoting反序列化漏洞的更多相关文章
- .NET高级代码审计(第一课)XmlSerializer反序列化漏洞
0X00 前言 在.NET 框架中的 XmlSerializer 类是一种很棒的工具,它是将高度结构化的 XML 数据映射为 .NET 对象.XmlSerializer类在程序中通过单个 API 调用 ...
- .NET高级代码审计(第二课) Json.Net反序列化漏洞
0X00 前言 Newtonsoft.Json,这是一个开源的Json.Net库,官方地址:https://www.newtonsoft.com/json ,一个读写Json效率非常高的.Net库,在 ...
- .NET高级代码审计(第三课)Fastjson反序列化漏洞
0X00 前言 Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置 ...
- .NET高级代码审计(第四课) JavaScriptSerializer反序列化漏洞
0X00 前言 在.NET处理 Ajax应用的时候,通常序列化功能由JavaScriptSerializer类提供,它是.NET2.0之后内部实现的序列化功能的类,位于命名空间System.Web.S ...
- [代码审计]四个实例递进php反序列化漏洞理解【转载】
原作者:大方子 原文链接:https://blog.csdn.net/nzjdsds/article/details/82703639 0x01 索引 最近在总结php序列化相关的知识,看了好多前辈师 ...
- 【C语言探索之旅】 第二部分第五课:预处理
内容简介 1.课程大纲 2.第二部分第五课: 预处理 3.第二部分第六课预告: 创建你自己的变量类型 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语 ...
- 【C语言探索之旅】 第一部分第五课:运算那点事
内容简介 1.课程大纲 2.第一部分第五课:运算那点事 3.第一部分第六课预告:条件表达式 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏 ...
- NeHe OpenGL教程 第四十五课:顶点缓存
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- kali linux 渗透测试视频教程 第五课 社会工程学工具集
第五课 社会工程学工具集 文/玄魂 教程地址:http://edu.51cto.com/course/course_id-1887.html 目录 第五课社会工程学工具集 SET SET的社会工程 ...
随机推荐
- React中使用CSS
第一种: 在组件中直接使用style 不需要组件从外部引入css文件,直接在组件中书写. import React, { Component } from "react"; con ...
- android 使用webview 加载网页
1. <WebView android:id="@+id/webView" android:layout_width="fill_parent" andr ...
- java进行3DES加解密
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.Secre ...
- activiti如何获取当前节点以及下一步路径或节点(转)
ACTIVITI相对于JBPM来说,比较年轻,用的人少,中文方面的资料更少,我根据网上到处找得资料以及看官方文档总结出来了代码,非常不容易啊.废话不多说,直接上代码吧: 首先是根据流程ID获取当前任务 ...
- python包与模块导入
一 .module 通常模块为一个文件,直接使用import来导入就好了.可以作为module的文件类型有".py".".pyo".".pyc&quo ...
- 【转载】 Jointwave零延时视频传输for FPGA/ASIC进入军工领域
半导体知识产权H.264/H.265 硅IP核供应商Jointwave公司的发布了一系列视频编解码RTL IP核,已经成功应用于军事工业领域的指挥作战,无人机UAV控制,航空和航天摄像机,视频记录黑匣 ...
- python学习 day20 (3月27日)----(单继承多继承c3算法)
继承: 提高代码的重用性,减少了代码的冗余 这两个写法是一样的 Wa('青蛙').walk() #青蛙 can walk wa = Wa('青蛙') wa.walk() #青蛙 can walk 1. ...
- Firefox table 不居中解决办法 解决火狐层或 table 不居中
Firefox table 不居中解决办法: table 使用 align="center" ,IE正常,Firefox 却是居左了,网上有各种解决的办法,比如在table外面再套 ...
- 6. Uniforms in American's Eyes 美国人眼里的制服
6. Uniforms in American's Eyes 美国人眼里的制服 (1) Americans are proud of their variety and individuality,y ...
- TCP/IP协议(5):传输层之TCP
一.TCP报文 上图为TCP报文的格式,可以看到TCP头部占20个字节,其中红色圆圈中每一项占一位,表示TCP报文的类型,置1表示该项有效. SYN表示建立连接. FIN表示关闭连接. A ...