Basic Java Deserialization with ObjectInputStream readObject

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

이 POST에서는 java.io.Serializable을 사용하는 예제를 설명할 것이며, incoming stream이 공격자가 제어하는 경우 readObject()를 재정의하는 것이 얼마나 위험할 수 있는지에 대해 설명할 것입니다.

Serializable

Java Serializable 인터페이스(java.io.Serializable)는 클래스가 직렬화역직렬화되기 위해 구현해야 하는 마커 인터페이스입니다. Java 객체 직렬화(쓰기)는 ObjectOutputStream으로 수행되며, 역직렬화(읽기)는 ObjectInputStream으로 수행됩니다.

Reminder: Which methods are implicitly invoked during deserialization?

  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
import java.io.Serializable;
import java.io.*;

public class TestDeserialization {
interface Animal {
public void eat();
}
//Class must implements Serializable to be serializable
public static class Cat implements Animal,Serializable {
@Override
public void eat() {
System.out.println("cat eat fish");
}
}
//Class must implements Serializable to be serializable
public static class Dog implements Animal,Serializable {
@Override
public void eat() {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("dog eat bone");
}
}
//Class must implements Serializable to be serializable
public static class Person implements Serializable {
private Animal pet;
public Person(Animal pet){
this.pet = pet;
}
//readObject implementation, will call the readObject from ObjectInputStream  and then call pet.eat()
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
pet = (Animal) stream.readObject();
pet.eat();
}
}
public static void GeneratePayload(Object instance, String file)
throws Exception {
//Serialize the constructed payload and write it to the file
File f = new File(file);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
out.flush();
out.close();
}
public static void payloadTest(String file) throws Exception {
//Read the written payload and deserialize it
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Object obj = in.readObject();
System.out.println(obj);
in.close();
}
public static void main(String[] args) throws Exception {
// Example to call Person with a Dog
Animal animal = new Dog();
Person person = new Person(animal);
GeneratePayload(person,"test.ser");
payloadTest("test.ser");
// Example to call Person with a Cat
//Animal animal = new Cat();
//Person person = new Person(animal);
//GeneratePayload(person,"test.ser");
//payloadTest("test.ser");
}
}

결론 (고전 시나리오)

이 매우 기본적인 예에서 볼 수 있듯이, 여기서의 “취약점”은 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);
  1. JEP 415 (Java 17+) 컨텍스트별 필터 팩토리BinaryOperator<ObjectInputFilter>를 사용하여 실행 컨텍스트(예: RMI 호출당, 메시지 큐 소비자당)마다 다른 필터를 적용합니다.
  2. 원시 ObjectInputStream을 네트워크에 노출하지 마십시오 – 코드 실행 의미가 없는 JSON/이진 인코딩을 선호하십시오 (Jackson에서 DefaultTyping 비활성화 후, Protobuf, Avro 등).
  3. 심층 방어 한계 – 최대 배열 길이, 깊이, 참조 설정:
bash
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
  1. 지속적인 가젯 스캐닝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 – 네트워크 서비스에 대한 빠른 블랙박스 가젯 발견.
  • SerialSnifferObjectInputStream에 의해 읽힌 모든 클래스를 출력하는 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월)

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기