【问题标题】:External json vulnerable because of Json.Net TypeNameHandling auto?由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?
【发布时间】:2018-08-08 20:01:28
【问题描述】:

我正在运营一个小型网站,用户可以在其中上传以 JSON 定义的自定义“对象”。最近我了解到使用带有自动类型反序列化的 JSON 的可能威胁:JSON problem。我想我理解这些问题,但我必须要确定。如果我只反序列化具有给定特定类型(此处为 MyObjectJsonConvert.DeserializeObject<MyObject>(json, settings); 的传入 JSON,并且 MyObject 内没有类型,并且 MyObject 的任何成员的子类型都没有类型 System.Objectdynamic,则有没有什么会变坏的,对吧?

settingsTypeNameHandling 设置为TypeNameHandling.Auto(我们不要质疑它可能与None 一起使用的这个决定,但我想了解它设置为Auto 的问题。)

编辑: 更多信息:我已经从前面提到的网站测试了 JSON:

{
    "obj": {
        "$type": "System.IO.FileInfo, System.IO.FileSystem",
        "fileName": "rce-test.txt",
        "IsReadOnly": true
    }
}

如果MyObjectSystem.Objectdynamic 类型字段obj 我可以重现威胁。但我想知道的是:即使 MyObject 是一个非常复杂的对象,有很多(派生的)子对象,但没有一个是或有 System.Object 或动态字段(也不像List<Object>)?例如。我可以想象 Json.NET 会因为 $type 信息而创建对象,即使在 MyObject 中找不到相应的字段。

【问题讨论】:

  • 请提供minimal reproducible example(即向我们展示您的代码)。
  • 在博文中,它有一个恶意负载示例。您是否使用该恶意负载进行了测试?
  • 谢谢,我已经添加了更多信息
  • But what I want to know: I'm on the safe side with bad prepared user-json even if MyObject is a very complex Object with lots of (derived) sub objects but NONE of them is or has a System.Object or a dynamic field (also not something like List<Object>)?你尝试的时候发生了什么?
  • 如果没有对象或动态字段,我无法复制它。但我不确定我是否想到了所有可能的攻击媒介。

标签: c# json.net


【解决方案1】:

TL/DR:在没有明显的 objectdynamic 成员的情况下,您可能是安全的,但您不能保证 为了安全。为了进一步降低您的风险,您应该遵循Newtonsoft documentation 的建议:

当您的应用程序从外部源反序列化 JSON 时,应谨慎使用TypeNameHandling。当使用 None 以外的值反序列化时,应使用自定义 SerializationBinder 验证传入类型。

完整答案

How to configure Json.NET to create a vulnerable web APITypeNameHandling caution in Newtonsoft Json 和 Alvaro Muñoz & Oleksandr Mirosh 的 blackhat paper 中描述的攻击都依赖于使用 Json.NET 的 TypeNameHandling setting诱使接收者构造一个攻击小工具 - 一种类型的实例,在构造、填充或处置时会影响对接收系统的攻击。

Json.NET 做了两件事来帮助防止此类攻击。首先,它忽略了未知属性。因此,简单地向 JSON 有效负载添加一个额外的未知属性,其值包含一个 "$type" 属性应该没有害处。其次,在多态值的反序列化过程中,当解析"$type"属性时,它会检查解析的类型是否与JsonSerializerInternalReader.ResolveTypeName()中的预期类型兼容:

    if (objectType != null
#if HAVE_DYNAMIC
        && objectType != typeof(IDynamicMetaObjectProvider)
#endif
        && !objectType.IsAssignableFrom(specifiedType))
    {
        throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
    }

如果多态值的预期类型与任何攻击小工具类型不兼容,则攻击将失败。如果您没有objectdynamicIDynamicMetaObjectProvider 类型的可序列化成员,这很可能是真的。但不确定!

即使您的数据模型中没有任何明显的无类型成员,也可能构建攻击小工具的情况包括:

  • 无类型集合的反序列化。如果您要反序列化任何类型的无类型集合或字典,例如 ArrayListList<object>Dictionary<string, dynamic>HashTable,那么您的系统很容易受到包含在集合项目中的小工具的攻击。

  • CollectionBase 继承的几十个集合中的任何一个的反序列化。这种类型早于 .Net 中泛型的引入,它代表一个“半类型”集合,其中项目的类型在添加时在运行时进行验证。由于验证发生在构造之后,因此存在一个可能构造攻击小工具的窗口。

    示例fiddle 仅显示此内容。

  • 反序列化与除object 之外的攻击小工具共享公共基本类型或接口的值。 TempFileCollection 实现 ICollectionIDisposableObjectDataProvider 实现 INotifyPropertyChangedISupportInitialize。如果您有任何多态成员或值被声明为这些接口中的任何一个,那么您很容易受到攻击。

  • 实现ISerializable 的类型的反序列化。 Json.NET supports this interface 默认情况下,并且某些外部库中看似无害的类型可能会在您不知情的情况下反序列化其流构造函数中的无类型成员。

    一个明显的例子是Sytem.Exception(或其任何子类型),它在其streaming constructor 中反序列化一个无类型字典"Data",它对应于无类型字典Exception.Data。如果您要反序列化 Exception(例如包含在日志文件中,这很常见),则以下 JSON 应该会导致攻击:

    {
      "$type": "System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
      "ClassName": "System.Exception",
      "Message": "naughty exception",
      "Data": {
        "$type": "System.Collections.ListDictionaryInternal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "data": {
          "$type": "System.IO.FileInfo, System.IO.FileSystem",
          "fileName": "rce-test.txt",
          "IsReadOnly": true    
        }
      },
    }
    

    通过设置DefaultContractResolver.IgnoreSerializableInterface = true,可以在不创建自定义序列化绑定器的情况下缓解攻击。当然,这可能会导致某些 .Net 类库类型的序列化出现问题。

  • 如果您设置DefaultContractResolver.IgnoreSerializableAttribute = false,则反序列化标有[Serializable] 的类型可能会遇到类似问题。不过默认是true,所以不改这个设置应该没问题。

  • 使用您认为成员的反序列化类型不会被序列化——但如果存在则将被反序列化。例如。考虑以下类型:

    public MyType
    {
        public object tempData;
        public bool ShouldSerializeTempData() { return false; }
    }
    

    感谢 Json.NET 的 conditional serialization 功能,tempData 成员将永远不会被序列化,因此您可能认为自己很清楚。但如果存在,它将被反序列化!反编译您的代码并注意到此类成员的攻击者将能够为MyType 制作攻击小工具有效负载。

而这正是我能想到的。如您所见,验证在大型对象图中,永远不会尝试反序列化与某些攻击小工具兼容的多态类型,这基本上是不平凡的。因此,我强烈建议对自定义 SerializationBinder 进行额外保护,以确保不会对意外类型进行反序列化。

【讨论】:

  • 非常感谢您的详细解答!所以解决方案是使用 SerializationBinder 和“白名单”所有可能的允许类型。
猜你喜欢
  • 1970-01-01
  • 2018-11-17
  • 2016-04-18
  • 2018-01-19
  • 2015-10-03
  • 2019-08-10
  • 2016-12-17
  • 2013-05-21
  • 1970-01-01
相关资源
最近更新 更多