
CVE-2020-2551 POC zur Verwendung im Internet
Test-POC (für externe Netztests)
python CVE-2020-2551.py [HOST] [IP]
Versuch, codebase zu ändern, um Klassen remote zu laden (fehlgeschlagen)
python CVE-2020-TEST.py [HOST] [IP]
(Erstveröffentlichung auf Anquanke, Originalartikel)
Um diese Schwachstelle zu verstehen, benötigt man einiges an Vorwissen, z. B. über CORBA und RMI.
Ein kurzer Überblick:
CORBA ist ein von der OMG festgelegter technischer Standard für verteilte Anwendungen. Dabei wird IDL für die sprachübergreifende Unterstützung verwendet; zwischen Client und Server wird über das IIOP-Protokoll kommuniziert.
RMI ist eine weitere Technologie für verteilte Anwendungen. In Java kann sie mit JNDI vereinfacht genutzt werden; Client und Server kommunizieren über das JRMP-Protokoll. In WebLogic verwendet RMI jedoch das T3-Protokoll, zu dem es bereits einige Schwachstellen gab.
RMI-IIOP vereint die Vorteile von RMI und CORBA und ermöglicht die Bereitstellung von RMI-Anwendungen über das IIOP-Protokoll.
Die offizielle Dokumentation erwähnt ebenfalls:
RMI-Serverobjekte können das IIOP-Protokoll verwenden und mit in beliebiger Sprache geschriebenen CORBA-Clientobjekten kommunizieren.
Lassen wir WebLogic zunächst beiseite und schauen wir uns an, wie man ein RMI-IIOP-Beispiel schreibt:
Der Client-Code orientiert sich an dem Testprojekt aus RMI, JNDI, LDAP, JRMP, JMX, JMS in Java (Teil 1). Man kann HelloClient und HelloServer selbst kompilieren oder die bereits kompilierten Klassen aus dem Testprojekt verwenden.
Starte den Namensserver in der Befehlszeile (in Java enthalten):
start orbd -ORBInitialPort 1050
Starte HelloServer in der Befehlszeile und konfiguriere Remote-Debugging. Wie man mit IDEA Remote-Debugging durchführt, kann man in der zu Beginn von diesem Artikel erwähnten Methode nachlesen.
Natürlich kann man auch ohne Remote-Debugging einfach das Ergebnis ansehen und direkt starten:
java HelloServer
Client in der Befehlszeile starten:
Java HelloClient
Daraufhin öffnet sich der Taschenrechner. Ist das Remote-Debugging erfolgreich, sieht man den folgenden Aufrufstapel:

In EvilMessage.readObejct() wird der Befehl ausgeführt.

Nebenbei: Artikel zur Installation und zum Debugging von WebLogic.
Wie sieht es nun mit RMI-IIOP in WebLogic aus? In dem Artikel Über RMI-IIOP in Java wird die Ausnutzung von WebLogic RMI-IIOP erwähnt. Auf dieser Grundlage habe ich einige Untersuchungen angestellt. Using WebLogic’s RMI over IIOP beschreibt mehrere Möglichkeiten, wie WebLogic RMI-IIOP-Clients verwendet, darunter:
Der Unterschied zwischen den ersten beiden Ansätzen scheint nur in der JNDI_FACTORY-Einstellung zu liegen.
Als ich mich zuvor mit der T3-Deserialisierung in WebLogic beschäftigt habe, habe ich auf WebLogic die Anwendung Helloserver bereitgestellt, deren sayhello()-Methode sich ausnutzen ließ. Ich habe beide JNDI_FACTORY-Einstellungen versucht: Mit der zweiten JNDI_FACTORY konnte sayhello() erfolgreich aufgerufen werden.
Daraufhin habe ich den POC für das WebLogic-T3-Protokoll angepasst. Im Grunde wurde nur RMI durch IIOP ersetzt. Dabei zeigte sich, dass die jtaTransactionManager-Nutzungskette erfolgreich ausgeführt wurde und eine JRMP-Anfrage an das lokale jrmplisten gesendet wurde.
Schaut man sich den Datenverkehr an, wird beim Aufruf der Methode remove() eine remove__java_lang_Object-Anfrage gesendet. Der Datenverkehr enthält bösartige Daten, aber es wurde kein aced-Magic-Header gefunden.
Vermutlich werden die Daten auf dem Server erst speziell geparst und dann deserialisiert. Ein Blick auf den Aufrufstapel zeigt, dass die zweite Hälfte der Ausführungskette der zuvor gezeigten nativen RMI-IIOP-Kette sehr ähnlich ist. Dort wurde die Kette durch CDRInputStream.read_value() ausgelöst, hier durch IIOPInputStream.read_value() in WebLogic. (Auch in der Präsentation von 2019 wurde auf diesen Punkt read_value hingewiesen.)
Die Anfrage wird hier zunächst von clusterableServerRef.invoke() verarbeitet, das je nach Invoker this.invoker.invoke() aufruft. Anschließend wird Mejb_dj5nps_HomeImpl_WLSkel.invoke() aufgerufen. Da es sich um „remove“ handelt, wird der Zweig case 6 betreten und IIOPInputStream.readObject() aufgerufen. In der Methode read_value() werden die IIOPInputStream-Daten geparst und die Deserialisierung ausgelöst. Das ist der POC zur Ausnutzung der Methode remove().
Lucifaers [Analyseartikel](https://lucifaer.com/2020/02/25/WebLogic WLS核心组件RCE分析(CVE-2020-2551)/?from=timeline&isappinstalled=0#2-2-Weblogic解析流程) erwähnt die Ausnutzung über die Methode bind() – das ist auch die im Internet gängigste Methode. Verfolgen wir den Aufrufstapel.

Wie zuvor wird die Anfrage zuerst von clusterableServerRef.invoke() verarbeitet, das je nach Invoker this.invoker.invoke() aufruft. Hier wird CobraServerRef.invoke() aufgerufen. In _NamingContextAnyImplBase._invoke() wird – da va1 den Wert „bind_any“ hat – der Zweig case 0 betreten und die Methode IIOPInputStream.read_any() aufgerufen. Anschließend wird weiterhin IIOPInputStream.read_value() aufgerufen, um die Deserialisierung auszulösen. Dass zuvor im Datenverkehr kein aced-Magic-Header zu sehen war, liegt daran, dass IIOPInputStream über eine eigene Parsemethode verfügt. Die Hex-Value-Form von IIOPInputStream sieht folgendermaßen aus und enthält Klassennamen und Feldinformationen:

Letztendlich wird die Methode readObejct() der bösartigen Klasse aufgerufen.

Ein Blick auf den Patch zeigt, dass er sich an derselben Stelle befindet wie der Patch für die T3-Deserialisierungsausnutzung von 2015.