
CVE-2023-46604에 대한 심층 기술 분석, Apache ActiveMQ의 OpenWire 프로토콜에 존재하는 RCE 취약점으로, 패킷 구조 분석 및 익스플로잇 메커니즘을 포함합니다.
ActiveMQ는 JMS를 지원하는 클라이언트를 포함하는 브로커, 자바 뿐만 아니라 다양한 언어를 이용하는 시스템 간 의 통신을 할 수 있게해준다. 또한 클러스터링 기능 및 DB 그리고 FileSystem을 통해 각 시스템간의 일관성 및 지속성을 유지 시켜주는 오픈 소스 메세징 그리고 통합 패턴 서버 입니다.
OpenWire는 Apache ActiveMQ에서 사용되는 이진 메시징 프로토콜 입니다. 브로커(ActiveMQ)와 클라이언트 간의 효율적인 데이터 전송을 위해 설계 되었습니다.
CVE-2023-46604는 ActiveMQ에서 OpenWire 프로토콜(Marshal과정에) 취약성은 Java 기반 OpenWire 브로커 또는 클라이언트에 대한 네트워크 액세스 권한이 있는 원격 공격자가 OpenWire 프로토콜에서 직렬화된 클래스 유형을 조작하여 임의의 셸 명령을 실행하여 클라이언트 또는 브로커(각각)가 클래스 경로에 있는 모든 클래스를 인스턴스화 하도록 할 수 있으며 APT 그룹 Andariel의 대표적으로 사용한 공격 방식 중 하나 입니다.
CVE-2023-46604는 OpenWire 프로토콜을 통해 데이터를 주고받는 과정에서 XML 호출을 조작하거나 악성 데이터를 삽입하여 원격 명령을 실행하는 식으로 진행 됩니다. OpenWire 프로토콜은 기본적으로 데이터 직렬화 및 전송을 처리하는데, 취약점은 이 직렬화 과정에서 악의적인 클래스 유형이 허용되는 점을 악용합니다.
[그림] POC
[그림] XML
패킷 Header
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
패킷 Body
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
OpenWire 패킷 Body 형식
[=If not-null is 1===========]
+----------+ [ +-------+----------------+ ]
| not-null | [ | size | encoded-string | ]
+----------+ [ +-------+----------------+ ]
| byte | [ | short | size octects | ]
+----------+ [ +-------+----------------+ ]
[============================]
[그림 1] WireShark OpenWire 패킷 체크
[그림 2] 패킷 Header의 의미
패킷 Header 끊어서 파악
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
Packet Length : 00000066 / OpenWire 같은 프로토콜은 기본적으로 패킷을 길이를 명시.
Command : 1f / 는 ExecptionResponse(31)을 명시 하기 위한 설정 31은 16진수(hex)로 1f.
Command Id : 00000000 / 는 int 형태 4바이트 형태 임으로 16진수 표현시 00 00 00 00.
Command response required : 00 / 는 boolean 타입으로 True(01), False(00) 에서 False.
CorrelationId : Command Id와 같은 유형
[그림 2]는 위 패킷 헤더의 이해를 돕기 위해, 각 헤더 항목들의 형태와 지정된 코드에 대한 설명을 추가한 내용입니다. 이제 Header 알아 봤으니 Body 내용을 통해 어떻게 코드를 통과하는지 보겠습니다.
[그림 3] 패킷 Body의 의미
패킷 Body 내용 끊어서 파악
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
not-null (01) | / [그림 3]의 첫번째 함수에서 not-null pass
not-null (01) | classname-size (0043) | classname / [그림 3]의 두번째 함수에서 not-null pass, 세번째 함수에서 사이즈 체크 위한
not-null (01) | message-size (0012) | message / [그림 3]의 두번째 함수에서 not-null pass, 세번째 함수에서 사이즈 체크 위한
[그림 3]은 패킷의 Body에서 설정한 값들이 어떻게 작용하는지 보여주고 있습니다. 최종 적으로 [그림 4]를 통하여 직렬화 한 데이터를 통해 클래스 로드하고 인스턴스화 합니다.
[그림 4] createThrowable 를 통한 RCE 실행
[그림 5] RCE 계산기 실행 예시
[그림 5] Git Diff (5.17.2 -> 5.17.6)
[그림 5] validate Function
다른 분석과 달리 해당 취약점에서 공격 패킷을 분석한 이유는 공격이 실제로 어떻게 실행되는지 이해 및 공부하기 위해서였습니다.
패킷의 구조와 흐름을 면밀히 살펴봄으로써, 공격자가 시스템을 침해하기 위해 사용하는 구체적인 방식과 그 동작 메커니즘을 명확히 파악할 수 있었습니다.