Serialization & Deserialization

hjkim·2022년 6월 11일
1

Serialization & Deserialization

객체의 직렬화란 객체를 바이트 스트림으로 인코딩(serialization)하고 그 바이트 스트림으로부터 다시 객체를 재구성(deserialization)하는 메커니즘을 의미한다.
serialized 객체는 다른 VM에 전송하거나 디스크에 저장한 후 deserialize 할 수 있다.
각 PC의 OS마다 서로 다른 메모리 주소 공간을 갖기 때문에 Reference Type의 데이터들은 인스턴스를 전달할 수 없다. 이런 문제를 해결하고자 주소값이 아닌 byte 형태로 객체를 직렬화하여 데이터를 전달하는 것이다.

Serialization 구현

public class Post implements Serializable {
	private static final long serialVersionUID = 1L;
    
    private String title;
    private String content;
}
Post post = new Post("타이틀", "내용");
byte[] serializedPost;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
	try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
    	oos.writeObject(post);
        serializedPost = baos.toByteArray();
    }
}

Post 객체 내부에 serialVersionUID를 지정하지 않을 경우 추후 Post 객체의 멤버 변수가 추가/삭제될 경우 serialVersionUID 값이 새롭게 생성된 해쉬값으로 자동 할당되어 역직렬화 했을 때 InvalidClassException이 발생한다. 서로 다른 객체로 인식되기 때문이다. serialVersionUID를 같도록 설정하여도 멤버변수의 타입이 다를 경우 ClassCastException이 발생한다.

Deserialization 구현

try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedPost)) {
	try (ObjectInputStream ois = new ObjectInputStream(bais)) {
    	Object objectPost = ois.readObject();
        // 여기서부터 customize 코드 작성 가능
        Runtime.getRuntime().exec(this.command);
        Post post = (Post) objectPost;
        ...
    }
}

보안 이슈

공격자는 서버 측에 존재하는 class 중에서 임의의 메소드(주로 Runtime.exec)를 실행할 수 있도록 작성된 취약한 class가 존재할 경우 공격을 실행할 수 있다.

AnnotationInvocationHandler에서 발생한 Java Deserialization 취약점에 대해 살펴본다. AnnotationInvocationHandler 클래스는 Deserialization 과정에서 customize 코드를 통해 다양한 class들과 연결되는데 이 과정을 통해 InvokerTransformer 클래스에 접근할 수 있다.

InvokerTransformer 클래스는 인스턴스를 생성할 수 있는 클래스로, 공격자는 이 InvokerTransformer 클래스 함수에 "getMethod", "invoke", "getRuntime", "exec" 등의 문자열이 전달되는 클래스 인스턴스를 생성하고 이 클래스를 Serialize 하여 전송한다.

수신하는 서버에서는 이 객체가 Deserialize 되면서 AnnotationInvocationHandler 클래스의 readObject 메소드가 호출되고 공격자가 만든 클래스로부터 전달되는 문자열을 받아 시스템 명령어를 계속 실행시키게 된다.

해결 방안

  1. Deserialization 이전 반드시 인증 과정 수행할 것
  2. 출처를 알 수 없는 객체의 경우 역직렬화 수행하지 않을 것
  3. Serialize 된 객체에 디지털 서명이 되도록 하여 Deserialize 과정에서 객체의 변조 여부 점검할 것

[참조] https://gyoogle.dev/blog/computer-language/Java/Serialization.html
[참조] https://techblog.woowahan.com/2551/
[참조] https://blog.maxtive.co.kr/12
[참조] https://rsy99.tistory.com/61
[참조] https://m.blog.naver.com/skinfosec2000/220887425296

profile
피드백은 언제나 환영입니다! :)

0개의 댓글