外部json因为Json.Net TypeNameHandling auto而易受攻击?

时间:2018-02-28 20:33:01

标签: c# json.net

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

<{1}} dynamic的{​​{1}}设置为TypeNameHandling(我们不会质疑这个可能适用于settings的决定,但我想了解它的问题,设置为TypeNameHandling.Auto。)

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

None

如果Auto{ "obj": { "$type": "System.IO.FileInfo, System.IO.FileSystem", "fileName": "rce-test.txt", "IsReadOnly": true } } MyObject类型的字段System.Object,我可以重现威胁。但是我想知道的是:即使MyObject是一个非常复杂的对象,有很多(派生的)子对象,但是其中没有一个是或者有dynamic或者动态字段(也不是obj)?例如。我可以想象,即使System.Object中没有相应的字段,Json.NET也会像List<Object>信息一样创建对象。

1 个答案:

答案 0 :(得分:17)

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

中的建议
  当您的应用程序从外部源反序列化JSON时,应谨慎使用

TypeNameHandling。使用非None以外的值进行反序列化时,应使用自定义SerializationBinder验证传入类型。

完整答案

How to configure Json.NET to create a vulnerable web API TypeNameHandling caution in Newtonsoft Json 和AlvaroMuñoz&amp; 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内对与无类型字典Exception.Data对应的无类型字典"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类库类型的序列化问题。

  • 如果设置[Serializable],反序列化标有DefaultContractResolver.IgnoreSerializableAttribute = false的类型可能会遇到类似的问题。但是,默认值为true,因此如果您不更改此设置,则应该没问题。

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

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

    由于Json.NET的conditional serialization功能,tempData成员永远不会被序列化,所以你可能会认为你是明确的。但如果存在,它将被反序列化!反编译您的代码并通知此类成员的攻击者将能够为MyType制作攻击小工具负载。

而这正是我能想到的最重要的事情。正如您所看到的,验证在大型对象图中,从来没有尝试反序列化与某些攻击小工具兼容的多态类型,这实际上是非常重要的。因此,我强烈建议对自定义SerializationBinder进行额外保护,以确保不会反序列化任何意外类型。