Younge学习.NET反序列化漏洞

原创 时间 2017-10-20   younge 神月资讯

在上一篇文章《小白学源码审计-7-.NET反序列化漏洞》已经简单介绍了错误使用XmlSerializer类进行反序列化时可能造成远程代码执行的问题,除了XmlSerializer外,.NET下还提供了其他序列化类,错误使用其他序列化类同样可导致远程代码执行。

0x01 前言

在上一篇文章《小白学源码审计-7-.NET反序列化漏洞》已经简单介绍了错误使用XmlSerializer类进行反序列化时可能造成远程代码执行的问题,除了XmlSerializer外,.NET下还提供了其他序列化类,错误使用其他序列化类同样可导致远程代码执行。

0x02 序列化与反序列化

.NET提供了多种序列化方法,上文简单介绍了使用XmlSerializer进行序列化,攻击者可通过ObjectDataProvider类、System.Windows.Markup.XamlReader类实现反序列化过程代码执行,而除了该类外,常用的还有二进制序列化。

二进制序列化

二进制序列化用到的类为System.Runtime.Serialization.Formatters.Binary.BinaryFormatter。该反序列化过程可以注意的特点如下:

  1. BinaryFormatter仅能反序列化声明了Serializable的类。

  2. 反序列化对象时,类的常规构造函数不会被调用,任何依赖于常规构造函数的代码不会执行。

  3. 反序列化过程会调用OnDeserializedOnDeserializing方法。

  4. 反序列化的类实现了ISerializable接口,反序列化过程会调用用户自定义的反序列化过程方法,方法名定义类似构造函数,方法为类名加两个参数(SerializationInfoStreamingContext),如classname(SerializationInfo info,StreamingContext context)

  5. 反序列化的类实现了IDeserializationCallback接口,反序列化过程会调用IDeserializationCallback.OnDeserialization(Objectsender)方法。

  6. 反序列化的类实现了IObjectReference接口,反序列化过程会调用GetRealObject(StreamingContext context)方法。

  7. 反序列化的类如果自定义了析构方法,也存在风险,虽然反序列化过程并不会直接调用析构方法,但在对象被垃圾回收器回收的时候,析构函数被GC自动调用。自定义析构方法名为类名前加~,如~classname()

总结就是下图中定义的类,在反序列化该类时会调用图中定义的除析构方法外的所有方法。

微信图片_20171023204210.jpg

0x03 Gadget

.NET Framework的部分类可以协助攻击者完成一些危险操作。在2012James Forshaw演讲的议题《Are you my Type?》就已经提到过一些可被利用的类:

TempFileCollection

该类自定义了析构方法,当该类对象被回收时,会调用自定义析构方法,该析构方法中会删除files字段上的文件,导致任意文件删除漏洞。

微信图片_20171023205015.jpg

System.IO.FileSystemInfo

FileSystemInfo类是提供文件系统信息(如FileInfoDirectoryInfo)类的基类,它实现了ISerializable接口,反序列化期间会调用自定义的反序列化方法,使得可自动创建SMB请求。

微信图片_20171023205024.jpg

SortedSet & ComparisonComparer

而在174月,他又提出了可以通过SortedSet类与ComparisonComparer类实现反序列化时代码执行。下面简单分析利用链的原理(作者水平有限,难免存在不足,请指出):

ComparisonComparer类中定义了委托变量_comparisonComparison<T>是一个接收两个相同类型参数的委托类型,委托C#的特性,可以将其看作是一个安全的'函数指针')。ComparisonComparer类中方法Compare(T x, T y)中调用_comparison(x, y),我们可以通过控制_comparison的值,通过多路广播委托实现调用IComparer::Compare时,调用Process::Start,下面是ComparisonComparer类的源码

微信图片_20171023205028.jpg

回到SortedSet类,该类会对插入的元素(Add方法)自动调用比较器IComparer::Compare方法对比排序,比较器由用户创建时SortedSet类确定,那么我们就可以使用上述ComparisonComparer类作为比较器,使得进行对比时调用Process::Start,即SortedSet对象调用Add ->IComparer::Compare->Process::Start

观察SortedSet类源码,注意到反序列化时的OnDeserialization方法,调用了Add方法。如下图所示:

微信图片_20171023205033.jpg

payload生成示例代码如下,运行后会产生一个序列化文件,使用该文件进行反序列化即可弹出计算器:

微信图片_20171023205037.jpg

借用原文中的图片,整个反序列化过程的调用链如下:

微信图片_20171023205042.jpg

除了上述Gadget外,17Black Hat议题《JSON Attacks》上同样提出了可实现远程代码执行的类PSobject,但在经过CVE-2017-8565的补丁修复后,已经无法利用。

0x04 缺陷代码示例

为了方便理解,编写了一个常见的使用BinaryFormatter进行反序列化例子。程序首先从用户提交的参数中接收一段字符串,对该进行Base64解码恢复成流,最后将该字节流反序列化为对象。

微信图片_20171023205046.jpg

使用以下代码,生成payload

微信图片_20171023205049.jpg

运行后产生以下payload

微信图片_20171023205054.jpg

payload提交至刚刚编写的反序列化位置可以看到计算器被弹出。

微信图片_20171023205057.jpg

除了BinaryFormatter,在ObjectStateFormatterNetDataContractSerializerLosFormatter中均可使用SortedSet  ComparisonComparer类实现反序列化过程代码执行。

<<上一篇下一篇>>