利用链分析 关于序列化与反序列化过程中使用的代理选择器以及代理这里就不再介绍了,代理(Surrogate)可以使得不能被序列化的类被序列化,具体的操作需要用户自行实现一个ISerializationSurrogate
接口并实现其GetObjectData
以及SetObjectData
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Reflection;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.Text;namespace Test { public class Personal { public string Name; public int Age; public string Address; } public class PersonalSurrogate : ISerializationSurrogate { public void GetObjectData (object obj, SerializationInfo info, StreamingContext context ) { Personal personal = (Personal)obj; info.AddValue("Name" , personal.Name); info.AddValue("Age" , personal.Age); info.AddValue("Address" , personal.Address); } public object SetObjectData (object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector ) { Personal personal = (Personal)obj; personal.Name = info.GetString("Name" ); personal.Age = info.GetInt32("Age" ); personal.Address = info.GetString("Address" ); return personal; } } public class SurrogateTest { static void Main (string [] args ) { Personal personal = new Personal(); BinaryFormatter binaryFormatter = new BinaryFormatter(); PersonalSurrogate personalSurrogate = new PersonalSurrogate(); SurrogateSelector surrogateSelector = new SurrogateSelector(); surrogateSelector.AddSurrogate(typeof (Personal), new StreamingContext(StreamingContextStates.All), personalSurrogate); binaryFormatter.SurrogateSelector = surrogateSelector; MemoryStream memoryStream = new MemoryStream(); binaryFormatter.Serialize(memoryStream, personal); } } }
在上面的例子中personal
既没有实现ISerializable
接口也没有被Serilizable
特性修饰,正常来说是不能被序列化以及反序列化的,不过我们通过创建SurrogateSelector
并设置Surrogate
来实现Personal
对象的正确序列化与反序列化。 通过Surrogate
的特性我们便可以在反序列化漏洞的利用中使用哪些正常来说不可以被序列化与反序列化的类型。不过从上面的代码中我们也知道,要想实现对某个特定的不可序列化类的序列化需要我们在服务端创建对应的Surrogate
并实现ISerializationSurrogate
接口, 然后在序列化过程中进行配置,而服务端的代码逻辑是我们在攻击过程中影响不了的,这样看起来Suggogate
并没有用武之地。 天无绝人之路,存在这样一个特殊的SurrogateSeletor
ActivitySurrogateSelector
其GetSurrogate
方法在特定条件下可以返回一个ObjectSurrogate
类型的Surrogate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public override ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector ) { if (type == null ) { throw new ArgumentNullException("type" ); } selector = this ; ISerializationSurrogate serializationSurrogate = null ; bool flag; lock (ActivitySurrogateSelector.surrogateCache) { flag = ActivitySurrogateSelector.surrogateCache.TryGetValue(type, out serializationSurrogate); } if (flag) { if (serializationSurrogate != null ) { return serializationSurrogate; } return base .GetSurrogate(type, context, out selector); } else { if (typeof (Activity).IsAssignableFrom(type)) { serializationSurrogate = this .activitySurrogate; } else if (typeof (ActivityExecutor).IsAssignableFrom(type)) { serializationSurrogate = this .activityExecutorSurrogate; } else if (typeof (IDictionary<DependencyProperty, object >).IsAssignableFrom(type)) { serializationSurrogate = this .dependencyStoreSurrogate; } else if (typeof (XmlDocument).IsAssignableFrom(type)) { serializationSurrogate = this .domDocSurrogate; } else if (typeof (Queue) == type) { serializationSurrogate = this .queueSurrogate; } else if (typeof (Guid) == type) { serializationSurrogate = this .simpleTypesSurrogate; } else if (typeof (ActivityBind).IsAssignableFrom(type)) { serializationSurrogate = this .objectSurrogate; } else if (typeof (DependencyObject).IsAssignableFrom(type)) { serializationSurrogate = this .objectSurrogate; } lock (ActivitySurrogateSelector.surrogateCache) { ActivitySurrogateSelector.surrogateCache[type] = serializationSurrogate; } if (serializationSurrogate != null ) { return serializationSurrogate; } return base .GetSurrogate(type, context, out selector); } }
从上面的代码可知要想获取ObjectSurrogate
类型的Surrogate
需要满足序列化类为DependencyObject
或者ActivityBind
的子类,这样就限制了我们的发挥。 不过虽然ActivitySurrogateSelector
的GetSurrogate
方法有这个限制,但我们可以自定义一个SurrogateSelector
来绕开这个限制,从而完成使用ObjectSurrogate
的getObjectData
方法来进行序列化。
1 2 3 4 5 6 7 8 9 10 11 public override ISerializationSurrogate GetSurrogate (Type type, StreamingContext context, out ISurrogateSelector selector ) { selector = this ; if (!type.IsSerializable) { Type t = Type.GetType("System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate, System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" ); return (ISerializationSurrogate)Activator.CreateInstance(t); } return base .GetSurrogate(type, context, out selector); }
这时候就又存在问题了,这不还是在改变序列化的过程吗,如果反序列化的过程没有设置对应的Surrogate
不还是不能成功进行漏洞利用吗? 这里就不得不提到ObjectSurrogate
神奇的GetObjectData
方法了。 在该方法中调用了info.SetType
设置了反序列化过程中obj
的实际类型为ActivitySurrogateSelector.ObjectSurrogate.ObjectSerializedRef
,也就是说发序列化过程中将不会立即得到原始的obj,而是先得到ObjectSerializedRef
类型。
1 2 3 4 5 6 7 8 9 public void GetObjectData (object obj, SerializationInfo info, StreamingContext context ) { info.AddValue("type" , obj.GetType()); string [] array = null ; MemberInfo[] serializableMembers = FormatterServicesNoSerializableCheck.GetSerializableMembers(obj.GetType(), out array); object [] objectData = FormatterServices.GetObjectData(obj, serializableMembers); info.AddValue("memberDatas" , objectData); info.SetType(typeof (ActivitySurrogateSelector.ObjectSurrogate.ObjectSerializedRef)); }
ObjectSerializedRef
实现了 IObjectReference
以及IDeserializationCallback
接口,这两个接口分别包括方法GetRealObject
以及OnDeserialization
方法。GetRealObject
与OnDeserialization
方法均在对象图构造完成后执行,即ObjectSerializedRef
对象构造完成后执行,且GetRealObject
方法先于OnDeserialization
方法执行,主要作用是控制反序列化后的实际对象返回, 而OnDeserialization
则用于在所有字段都恢复后进行初始化或验证操作。GetRealObject
方法调用GetUninitializedObject
通过this.type
构造目标对象,而this.type
我们通过ObjectSurrogate
的getObjectData
方法可以知道是哪个最初序列化的不可序列化的类,在我们的例子中即Personal
。
1 2 3 4 5 6 7 8 object IObjectReference.GetRealObject(StreamingContext context) { if (this .returnedObject == null ) { this .returnedObject = FormatterServices.GetUninitializedObject(this .type); } return this .returnedObject; }
OnDeserialization
方法用于还原Personal
对象的成员变量的值。
1 2 3 4 5 6 7 8 9 10 void IDeserializationCallback.OnDeserialization(object sender) { if (this .returnedObject != null ) { string [] array = null ; MemberInfo[] serializableMembers = FormatterServicesNoSerializableCheck.GetSerializableMembers(this .type, out array); FormatterServices.PopulateObjectMembers(this .returnedObject, serializableMembers, this .memberDatas); this .returnedObject = null ; } }
由此我们知道了我们可以通过自定义SurroGateSeletor
返回ObjectSurrogate
实现对不可序列化对象的序列化,并且这样序列化的结果字符串即便在反序列化过程中BinarryFormatter
没有设置对应的SurroGateSeletor
的情况下也能被成功反序列化, 因为其使用了ObjectSerializedRef
这个可以序列化以及反序列化的类对那些不可序列化的类进行了包装。