
CVE-2020-2551 POC da utilizzare su Internet
POC di test (utilizzabile per test su Internet)
python CVE-2020-2551.py [HOST] [IP]
Tentativo di modifica del codebase per il caricamento remoto delle classi (fallito)
python CVE-2020-TEST.py [HOST] [IP]
(Pubblicato originariamente su Anquanke, link originale)
Per studiare questa vulnerabilità servono alcune conoscenze preliminari, come CORBA e RMI.
Ecco una breve panoramica:
CORBA è uno standard tecnico definito da OMG per le applicazioni distribuite; utilizza IDL per il supporto cross-language e la comunicazione tra client e server avviene tramite il protocollo IIOP.
RMI è un'altra tecnologia per applicazioni distribuite. In Java può essere semplificata con JNDI; client e server comunicano tramite il protocollo JRMP, ma in WebLogic l'RMI usa il protocollo T3, e in passato sono state scoperte molte vulnerabilità al riguardo.
RMI-IIOP combina i punti di forza di RMI e CORBA e consente di distribuire applicazioni RMI tramite il protocollo IIOP.
Anche la documentazione ufficiale afferma:
Gli oggetti server RMI possono utilizzare il protocollo IIOP e comunicare con oggetti client CORBA scritti in qualsiasi linguaggio.
Per ora lasciamo da parte WebLogic e concentriamoci su come scrivere un esempio RMI-IIOP:
Per il codice client si può fare riferimento al progetto di test presente in Le cose da sapere su RMI, JNDI, LDAP, JRMP, JMX e JMS in Java (Parte 1); si possono compilare da sé HelloClient e HelloServer, oppure usare quelli già compilati nel progetto di test.
Avviare il name server da riga di comando (fornito con Java):
start orbd -ORBInitialPort 1050
Avviare il server HelloServer da riga di comando e configurare il debug remoto; per come usare IDEA per il debug remoto, si può fare riferimento al metodo indicato all'inizio di questo articolo.
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 HelloServer
Ovviamente si può anche avviare direttamente senza debug remoto e vedere il risultato:
java HelloServer
Avviare il client da riga di comando:
Java HelloClient
A questo punto si aprirà la calcolatrice; se il debug remoto funziona, si può vedere la seguente stack trace:

L'esecuzione del comando avviene in EvilMessage.readObejct().

Nota a margine: articoli su installazione e debug di WebLogic.
E l'RMI-IIOP in WebLogic? L'articolo RMI-IIOP in Java menziona lo sfruttamento dell'RMI-IIOP di WebLogic; sulla base di questo ho svolto alcune ricerche. Using WebLogic’s RMI over IIOP illustra diversi modi in cui WebLogic può usare client RMI-IIOP, tra cui:
La differenza tra i primi due metodi sembra essere solo nell'impostazione di JNDI_FACTORY.

In precedenza, studiando la deserializzazione T3 di WebLogic, avevo distribuito su WebLogic un'applicazione Helloserver con un metodo sayhello() utilizzabile. Ho provato a impostare entrambi i tipi di JNDI_FACTORY e a chiamarlo: con il secondo tipo di JNDI_FACTORY sono riuscito a invocare con successo il metodo sayHello().

Ho quindi modificato il POC per il protocollo T3 di WebLogic: in pratica ho solo cambiato RMI in IIOP. Ho scoperto che la catena di gadget jtaTransactionManager viene eseguita con successo e viene inviata una richiesta jrmp al jrmplisten locale.

Osservando il traffico, durante la chiamata al metodo remove() viene inviata una richiesta remove__java_lang_Object; il traffico contiene dati malevoli, ma non ho trovato la magic header aced.

C'è da supporre che sul server venga eseguito un parsing speciale prima della deserializzazione dei dati. Guardando la stack trace, la parte finale della catena di esecuzione è molto simile a quella del RMI-IIOP nativo visto prima: lì si parte da CDRInputStream.read_value(), qui da IIOPInputStream.read_value() di WebLogic (questo punto read_value era stato menzionato anche nella presentazione del 2019).

Qui la richiesta viene prima gestita da clusterableServerRef.invoke(); a seconda dell'invoker viene chiamato this.invoker.invoke(). In questo caso viene invocato Mejb_dj5nps_HomeImpl_WLSkel.invoke(); poiché è “remove”, si entra nel ramo case 6 che chiama IIOPInputStream.readObject(); nel metodo read_value() vengono analizzati i dati di IIOPInputStream, innescando la deserializzazione. Questo è il POC che sfrutta il metodo remove().
L'[articolo](https://lucifaer.com/2020/02/25/WebLogic WLS核心组件RCE分析(CVE-2020-2551)/?from=timeline&isappinstalled=0#2-2-Weblogic解析流程) di analisi di Lucifaer menziona lo sfruttamento tramite il metodo bind(), che è anche il metodo di sfruttamento più comune su Internet; seguiamo la stack trace.

Come prima, la richiesta viene prima gestita da clusterableServerRef.invoke(); a seconda dell'invoker viene chiamato this.invoker.invoke(). Qui viene invocato CobraServerRef.invoke(); successivamente, in _NamingContextAnyImplBase._invoke(), poiché va1 è “bind_any”, si entra nel ramo case 0 che chiama IIOPInputStream.read_any(); in seguito verrà comunque chiamato IIOPInputStream.read_value() per innescare la deserializzazione. Prima ho detto che nel traffico non avevo visto la magic header aced: il motivo è che in IIOPInputStream esiste un meccanismo di parsing. La forma hex-value di IIOPInputStream è la seguente e contiene il nome della classe e le informazioni sui campi: