BinaryFormatter反序列化恶意代码?

时间:2014-01-08 08:46:21

标签: c# serialization binaryformatter

我听说有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)
    {

    }
}

那么客户端怎么能通过这个向量成功地将代码放入我的服务器?通过伪造命名空间名称和公钥,导致服务器尝试反序列化它,从而运行上面的代码?或者有更微妙的方法来做到这一点?

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

3 个答案:

答案 0 :(得分:3)

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

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

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

在任何情况下,对原始帖子的回答主要是猜测,对Java序列化的评论与.NET无关或真正做出的例子。

答案 1 :(得分:2)

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

<块引用>

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

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

<块引用>

无论如何,原始帖子的答案大多是猜测,对与 .NET 没有真正相关的 Java 序列化的评论或真正人为的示例。

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

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

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

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

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

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

答案 2 :(得分:1)

BinaryFormatter序列化字段而不是方法

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

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