Notice
Recent Posts
Recent Comments
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
07-12 14:27
Today
Total
관리 메뉴

해킹공주의 일상

자바 역직렬화 취약점 | 05.05 신뢰할 수 없는 데이터의 역직렬화 본문

소스코드 진단

자바 역직렬화 취약점 | 05.05 신뢰할 수 없는 데이터의 역직렬화

7.3.7 2024. 4. 19. 14:40

개요

진단 중 개념이해가 필요해서 정리했다.. 사람이 이래서 벼랑끝에 서봐야한다

 

직렬화와 역직렬화 ?

기본적으로 직렬화가 왜 필요한지, 직렬화가 뭔지는 아래 포스팅에 작성해 두었으니 참고 바란다.

https://7-3-7.tistory.com/264

 

[JAVA] 직렬화와 역직렬화

개요 진단하는데 내용을 도저히 모르겠어서 개념부터 정리해본다.. 정의 직렬화 객체 데이터를 연속적인 데이터, 즉 바이트 스트림으로 변형해서 전송가능한 형태로 만드는것. 역직렬화 직렬화

7-3-7.tistory.com

 

💡 요약 💡

직렬화는 객체를 저장하거나 네트워크를 통해 전송하기 위해 바이트 스트림으로 변환하는 것이며, 역직렬화는 그 바이트 스트림을 다시 객체로 변환하여 사용할 수 있도록 하는 것이다. 이를 통해 자바 시스템 간에 데이터를 효율적으로 공유하고 전달할 수 있다.

 

어떻게 역직렬화 취약점이 발생하는가

네트워크를 통해 직렬화된 바이트 스트림을 수신하면 수신한 쪽에서는 역직렬화를 통해 해당 데이터를 복원하게된다. 객체의 바이트 스트림을 다시 객체로 변환하는 과정, 즉 역직렬화에서 해당 객체의 생성자가 호출되고, 필요한 초기화 작업이 수행될 수 있다. 따라서 역직렬화를 수행하는 동안에는 객체의 생성자나 초기화 블록 등이 실행될 수 있는데, 만약 전달받은 코드에 악성 코드가 삽입되어있다면 함께 실행될 수 있다. 

 

쉽게 말하면 Student라는 클래스에 값을 담아서 전달하고 있었는데, 뜬금없이 다른 값 혹은 다른 클래스를 보내거나, 클래스 값을 변조해서 악성코드를 담아서 보내거나 하는 행위를 수행한다고 보면 쉽다.

 

🔪 공격 방법(예시) 🔪

1. 웹 어플리케이션에서 입력값을 통해 직렬화되는 값을 직접 변조하여 전달

2. 중간자 공격을 통해 중간에서 직렬화 패킷을 변조

 

실제 예시는 아래 게시글을 참고하자.

Burpsuite에 존재하는 Deserialization Scanner를 통해서 해당 취약점을 진단해볼 수 있다.

https://www.lgcns.com/blog/cns-tech/security/3139/

 

[RED팀] 역직렬화 취약점, 이렇게 하면 극복 가능! - LG CNS

최근 마이크로소프트가 익스체인지 서버(Exchange Server)에 알려지지 않은 네 가지 취약점에 대해 긴급 패치를 발표했습니다. 이번 패치에는 서버에서 시스템 권한으로 원격 코드를 실행할 수 있는

www.lgcns.com

 

따라서 역직렬화를 수행하는 과정에서는 안전하지 않은 코드나 외부로부터의 악의적인 입력에 대한 검증이 필요하다. 외부로부터의 데이터를 역직렬화할 때에는 보안 상의 위험이 있을 수 있으므로, 신뢰할 수 있는 소스에서의 데이터만을 역직렬화하는 것이 중요하다고 볼 수 있다.

 

어떻게 대응해야하나?

대응 방안은 아래 3가지로 나뉜다. 

아래 3가지 대응방안 모두 적용되어야 역직렬화 공격 위험을 낮출 수 있다. 

 

1. 지속적인 보안 패치

취약점에 대한 보안 패치가 발표되었을 때 이를 빠르게 적용해야한다.

 

2. 송수신 데이터 암 복호화 또는 서명 추가
송신 측에서 데이터를 암호화하고, 수신 측에서 복호화하거나 데이터에 대한 서명을 추가한다. 이를 확인하는 과정을 통해 무결성 검증을 거치면 중간자에 의한 객체 변조를 어렵게 할 수 있다. 보통 SSL/TLS 통신을 구현하는 방식을 사용한다. 행안부 가이드 예제에서는 서명값을 추가하라고 하는데 하나하나 서명값 추가하는게 더 복잡하지않을까 싶다. 만약 암호화 통신이 어려울 경우에는 서명값을 추가해서 송신/수신 하도록 한다.

 

3. 입력 값 유효성 검사
웹 애플리케이션에서 자체적으로 역직렬화를 수행하는 경우, 공격자가 전송한 임의의 객체를 역직렬화하지 못하도록 화이트리스트 또는 블랙리스트 방식으로 입력 값을 검증해야 한다.

 

(예시)
- 바이트 수를 제한한 입력 스트림 생성
- 클래스 체크 및 개체 수를 제한하여 오브젝트 생성
- 검증을 통과한 오브젝트를 읽어 객체로 변환 후 리턴

 

아래 방법은 전달받아서 역직렬화를 진행하는 클래스에 대한 유효성을 검증하는 시큐어 코딩을 적용한 예시이다. 

 

안전하지않은 코드

전달받은 ois 라는 객체에 대해서 필터링 안하고 바로 역직렬화 하고 있어서 보안상 문제가 있다.

해당 값에 대해 화이트리스트를 통한 검증이 필요하다.

class DeserializeExample {
public static Object deserialize(byte[] buffer)
throws IOException, ClassNotFoundException {
Object ret = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(buffer)) {
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
	ret = ois.readObject(); // 여기서 필터링없이 바로 역직렬화 수행하는게 문제
			}
		}
return ret;
	}
}

 

 

안전한 코드

아래 코드에서는 전달받은 클래스에 대해 화이트리스트로 검증하고 있으므로 안전하다.

public class WhitelistedObjectInputStream extends ObjectInputStream {
public Set<String> whitelist;
// WhilelistedObjectInputStream을 생성할 때 화이트리스트를 입력받는다.
public WhitelistedObjectInputStream(InputStream inputStream, Set<String> wl)
throws IOException {
super(inputStream);
whitelist = wl;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass cls) throws IOException,
ClassNotFoundException {
// ObjectStreamClass의 클래스명이 화이트리스트에 있는지 확인한다.
if (!whitelist.contains(cls.getName())) {
throw new InvalidClassException("Unexpected serialized class", cls.getName());
		}
	return super.resolveClass(cls);
	}
}
    
    
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public Student upload(@RequestParam("file") MultipartFile multipartFile)
throws ClassNotFoundException, IOException {
	Student student = null;
	File targetFile = new File("/temp/" + multipartFile.getOriginalFilename());
	// 역직렬화 대상 클래스 이름의 화이트리스트 생성한다.
	Set<String> whitelist = new HashSet<String>(Arrays.asList(
	new String[] { 
		"Student"
	}));
	try (InputStream fileStream = multipartFile.getInputStream()) {
		try (WhitelistedObjectInputStream ois = 
			new WhitelistedObjectInputStream(fileStream, whitelist)) {
			// 화이트리스트에 없는 역직렬화 데이터의 경우 예외 발생시킨다. 
			student = (Student) ois.readObject();
			}
	} 
	return student;
}

 

역직렬화를 해야 클래스 이름을 다 알아오는게 아닌가, 싶었는데 직렬화된 데이터 맨앞에 보통 클래스 명이 있어서 역직렬화 하기 전에 먼저 뽑아서 확인할 수 있다고 한다. 맨첫번째꺼뽑아서 확인하면 되겠다.

 

클래스 내부 값을 변조하면 어떻게 대응해야하는가 ?

위와 같은 화이트리스트에도 한계가 존재한다. 그에대한 여러가지 방어 기법이 있는데, 해당 내용은 아래 게시글을 참고하길 바란다..

https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EA%B0%9D%EC%B2%B4-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94-%EB%B0%A9%EC%96%B4-%EA%B8%B0%EB%B2%95-%EC%B4%9D%EC%A0%95%EB%A6%AC-%EB%AA%A8%EC%9D%8C

 

☕ 자바 역직렬화 방어 기법 - 총정리 모음

Serializable 구현은 보안에 구멍이 생길 수 있다 보통 자바에서 인스턴스는 생성자를 이용해 만든는 것이 기본이다. 하지만 역직렬화는 언어의 기본 메커니즘을 우회하여 객체를 바로 생성하도록

inpa.tistory.com

 

 

어떻게 진단해야하나?

 

1번 보안패치는 관리적 측면에서 수행할 수 있는 내용이고, 2번은 일괄적으로 적용하면 되는 내용이다. 3번 입력값 검증 유효성 검사는 우리가 실질적으로 확인하고 적용되어있지 않다면 수정이 필요하다. 위에서 말했듯 위 3가지 대응방안 모두 적용되어야 역직렬화 취약점으로부터 안전하다고 볼 수 있다.  따라서 먼저 SSL/TLS통신을 사용하고 있는지 확인하고, 역직렬화 되는 값이 입력값 검증을 수행하고 있는지 확인한다. 만약 두 조건 모두 충족하지 않는다면 보안상 취약하다고 판단한다. (SSL/TLS 통신을 하고 있으나 사용자 입력값이 아닐경우 제외처리) 

Comments