Удаленное выполнение кода при десериализации в Java
От: maxkar  
Дата: 14.12.15 19:46
Оценка: 11 (2)
Всем доброго времени суток.

Сегодня наткнулся на интересную тему. Если Java-приложение использует определенные библиотеки и десериализует объекты из сети, оно подвержено удаленному выполнению кода. При этом уязвимость не имеет никакого отношения к buffer overflow и прочим проблемам в реализации десериализатора.

Подробности: здесь, здесь и здесь.

Для ленивых, тезисно:
1. В Java есть сериализация и десериализация объектов в бинарной форме.
2. Она восстанавливает объекты с правильным (исходным) типом.
3. Этот механизм настраиваем и позволяет типам задавать свои сериализаторы/десериализаторы.
4. В apache-common-collections и некоторых других библиотеках это настройка (кастомизация) выполняет код, пришедший в данных (там не машинный код, а некий аналог байт-кода java, но не принципиально). Да, так было задумано разработчиками.
5. Можно сделать запрос, который выполняет непотребные вещи вроде Runtime.exec("calc.exe") и т.п. Причем запрос можно делать к любому сервису, использующему десериализацию.

Что необычно. Для использования уязвимости не обязательно вызывать "уязвимую библиотеку" в коде. Достаточно наличия ее в classpath (в пути загрузки библиотек). Т.е. был у нас какой-то банальный RPC-сервис, и все было хорошо. Добавили apache-common-collections (даже не используя ее) — уязвимость появилась.

Сопутствующие факторы для уязвимости (полезно при дизайне/использовании своего API):
1. API десериализации. Это ObjectInputStream.readObject(). Нельзя указать целевой класс (т.е. любой сервис с десериализацией уязвим, даже если он ожидает простые и безопасные объекты).
2. Широкий полиморфизм. Т.е. наличие в структуре данных Object[] тоже позволит десериализовывать произвольные объекты (в том числе — и в "уязвимых" классах). Этим часто RPC-подобные сервисы грешат, восстанавливая параметры.
3. Запуск кода из десериализатора (да и вообще чего-то, полученного из сети). Это основная проблема. Другими мерами не лечится.

Ну и немного не по теме. Хочется высказать свое "фи" сборкам библиотек вроде dropwizard, spring boot и подобным "средам быстрого старта". Оно, конечно, позволяет что-то сделать на коленке и запустить. Но вот потом становится сложно. Ни отдельную библиотеку не обновить (не поймешь, используется ли она и что отвалится). Ни аудит нормальный не провести при необходимости. Где там у них список сервисов доступных по-умолчанию? И что вообще сконфигурировано а что — нет. Как вот я должен узнавать, включен у них JMX (одна из уязвимых штук) для удобства разработчиков, или все же нет?
Re: Удаленное выполнение кода при десериализации в Java
От: vsb Казахстан  
Дата: 14.12.15 20:11
Оценка:
А нельзя запускать этот код в "песочнице"?

Вообще вся эта встроенная сериализация/десериализация — сомнительное дело, слишком перемудрили. Только между доверенными узлами гонять или на диск сохранять, имхо. Да и то вроде там скорость совсем не впечатляет, вообще непонятно, зачем оно нужно. Для любых внешних взаимодействий надо использовать простые решения вроде XML/JSON/...
Re: Удаленное выполнение кода при десериализации в Java
От: Ops Россия  
Дата: 15.12.15 03:00
Оценка:
Здравствуйте, maxkar, Вы писали:

M> 5. Можно сделать запрос, который выполняет непотребные вещи вроде Runtime.exec("calc.exe") и т.п. Причем запрос можно делать к любому сервису, использующему десериализацию.


Так метод борьбы очевиден — только проверенные источники. А то так и возможность пересылать по почте исполняемые файлы можно уязвимостью почты назвать.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: Удаленное выполнение кода при десериализации в Java
От: drVanо Россия https://vmpsoft.com
Дата: 15.12.15 03:54
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Сегодня наткнулся на интересную тему. Если Java-приложение использует определенные библиотеки и десериализует объекты из сети, оно подвержено удаленному выполнению кода. При этом уязвимость не имеет никакого отношения к buffer overflow и прочим проблемам в реализации десериализатора.


Напомнило анекдот:
— Доктор, а вот когда я так делаю мне больно!
— А вы так не делайте!
Re: Удаленное выполнение кода при десериализации в Java
От: Слава  
Дата: 18.12.15 02:54
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Всем доброго времени суток.



M> 5. Можно сделать запрос, который выполняет непотребные вещи вроде Runtime.exec("calc.exe") и т.п. Причем запрос можно делать к любому сервису, использующему десериализацию.


Извиняюсь за нубский вопрос, а разве в java нет какого-то аналога CAS из дотнета? То есть, некая ветка кода может делать только то, что разрешено коду выше по стеку.
Re[2]: Удаленное выполнение кода при десериализации в Java
От: maxkar  
Дата: 24.12.15 13:37
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>А нельзя запускать этот код в "песочнице"?

Чисто теоретически — можно. Но там нужно специально лишние телодвижения делать. Плюс оно вроде бы работает на основе имен классов а не стека. Лишние сложности.

vsb>Вообще вся эта встроенная сериализация/десериализация — сомнительное дело, слишком перемудрили. Только между доверенными узлами гонять или на диск сохранять, имхо. Да и то вроде там скорость совсем не впечатляет, вообще непонятно, зачем оно нужно. Для любых внешних взаимодействий надо использовать простые решения вроде XML/JSON/...

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

Там проблема даже не в формате сериализации. Проблема в том, что сериализация расширяема кастомными методами и при этом есть поддержка полиморфизма. Если разрешить кастомные сериализаторы и полиморфизм, можно и на XML подобную уявзимость сделать.

В коде будет примерно так:
@Serializer(CommandSerializer)
class Command {
  public String commandText;
}

class CommandSerializer {
  public static Element serialize(Command command) {
    return XMLSerializer.defaultSerialize(command);
  }

  public static Command deserialize(Element xml) {
    final Command res = XMLSerializer.defaultDeserialize(Command.class, xml);
    Runtime.exec(res.commandText);
    return res;
  }
}

class Payload {
  @Polymorphic
  public Object[] items;
}


И можно посылать следующий XML:
<payload>
  <items>
    <command class="com.test.Command">
      <commandText>calc.exe</commandText>
    </command>
  </items>
</payload>


Кастомные сериализаторы сами по себе не так плохи. Они нужны для сохранения совместимости данных между разными версиями (в JSON/XML тоже понадобились бы при изменении внутренней структуры класса). И полиморфизм удобен (можно коллекцию различных объектов передавать, конкретных наследников и т.п.). Хотя вот как раз полиморфизм стоило бы делать ограниченным.

Проблема появляется, когда к полезным фичам добавляется "кастомный десериализатор" с выполнением команд (CommandSerializer). Вот он присутствует (присутствовал) в apache commons. И в комбинации с другими факторами и получилось то, что получилось.

А так я полностью согласен. Простые форматы вроде JSON/XML рулят. Я даже сериализацию делаю по-возможности вручную и весь "полиморфизм" закрытый, т.е. список "возможных типов" в каждой точке сериализации известен и ограничен.
Re[2]: Удаленное выполнение кода при десериализации в Java
От: maxkar  
Дата: 24.12.15 13:42
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>А то так и возможность пересылать по почте исполняемые файлы можно уязвимостью почты назвать.

Сама по себе возможность — нет. А вот если какой-то почтовый клиент (или плагин к клиенту) станет автоматически выполнять приложенные файлы — будет уязвимость. apache commons содержат такой "плагин", который автоматически выполняет команды из "писем в определенном формате".
Re[2]: Удаленное выполнение кода при десериализации в Java
От: maxkar  
Дата: 24.12.15 13:48
Оценка:
Здравствуйте, Слава, Вы писали:

С>Извиняюсь за нубский вопрос, а разве в java нет какого-то аналога CAS из дотнета? То есть, некая ветка кода может делать только то, что разрешено коду выше по стеку.


Есть. Называется SecurityManager. Но он "глобальный" для приложения. Может быть, можно и на время метода настроить (там есть различные контексты и AccessController).

Но JSON/XML и десериализация в указанный целевой тип обычно гораздо проще в реализации и преподносят потом меньше сюрпризов.
Re: Удаленное выполнение кода при десериализации в Java
От: woah  
Дата: 01.02.16 22:43
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Всем доброго времени суток.


M>Сегодня наткнулся на интересную тему. Если Java-приложение использует определенные библиотеки и десериализует объекты из сети, оно подвержено удаленному выполнению кода. При этом уязвимость не имеет никакого отношения к buffer overflow и прочим проблемам в реализации десериализатора.


Проблема называется

https://www.owasp.org/index.php/Deserialization_of_untrusted_data

И известно давно, не только в яве
https://cwe.mitre.org/data/definitions/502.html
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.