mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/deserialization/basic-java-deserializati
This commit is contained in:
parent
643de1c556
commit
5c76cba27d
@ -1,15 +1,27 @@
|
|||||||
|
# Basic Java Deserialization with ObjectInputStream readObject
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
이 POST에서는 `java.io.Serializable`을 사용하는 예제를 설명합니다.
|
이 POST에서는 `java.io.Serializable`을 사용하는 예제를 설명할 것이며, **incoming stream이 공격자가 제어하는 경우 `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)으로 수행됩니다.
|
||||||
|
|
||||||
**직렬화 가능한** **Person 클래스**의 예를 살펴보겠습니다. 이 클래스는 **readObject** 함수를 **재정의**하므로, 이 **클래스**의 **어떤 객체**가 **역직렬화**될 때 이 **함수**가 **실행**됩니다.\
|
### Reminder: Which methods are implicitly invoked during deserialization?
|
||||||
예제에서 Person 클래스의 **readObject 함수**는 그의 애완동물의 `eat()` 함수를 호출하고, Dog의 `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)에서 가져온 것입니다.**
|
1. `readObject()` – 클래스별 읽기 로직(구현된 경우 및 *private*).
|
||||||
|
2. `readResolve()` – 역직렬화된 객체를 다른 객체로 대체할 수 있습니다.
|
||||||
|
3. `validateObject()` – `ObjectInputValidation` 콜백을 통해.
|
||||||
|
4. `readExternal()` – `Externalizable`을 구현하는 클래스의 경우.
|
||||||
|
5. 생성자는 **실행되지 않습니다** – 따라서 가젯 체인은 이전 콜백에만 의존합니다.
|
||||||
|
|
||||||
|
그 체인에서 공격자가 제어하는 데이터를 호출하는 메서드는(명령 실행, JNDI 조회, 리플렉션 등) 역직렬화 루틴을 RCE 가젯으로 전환합니다.
|
||||||
|
|
||||||
|
**직렬화 가능한** **Person** 클래스를 예로 들어 보겠습니다. 이 클래스는 **readObject** 함수를 재정의하므로, 이 **클래스**의 **어떤 객체**가 **역직렬화**될 때 이 **함수**가 **실행**됩니다.\
|
||||||
|
예제에서, Person 클래스의 **readObject** 함수는 그의 애완동물의 `eat()` 함수를 호출하고, Dog의 `eat()` 함수는(어떤 이유로) **calc.exe**를 호출합니다. **이 계산기를 실행하기 위해 Person 객체를 직렬화하고 역직렬화하는 방법을 살펴보겠습니다:**
|
||||||
|
|
||||||
|
**다음 예제는 <https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649>에서 가져온 것입니다.**
|
||||||
```java
|
```java
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.*;
|
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: `checkDeserExWhen*` 플래그가 활성화된 상태에서 Spring-Kafka의 오류 레코드 헤더 역직렬화로 인해 공격자가 게시한 주제로부터 임의의 가젯 구성이 가능해졌습니다. 3.0.10 / 2.9.11에서 수정됨. ¹
|
||||||
|
* 2023 – CVE-2023-36480: Aerospike Java 클라이언트의 신뢰할 수 있는 서버 가정이 깨짐 – 악의적인 서버 응답에 클라이언트에 의해 역직렬화된 직렬화된 페이로드가 포함됨 → RCE. ²
|
||||||
|
* 2023 – CVE-2023-25581: `pac4j-core` 사용자 프로필 속성 파싱이 `{#sb64}`로 접두사가 붙은 Base64 블롭을 수용하고 `RestrictedObjectInputStream`에도 불구하고 이를 역직렬화했습니다. 4.0.0 이상으로 업그레이드하십시오.
|
||||||
|
* 2023 – CVE-2023-4528: JSCAPE MFT Manager Service (포트 10880)가 XML 인코딩된 Java 객체를 수용하여 root/SYSTEM으로 RCE를 초래했습니다.
|
||||||
|
* 2024 – Hibernate5, TomcatEmbed 및 SnakeYAML 2.x 클래스를 포함한 여러 새로운 가젯 체인이 ysoserial-plus(mod)에 추가되어 일부 오래된 필터를 우회합니다.
|
||||||
|
|
||||||
|
## 배포해야 할 현대적 완화책
|
||||||
|
|
||||||
|
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<ObjectInputFilter>`를 사용하여 실행 컨텍스트(예: RMI 호출당, 메시지 큐 소비자당)마다 다른 필터를 적용합니다.
|
||||||
|
3. **원시 `ObjectInputStream`을 네트워크에 노출하지 마십시오** – 코드 실행 의미가 없는 JSON/이진 인코딩을 선호하십시오 (Jackson에서 `DefaultTyping` 비활성화 후, Protobuf, Avro 등).
|
||||||
|
4. **심층 방어 한계** – 최대 배열 길이, 깊이, 참조 설정:
|
||||||
|
```bash
|
||||||
|
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
|
||||||
|
```
|
||||||
|
5. **지속적인 가젯 스캐닝** – CI에서 `gadget-inspector` 또는 `serialpwn-cli`와 같은 도구를 실행하여 위험한 가젯이 접근 가능해지면 빌드를 실패하게 합니다.
|
||||||
|
|
||||||
|
## 업데이트된 도구 치트 시트 (2024)
|
||||||
|
|
||||||
|
* `ysoserial-plus.jar` – > 130개의 가젯 체인을 가진 커뮤니티 포크:
|
||||||
|
```bash
|
||||||
|
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0
|
||||||
|
```
|
||||||
|
* `marshalsec` – JNDI 가젯 생성을 위한 여전히 참고 자료 (LDAP/RMI).
|
||||||
|
* `gadget-probe` – 네트워크 서비스에 대한 빠른 블랙박스 가젯 발견.
|
||||||
|
* `SerialSniffer` – `ObjectInputStream`에 의해 읽힌 모든 클래스를 출력하는 JVMTI 에이전트 (필터를 작성하는 데 유용).
|
||||||
|
* **탐지 팁** – 필터 결정 및 거부된 클래스를 기록하기 위해 `-Djdk.serialDebug=true` (JDK 22+)를 활성화하십시오.
|
||||||
|
|
||||||
|
## 안전한 `readObject()` 구현을 위한 빠른 체크리스트
|
||||||
|
|
||||||
|
1. 메서드를 `private`로 만들고 `@Serial` 주석을 추가하십시오 (정적 분석에 도움이 됩니다).
|
||||||
|
2. 사용자 제공 메서드를 호출하거나 메서드 내에서 I/O를 수행하지 마십시오 – 필드만 읽으십시오.
|
||||||
|
3. 검증이 필요한 경우, 역직렬화 **후에** `readObject()` 외부에서 수행하십시오.
|
||||||
|
4. `Externalizable`을 구현하고 기본 직렬화 대신 명시적 필드 읽기를 선호하십시오.
|
||||||
|
5. 내부 서비스에 대해서도 강화된 `ObjectInputFilter`를 등록하십시오 (타협 저항 설계).
|
||||||
|
|
||||||
|
## 참고 문헌
|
||||||
|
|
||||||
|
1. Spring Security Advisory – CVE-2023-34040 Java Deserialization in Spring-Kafka (2023년 8월)
|
||||||
|
2. GitHub Security Lab – GHSL-2023-044: Unsafe Deserialization in Aerospike Java Client (2023년 7월)
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user