Hoje, temos um caso clássico onde os desenvolvedores corrigiram uma vulnerabilidade, mas inadvertidamente facilitaram a vida dos hackers. Neste artigo, demonstrarei como a vulnerabilidade funcionava e como percorrer todo o caminho, desde seu estudo até a escrita de um exploit.
Atenção: Este artigo tem caráter informativo e destina-se a especialistas em segurança que realizam testes sob contrato. O autor e a redação não se responsabilizam por quaisquer danos causados pela aplicação das informações apresentadas. A distribuição de programas maliciosos, a interrupção de sistemas e a violação da confidencialidade da comunicação são puníveis por lei.
CVE-2026-34486 é uma vulnerabilidade crítica de execução remota de código (RCE) via desserialização no módulo Apache Tomcat Tribes. Ela permite que um invasor não autorizado assuma o controle de um servidor com uma única requisição. Na prática, isso é uma regressão da CVE-2026-29146: corrigiram uma vulnerabilidade, mas criaram uma nova. Além disso, a nova vulnerabilidade é mais fácil de explorar. Enquanto na CVE-2026-29146 era necessário interceptar pacotes criptografados e sondar metodicamente o servidor para recuperar o texto plano com base em sua resposta a erros de padding, na CVE-2026-34486, basta enviar uma requisição bruta.
Apache Tomcat Tribes é um módulo do Apache Tomcat para troca de mensagens entre servidores Tomcat, quando há vários deles. Múltiplos servidores são necessários para balanceamento de carga em projetos de alta demanda, quando um único servidor não consegue lidar com o tráfego. Por exemplo, projetos distribuídos tentam posicionar servidores mais próximos dos usuários para reduzir o tempo de resposta, mas existem outras aplicações. Em qualquer caso, se houver vários servidores, surgem problemas em garantir a integridade dos dados e o funcionamento contínuo da aplicação. Se um usuário se autenticou, todos os servidores devem saber sobre a sessão. Caso contrário, ao alternar, o usuário terá que se autenticar repetidamente. Para resolver esses problemas, o Apache Tribes é necessário.
O Tribes gerencia a infraestrutura interna de um cluster de servidores; suas portas não são acessíveis externamente. Existem três cenários de ataque principais:
Acesso à rede corporativa. Um invasor, por exemplo, pode comprometer o computador de um funcionário ou se infiltrar em um Wi-Fi desprotegido. Ataque a um servidor vizinho. Um cluster de servidores nem sempre está dentro do ambiente corporativo. Neste caso, o hacker tem a chance de encontrar o servidor menos protegido e usá-lo como ponto de apoio. Clássica SSRF (Server-Side Request Forgery). Se a aplicação web for vulnerável, o hacker pode forçar o servidor a fazer uma requisição para o Tribes e enviar um payload malicioso.
Anatomia da Vulnerabilidade
Ao corrigir a CVE-2026-29146, os desenvolvedores cometeram um erro na classe EncryptInterceptor, que deveria fornecer proteção:
java@Override public void messageReceived(ChannelMessage msg) { try { byte[] data = msg.getMessage().getBytes(); data = encryptionManager.decrypt(data); XByteBuffer xbb = msg.getMessage(); // Substitui a mensagem pela descriptografada xbb.clear(); xbb.append(data, 0, data.length); } catch (GeneralSecurityException gse) { log.error(sm.getString("encryptInterceptor.decrypt.failed"), gse); } // A desserialização ocorrerá de qualquer forma super.messageReceived(msg); }
Em um código seguro, cada pacote de dados é descriptografado pela função encryptionManager.decrypt() usando uma chave. Se um hacker enviar dados brutos ou dados criptografados com a chave errada, o código falhará com um erro BadPaddingException ou IllegalBlockSizeException. A execução do código será interrompida.
Um exemplo de método messageReceived seguro pode ser visto no código-fonte do Tribes versão 9.0.115 - no arquivo EncryptInterceptor.java, na linha 142.
java// Função messageReceived na versão 9.0.115
No commit 0112ed22, os desenvolvedores moveram a chamada super.messageReceived() para fora do try/catch. Este é um erro lógico. O hacker não precisa adivinhar a chave de criptografia - pelo contrário, é necessário causar um erro de descriptografia. Se o hacker enviar dados abertos, o servidor não falhará, mas registrará um erro no log e continuará o trabalho.
java// Função messageReceived vulnerável
Os bytes maliciosos vão diretamente para o componente GroupChannel, que usa a classe XByteBuffer para processar a mensagem. A primeira etapa do processamento é a desserialização usando XByteBuffer.deserialize(). O método inicia o mecanismo padrão de leitura de objetos através do fluxo ObjectInputStream.
java// Commit 0112ed22
Durante a desserialização de um objeto Java, métodos de serviço como readObject() ou hashCode() são executados automaticamente, conforme descrito na classe. É importante entender que o atacante não adiciona nada de novo, ele apenas envia um objeto com uma estrutura familiar ao servidor. O servidor conhece cada objeto aninhado e pode mapeá-lo para uma classe específica. As classes são especificadas em seu classpath pelos administradores ou desenvolvedores. Frequentemente, são classes do Apache Commons Collections ou bibliotecas JDK embutidas. Este é um conjunto de classes bem conhecido com características e pontos fracos bem estudados.
Info: Commons Collections (parte do projeto Apache Commons) é uma biblioteca para Java que complementa o Java Collections Framework (JCF) padrão. Ela contém novas estruturas de dados e ferramentas para trabalhar com objetos. Por exemplo, Trie é uma estrutura de dados em árvore para busca rápida de strings por prefixo.
Um payload é uma cadeia de classes conectadas (gadgets), cujo objetivo final é chamar uma função perigosa, como java.lang.Runtime.getRuntime().exec(). Se a cadeia de gadgets for descrita como um objeto, tal objeto pareceria assim:
json{ "HashSet": { "HashMap": { "TiedMapEntry": { "LazyMap": { "ChainedTransformer": [ { "ConstantTransformer": "java.lang.Runtime.class" }, { "InvokerTransformer": { "method": "getMethod", "args": ["getRuntime"] } }, { "InvokerTransformer": { "method": "invoke", "args": [] } }, { "InvokerTransformer": { "method": "exec", "args": ["whoami"] } } ] } } } } }
A cadeia completa de chamadas no exemplo do Apache Commons Collections:
HashSet.readObject()HashMap.put(key, ...)TiedMapEntry.hashCode()LazyMap.get("poc")ChainedTransformer.transform()ConstantTransformer->Runtime.classInvokerTransformer->Runtime.getMethod("getRuntime")InvokerTransformer->runtime.getRuntime()InvokerTransformer->runtime.exec(cmd)
Os desenvolvedores nem sempre usam o Commons Collections, é apenas um conjunto popular. Existem alternativas: Spring, Groovy, Commons BeanUtils, JDK. Além disso, a versão do Commons Collections pode variar, e para cada uma delas é construída uma cadeia diferente. Por exemplo, o ysoserial possui oito variações para esta biblioteca. A tarefa do hacker é encontrar a cadeia de gadgets apropriada.
Montagem do Ambiente de Teste
Criamos um Dockerfile que instalará e configurará uma versão vulnerável do Apache Tomcat 9.0.116:
dockerfile# Versão vulnerável do Apache Tomcat FROM tomcat:9.0.116-jdk8 RUN mv /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps/ RUN set -ex \ && curl -fSL https://repo1.maven.org/maven2/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar \ -o /usr/local/tomcat/lib/commons-collections-3.2.1.jar COPY server.xml /usr/local/tomcat/conf/server.xml
Observe: para o teste, usamos commons-collections-3.2.1.jar.
O restante do conteúdo está disponível apenas para membros. Materiais das últimas edições tornam-se disponíveis individualmente apenas dois meses após a publicação. Para continuar a leitura, é necessário tornar-se membro da comunidade "Xakep.ru". Junte-se à comunidade "Xakep.ru"! A associação à comunidade durante o período especificado lhe dará acesso a TODO o material "Xakep", permitirá baixar edições em PDF, desativará a publicidade no site e aumentará seu desconto acumulado pessoal! Saiba mais Já sou membro "Xakep.ru" ← Anterior Contas de celebridades hackeadas através de vulnerabilidade em chatbot da Meta








