diff --git a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md index c2dabd15c..b03581c0c 100644 --- a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md +++ b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md @@ -1,15 +1,27 @@ +# Basic Java Deserialization with ObjectInputStream readObject + {{#include ../../banners/hacktricks-training.md}} -У цьому POST буде пояснено приклад використання `java.io.Serializable`. +У цьому POST буде пояснено приклад використання `java.io.Serializable` **і чому перевизначення `readObject()` може бути надзвичайно небезпечним, якщо вхідний потік контролюється атакуючим**. -# Serializable +## Serializable -Java `Serializable` інтерфейс (`java.io.Serializable` є маркерним інтерфейсом, який ваші класи повинні реалізувати, якщо вони повинні бути **серіалізовані** та **десеріалізовані**. Серіалізація об'єктів Java (запис) виконується за допомогою [ObjectOutputStream](http://tutorials.jenkov.com/java-io/objectoutputstream.html), а десеріалізація (читання) виконується за допомогою [ObjectInputStream](http://tutorials.jenkov.com/java-io/objectinputstream.html). +Java `Serializable` інтерфейс (`java.io.Serializable`) є маркерним інтерфейсом, який ваші класи повинні реалізувати, якщо вони мають бути **серіалізовані** та **десеріалізовані**. Серіалізація об'єктів Java (запис) виконується за допомогою [`ObjectOutputStream`](http://tutorials.jenkov.com/java-io/objectoutputstream.html), а десеріалізація (читання) виконується за допомогою [`ObjectInputStream`](http://tutorials.jenkov.com/java-io/objectinputstream.html). + +### Нагадування: Які методи імпліцитно викликаються під час десеріалізації? + +1. `readObject()` – специфічна для класу логіка читання (якщо реалізована та *приватна*). +2. `readResolve()` – може замінити десеріалізований об'єкт на інший. +3. `validateObject()` – через зворотні виклики `ObjectInputValidation`. +4. `readExternal()` – для класів, що реалізують `Externalizable`. +5. Конструктори **не** виконуються – тому ланцюги гаджетів покладаються виключно на попередні зворотні виклики. + +Будь-який метод у цьому ланцюзі, який в кінцевому підсумку викликає дані, контрольовані атакуючим (виконання команд, запити JNDI, рефлексія тощо), перетворює рутину десеріалізації на гаджет RCE. Давайте розглянемо приклад з **класом Person**, який є **серіалізованим**. Цей клас **перезаписує функцію readObject**, тому коли **будь-який об'єкт** цього **класу** буде **десеріалізований**, ця **функція** буде **виконана**.\ -У прикладі **функція readObject** класу Person викликає функцію `eat()` його домашньої тварини, а функція `eat()` собаки (з якоїсь причини) викликає **calc.exe**. **Ми побачимо, як серіалізувати та десеріалізувати об'єкт Person, щоб виконати цей калькулятор:** +У прикладі функція **readObject** класу Person викликає функцію `eat()` його домашньої тварини, а функція `eat()` собаки (з якоїсь причини) викликає **calc.exe**. **Ми побачимо, як серіалізувати та десеріалізувати об'єкт Person, щоб виконати цей калькулятор:** -**Наступний приклад з [https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649](https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649)** +**Наступний приклад взято з ** ```java import java.io.Serializable; import java.io.*; @@ -80,8 +92,63 @@ payloadTest("test.ser"); } } ``` -## Висновок +### Висновок (класичний сценарій) -Як ви можете побачити в цьому дуже простому прикладі, "вразливість" тут виникає тому, що функція **readObject** **викликає інші вразливі функції**. +Як ви можете бачити в цьому дуже базовому прикладі, "вразливість" тут виникає через те, що метод **readObject()** **викликає інший код, контрольований атакуючим**. У реальних ланцюгах гаджетів тисячі класів, що містяться в зовнішніх бібліотеках (Commons-Collections, Spring, Groovy, Rome, SnakeYAML тощо), можуть бути зловживані – атакуючому потрібен лише *один* досяжний гаджет для отримання виконання коду. + +--- + +## 2023-2025: Що нового в атаках десеріалізації Java? + +* 2023 – CVE-2023-34040: десеріалізація заголовків записів помилок Spring-Kafka, коли увімкнені прапорці `checkDeserExWhen*`, дозволила довільне створення гаджетів з тем, опублікованих атакуючими. Виправлено в 3.0.10 / 2.9.11. ¹ +* 2023 – CVE-2023-36480: порушено припущення про довірений сервер Java-клієнта Aerospike – зловмисні відповіді сервера містили серіалізовані корисні навантаження, які були десеріалізовані клієнтом → RCE. ² +* 2023 – CVE-2023-25581: парсинг атрибутів профілю користувача `pac4j-core` приймав Base64 блохи з префіксом `{#sb64}` і десеріалізував їх, незважаючи на `RestrictedObjectInputStream`. Оновлення ≥ 4.0.0. +* 2023 – CVE-2023-4528: JSCAPE MFT Manager Service (порт 10880) приймав XML-кодовані Java-об'єкти, що призводило до RCE як root/SYSTEM. +* 2024 – до ysoserial-plus(mod) додано кілька нових ланцюгів гаджетів, включаючи класи Hibernate5, TomcatEmbed і SnakeYAML 2.x, які обходять деякі старі фільтри. + +## Сучасні заходи, які ви повинні впровадити + +1. **JEP 290 / Фільтрація серіалізації (Java 9+)** +*Додайте список дозволених або заборонених класів:* +```bash +# Приймати лише ваші DTO та java.base, відхиляти все інше +-Djdk.serialFilter="com.example.dto.*;java.base/*;!*" +``` +Приклад програмного коду: +```java +var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" ); +ObjectInputFilter.Config.setSerialFilter(filter); +``` +2. **JEP 415 (Java 17+) Фабрики фільтрів, специфічні для контексту** – використовуйте `BinaryOperator`, щоб застосовувати різні фільтри для кожного контексту виконання (наприклад, для кожного виклику RMI, для кожного споживача черги повідомлень). +3. **Не піддавайте сирий `ObjectInputStream` через мережу** – надавайте перевагу JSON/бінарним кодуванням без семантики виконання коду (Jackson після відключення `DefaultTyping`, Protobuf, Avro тощо). +4. **Обмеження захисту в глибині** – встановіть максимальну довжину масиву, глибину, посилання: +```bash +-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000" +``` +5. **Безперервне сканування гаджетів** – запускайте інструменти, такі як `gadget-inspector` або `serialpwn-cli` у вашій CI, щоб зупинити збірку, якщо небезпечний гаджет стає досяжним. + +## Оновлений чек-лист інструментів (2024) + +* `ysoserial-plus.jar` – спільний форк з > 130 ланцюгами гаджетів: +```bash +java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0 +``` +* `marshalsec` – все ще еталон для генерації гаджетів JNDI (LDAP/RMI). +* `gadget-probe` – швидке виявлення гаджетів чорного ящика проти мережевих сервісів. +* `SerialSniffer` – агент JVMTI, який друкує кожен клас, прочитаний `ObjectInputStream` (корисно для створення фільтрів). +* **Порада з виявлення** – увімкніть `-Djdk.serialDebug=true` (JDK 22+), щоб записувати рішення фільтра та відхилені класи. + +## Швидкий чек-лист для безпечних реалізацій `readObject()` + +1. Зробіть метод `private` і додайте анотацію `@Serial` (допомагає статичному аналізу). +2. Ніколи не викликайте методи, надані користувачем, або не виконуйте I/O у методі – лише читайте поля. +3. Якщо потрібна валідація, виконуйте її **після** десеріалізації, поза `readObject()`. +4. Віддавайте перевагу реалізації `Externalizable` і виконуйте явні читання полів замість стандартної серіалізації. +5. Зареєструйте посилений `ObjectInputFilter` навіть для внутрішніх сервісів (дизайн, стійкий до компрометацій). + +## Посилання + +1. Консультація з безпеки Spring – CVE-2023-34040 Десеріалізація Java в Spring-Kafka (серпень 2023) +2. GitHub Security Lab – GHSL-2023-044: Небезпечна десеріалізація в Java-клієнті Aerospike (липень 2023) {{#include ../../banners/hacktricks-training.md}}