【问题标题】:BinaryFormatter deserialise malicious code?BinaryFormatter 反序列化恶意代码?
【发布时间】:2014-01-08 08:46:21
【问题描述】:

听说有safety questions over the BinaryFormatter.

我将用户生成的文件从客户端发送到服务器。这些是序列化的类,然后由服务器读取。

根据我对上述链接的理解,这是危险的。但是我尝试过发送一次性类,甚至尝试过实现 ISerilizable 的类。但由于服务器不知道源程序集,两者都被拒绝了。

[Serializable]
public class Ship : ISerializable
{
    public Ship()
    {

    }

    public Ship(SerializationInfo info, StreamingContext context)
    {
        Console.WriteLine("test");
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {

    }
}

那么客户端如何通过这个向量成功地将代码输入我的服务器?通过伪造命名空间名称和公钥导致服务器尝试反序列化它,从而运行上面的代码?还是有更微妙的方法?

不幸的是,这个功能是我游戏的核心基础,所以我要小心。

【问题讨论】:

  • 他们可能会向您发送您自己的任何恰好标记为可序列化的类。我认为这很危险。
  • 您是否需要使用BinaryFormatter,或者序列化您的数据?或者用二进制序列化你的数据?
  • 序列化作用于数据,而不是代码。如果你的代码容易受到恶意输入的攻击,那么是的,这可能是另一种攻击它的方式——就像注入恶意数据的任何其他方式一样。此外,原帖的答案大多是猜测,Java序列化不适用的cmets或真正人为的例子

标签: c# serialization binaryformatter


【解决方案1】:

我知道这是一个老问题,但我对接受的答案不太满意。

序列化作用于数据,而不是代码。 [...] 它不会从有效负载中提取任何代码。

事情没那么简单。 BinaryFormatter 使用程序集限定名称来标识类型。在反序列化期间,这些类型名称由Type.GetType 解析,它会愉快地加载任何程序集。因此,受操纵的流可以加载准备好的程序集,其模块初始化程序会立即执行(但恶意代码也可以放在序列化构造函数或[OnDeserializing]/[OnDeserialized] 方法中)。 This video 演示了如何利用它在浏览器中打开 PowerShell 和网页。

在任何情况下,原始帖子的答案大多是推测,关于 Java 序列化的 cmets 与 .NET 并不真正相关或真正人为的示例。

也许只是因为答案太老了,但今天有很多已知的BinaryFormatter 攻击。一些例子:

  • TempFileCollection 可被利用来删除文件(仅在 .NET Framework 中)。链接的视频(以及问题中链接的帖子)也提到了这一点。
  • StructurelEqualityComparer 可用于导致StackOverflowException 或极其缓慢的哈希码计算(DoS 攻击)。从 .NET Core 开始,此类型不再可序列化。
  • 许多未实现 ISerializable[Serializable] 类型(因此只需设置其字段即可恢复)可以使用无效数据进行初始化。
  • 即使是大多数实现ISerializable 的类型,也不会针对所有可能的攻击验证传入的SerializationInfo。例如,如果 HashSize 条目的值被操纵,Dictionary<TKey, TValue> 可以抛出 OutOfMemoryException
  • BinaryFormatter 在更深层次上也存在漏洞。例如,数组是在内部处理的(它甚至不能被代理选择器覆盖),并且操纵的长度信息也可能导致OutOfMemoryException

我实际上相信BinaryFormatter 可以变得安全。我什至在这里开了一个关于这个话题的问题:https://github.com/dotnet/runtime/issues/50909

但考虑到在实现可序列化类型时从未关注安全性,解决所有这些问题将是一项艰巨的任务,我可以理解BinaryFormatter 在未来的版本中将是obsoleted

虽然我在my binary serializer 中引入了SafeMode 选项,但只要可序列化类型本身易受攻击,它就不能完全安全。原生支持多种类型只能减少威胁(这也有利于产生very compact payload),但一般不能消除它。

结论:二进制序列化只有在序列化和反序列化在同一个进程中执行时才是安全的。在任何其他情况下,您都需要实施一些额外的安全措施(例如,通过加密方式对流进行签名)以确保完全安全。

【讨论】:

  • 七年前我会抱怨你没有回答我的问题,现在我意识到我的问题本身就是错误的。你完全正确,我的基本假设是序列化发送整个班级是错误的,但是还有许多其他方式可以以其他方式滥用BinaryFormatter。谢谢。
【解决方案2】:

序列化作用于数据,而不是代码。反序列化器从您提供的有效负载中提取数据,构造一个新的对象实例并从提取的数据中设置对象的值。它不会从有效负载中提取任何代码。

如果您的代码一开始就容易受到恶意输入的攻击,那么是的,反序列化可能是另一种攻击它的方式——就像注入恶意数据的任何其他方式一样。

例如,如果您通过连接字符串来构造 SQL 语句,那么无论字符串来自用户输入还是反序列化数据,您都将容易受到 SQL 注入攻击。解决这个问题的方法是使用参数化查询,而不是避免反序列化或尝试清理用户的输入。

在任何情况下,原始帖子的答案大多是推测,关于 Java 序列化的 cmets 与 .NET 并不真正相关或真正人为的示例。

【讨论】:

    【解决方案3】:

    BinaryFormatter 序列化字段而不是方法

    传输和加载未知代码的唯一方法是:

    1. 接收程序集并使用Assembly.Load 加载它。
    2. 使用 CodeDomProvider 在运行时发出 IL。

    【讨论】:

      猜你喜欢
      • 2012-08-12
      • 1970-01-01
      • 2011-09-30
      • 2011-01-08
      • 1970-01-01
      • 2014-12-10
      • 2013-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多