
ActiveMQ ist ein Broker, der Clients umfasst, die JMS unterstützen, und ermöglicht die Kommunikation zwischen Systemen, die nicht nur Java, sondern auch verschiedene andere Sprachen verwenden. Darüber hinaus ist es ein Open-Source-Messaging- und Integrationsmuster-Server, der über Clustering-Funktionen sowie DB und FileSystem die Konsistenz und Dauerhaftigkeit zwischen den einzelnen Systemen aufrechterhält.
OpenWire ist ein binäres Messaging-Protokoll, das in Apache ActiveMQ verwendet wird. Es wurde für eine effiziente Datenübertragung zwischen dem Broker (ActiveMQ) und den Clients entwickelt.
CVE-2023-46604 ist eine Schwachstelle im OpenWire-Protokoll (während des Marshal-Prozesses) in ActiveMQ. Sie ermöglicht es einem entfernten Angreifer mit Netzwerkzugriff auf einen Java-basierten OpenWire-Broker oder -Client, die im OpenWire-Protokoll serialisierten Klassentypen zu manipulieren, beliebige Shell-Befehle auszuführen und den Client bzw. den Broker (jeweils) dazu zu bringen, alle auf dem Klassenpfad befindlichen Klassen zu instanziieren. Sie ist eine der repräsentativen Angriffsmethoden der APT-Gruppe Andariel.
CVE-2023-46604 läuft so ab, dass während des Datenaustauschs über das OpenWire-Protokoll ein XML-Aufruf manipuliert oder bösartige Daten eingefügt werden, um Remote-Befehle auszuführen. Das OpenWire-Protokoll übernimmt grundsätzlich die Serialisierung und Übertragung von Daten. Die Schwachstelle nutzt aus, dass bei diesem Serialisierungsprozess bösartige Klassentypen zugelassen werden.
[Abbildung] POC
[Abbildung] XML
Wir werden dies anhand der Analyse der Pakete untersuchen, die in ActiveMQ 5.17.3 über das OpenWire-Protokoll gesendet werden. Zunächst müssen wir uns vor der Paketanalyse mit der Form des Pakets vertraut machen.패킷 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 | ]
+----------+ [ +-------+----------------+ ]
[============================]
[Abbildung 1] WireShark OpenWire-Paketprüfung
In [Abbildung 1] ist die tatsächliche Payload mit dem oben beschriebenen Header- und Body-Format des Pakets zu sehen (der Einfachheit halber erfolgt der Aufruf nicht über den ClassPath wie bei der ursprünglichen POC-Methode, sondern über das FileSystem). Wir werden nun im Code genauer untersuchen, welche Wirkung diese Paketinhalte entfalten und warum sie auf diese Weise gesendet werden müssen.
[Abbildung 2] Bedeutung des Paket-Headers
패킷 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와 같은 유형
[Abbildung 2] enthält ergänzende Erläuterungen zu den Formaten der einzelnen Header-Felder und den zugehörigen Code-Werten, um das Verständnis des obigen Paket-Headers zu erleichtern. Nachdem wir uns nun den Header angesehen haben, betrachten wir anhand der Body-Inhalte, wie der Code durchlaufen wird.
[Abbildung 3] Bedeutung des Paket-Bodys
패킷 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, 세번째 함수에서 사이즈 체크 위한
[Abbildung 3] zeigt, wie die im Body des Pakets gesetzten Werte wirken. Schließlich werden über die serialisierten Daten – wie in [Abbildung 4] dargestellt – Klassen geladen und instanziiert.
[Abbildung 4] RCE-Ausführung über createThrowable
[Abbildung 5] Ausführungsbeispiel des RCE-Rechners
[Abbildung 5] Git Diff (5.17.2 -> 5.17.6)
[Abbildung 5] validate-Funktion
Anders als bei anderen Analysen wurde bei dieser Schwachstelle das Angriffspaket analysiert, um zu verstehen und zu lernen, wie der Angriff tatsächlich ausgeführt wird.
Durch die genaue Untersuchung der Struktur und des Ablaufs der Pakete konnten die konkreten Methoden, mit denen ein Angreifer ein System kompromittiert, und der zugrunde liegende Wirkmechanismus klar nachvollzogen werden.
(nist) https://nvd.nist.gov/vuln/detail/cve-2023-46604
(POC) https://github.com/X1r0z/ActiveMQ-RCE/tree/main
(blog) https://attackerkb.com/topics/IHsgZDE3tS/cve-2023-46604/rapid7-analysis