BinaryFormatter десериализует вредоносный код?

Я слышал, что есть вопросы безопасности по 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)
    {

    }
}

Так как же клиент может успешно загрузить код на мой сервер через этот вектор? Подделывая имя пространства имен и открытый ключ, заставляя сервер пытаться десериализовать его, таким образом запуская приведенный выше код? Или есть более тонкие способы сделать это?

К сожалению, эта функция является фундаментальной для моей игры, поэтому я хочу быть осторожным.


person Tom    schedule 08.01.2014    source источник
comment
Вероятно, они могут отправить вам любой из ваших собственных классов, которые помечены как сериализуемые. Я думаю, это опасно.   -  person usr    schedule 08.01.2014
comment
Требуется ли вам использовать BinaryFormatter или сериализовать ваши данные? Или сериализовать ваши данные в двоичном формате?   -  person John Saunders    schedule 08.01.2014
comment
Сериализация работает с данными, а не с кодом. Если ваш код уязвим для злонамеренного ввода, то да, это может быть еще один способ его атаки — точно так же, как и любой другой способ внедрения вредоносных данных. Кроме того, ответы на исходный пост были в основном предположениями, неприменимыми комментариями к сериализации Java или действительно надуманными примерами.   -  person Panagiotis Kanavos    schedule 08.01.2014


Ответы (3)


Сериализация работает с данными, а не с кодом. Десериализатор извлекает данные из предоставленной вами полезной нагрузки, создает новый экземпляр объекта и устанавливает значения объекта на основе извлеченных данных. Он НЕ извлекает код из полезной нагрузки.

Если ваш код в первую очередь уязвим для злонамеренного ввода, то да, десериализация может быть еще одним способом его атаки — точно так же, как и любой другой способ внедрения вредоносных данных.

Например, если вы строите операторы SQL путем объединения строк, вы будете уязвимы для атак путем внедрения кода SQL независимо от того, получены ли строки из пользовательского ввода или из десериализованных данных. Способ исправить это — использовать параметризованные запросы, а не избегать десериализации или пытаться дезинфицировать ввод пользователя.

В любом случае ответы на исходный пост были в основном предположениями, комментариями о сериализации Java, которые на самом деле не имеют отношения к .NET, или действительно надуманными примерами.

person Panagiotis Kanavos    schedule 08.01.2014

Я знаю, что это старый вопрос, но я не совсем удовлетворен принятым ответом.

Сериализация работает с данными, а не с кодом. [...] Он НЕ извлекает код из полезной нагрузки.

Это не так просто. BinaryFormatter использует полные имена сборок для идентификации типов. Во время десериализации эти имена типов разрешаются с помощью Type.GetType, который успешно загружает любые сборки. Таким образом, управляемый поток может загрузить подготовленную сборку, инициализатор модуля которой выполняется немедленно (но вредоносный код также может быть помещен в конструктор сериализации или метод [OnDeserializing]/[OnDeserialized]). В этом видео показано, как использовать это для открытия PowerShell и веб-страницы в браузере.

В любом случае ответы на исходный пост были в основном предположениями, комментариями о сериализации Java, которые на самом деле не имеют отношения к .NET, или действительно надуманными примерами.

Может быть, просто потому, что ответ слишком старый, но сегодня известно много 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 будет устарел в будущих версиях.

И хотя я представил SafeMode в моем двоичном сериализаторе, он не может быть полностью безопасно, пока сами сериализуемые типы уязвимы. Нативная поддержка многих типов может просто уменьшить угрозу (что также хорошо для создания очень компактной полезной нагрузки), но не может устранить это вообще.

Вердикт: бинарная сериализация безопасна только тогда, когда и сериализация, и десериализация выполняются в одном и том же процессе. В любом другом случае вам необходимо реализовать некоторую дополнительную безопасность (например, путем криптографической подписи потока), чтобы быть в полной безопасности.

person György Kőszeg    schedule 15.04.2021
comment
Семь лет назад я бы пожаловался, что вы не ответили на мой вопрос, теперь я понимаю, что мой вопрос сам по себе был неверным. Вы совершенно правы в том, что мое базовое предположение о том, что сериализация отправляет весь класс, было неверным, и все же есть много других способов злоупотребить BinaryFormatter другими способами. Спасибо. - person Tom; 15.04.2021

BinaryFormatter сериализует поля, а не методы.

Единственный способ передать и загрузить неизвестный код:

  1. Получите сборку и загрузите ее с помощью Assembly.Load.
  2. Используйте CodeDomProvider для генерации IL во время выполнения.
person Gusdor    schedule 08.01.2014