
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.

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.

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.



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.
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.

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.

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
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.

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:
`
⇒ 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.


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.