Weniger bekannt, aber brandgefährlich
Wenn es um Injection geht, denken viele sofort an SQL. Doch moderne Anwendungen nutzen längst nicht mehr nur relationale Datenbanken – sie arbeiten mit Template-Engines für dynamische Inhalte oder mit Verzeichnisdiensten wie LDAP. Genau dort entstehen neue Angriffsflächen. Zwei besonders spannende Varianten sind Server-Side Template Injection (SSTI) und LDAP Injection. Sie sind zwar weniger berühmt als SQLi, können aber genauso zerstörerisch sein.
Server-Side Template Injection (SSTI)
Was ist eine Template Engine?
Viele Webframeworks nutzen Template-Engines, um dynamische Inhalte zu erzeugen. Beispiele:
- Jinja2 (Python / Flask)
- Twig (PHP)
- Freemarker (Java)
- Handlebars (JavaScript)
Die Idee: Entwickler schreiben HTML mit Platzhaltern, die später durch Werte ersetzt werden.
Beispiel in Jinja2:
<p>Hallo {{ username }}!</p>
Wenn username = "Alice"
, wird daraus:
<p>Hallo Alice!</p>
Soweit so gut – solange nur kontrollierte Werte in die Templates gelangen.
Wie entsteht SSTI?
Eine Template Injection tritt auf, wenn Nutzereingaben direkt in ein Template eingebaut und anschließend interpretiert werden. Statt nur als Text behandelt zu werden, kann der Input als Code ausgeführt werden.
Beispiel:
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route("/hello")
def hello():
name = request.args.get("name")
return render_template_string("Hallo " + name)
Ein Angreifer ruft auf:
/hello?name={{7*7}}
Das Template wird zu:
Hallo {{7*7}}
Die Engine wertet 7*7
aus → Ausgabe: Hallo 49
.
Das ist ein klarer Hinweis auf SSTI.
Von Spielerei zur Systemübernahme
Wenn einfache Ausdrücke wie 7*7
ausgewertet werden, ist oft noch mehr möglich. Viele Template-Engines erlauben Zugriff auf interne Objekte oder sogar das Ausführen von Systembefehlen.
Ein Beispiel in Jinja2:
/hello?name={{ config.items() }}
Damit kann der Angreifer Konfigurationswerte der App auslesen – etwa Geheimnisse wie API-Keys.
Mit ausgefeilteren Payloads sind sogar Remote Code Execution (RCE) möglich:
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
Ergebnis: Der Befehl id
wird auf dem Server ausgeführt und die Benutzerinformationen werden im Browser angezeigt.
Schutz vor Template Injection
- Kein unkontrolliertes render_template_string: Templates sollten nicht direkt mit Userinput befüllt werden.
- Autoescaping aktivieren: Viele Engines bieten Mechanismen, um Eingaben als reinen Text darzustellen.
- Whitelisting von Variablen: Nur explizit erlaubte Variablen in Templates zulassen.
- Sandboxing: Template-Engines so konfigurieren, dass kritische Funktionen (z. B. Import, Exec) blockiert sind.
LDAP Injection
Was ist LDAP?
Lightweight Directory Access Protocol (LDAP) wird genutzt, um auf Verzeichnisdienste zuzugreifen – etwa Benutzerverzeichnisse in Unternehmen.
Typische Einsätze:
- Login-Authentifizierung gegen Active Directory.
- Verwaltung von Benutzer- oder Gruppeninformationen.
- Zugriff auf Unternehmensressourcen.
Eine LDAP-Abfrage könnte so aussehen:
(&(uid=alice)(userPassword=mypassword))
Damit sucht der Server nach einem Eintrag mit uid=alice
und passendem Passwort.
Wie entsteht LDAP Injection?
Problematisch wird es, wenn Eingaben direkt in LDAP-Filter eingebaut werden – ähnlich wie bei SQL.
Unsichere Implementierung in Java:
String filter = "(&(uid=" + username + ")(userPassword=" + password + "))";
Wenn der Angreifer Folgendes eingibt:
- Username:
*)(uid=*)
- Passwort: beliebig
wird daraus:
(&(uid=*)(uid=*)(userPassword=beliebig))
Das matcht im Prinzip alle Nutzer – der Login ist umgangen.
Angriffsmöglichkeiten mit LDAP Injection
- Login-Bypass: Wie im Beispiel – Angreifer loggen sich ohne Passwort ein.
- Datenexfiltration: Durch Manipulation der Filter können mehr Informationen zurückgegeben werden, als vorgesehen.
- Privilege Escalation: Angreifer geben gezielt Bedingungen ein, die zu Admin-Accounts passen.
- Denial of Service: Komplexe Filterstrukturen können den Server belasten.
Schutzmaßnahmen gegen LDAP Injection
- Parameterisierte LDAP-Abfragen: Viele Libraries erlauben das sichere Binden von Parametern.
Beispiel in Java (JNDI):SearchControls sc = new SearchControls(); sc.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration results = ctx.search("ou=users,dc=example,dc=com", "(&(uid={0})(userPassword={1}))", new Object[]{username, password}, sc);
- Input-Validierung: Unerlaubte Sonderzeichen wie
*
,(
,)
,&
blockieren. - Least Privilege: Der LDAP-Bind-User sollte nur minimal notwendige Rechte haben.
- Fehlermeldungen generisch halten: Keine internen LDAP-Strukturen preisgeben.
Gemeinsamkeiten und Unterschiede
Aspekt | Template Injection (SSTI) | LDAP Injection |
---|---|---|
Zielsystem | Template-Engine (Server) | LDAP-Verzeichnisdienst |
Ursache | Userinput im Template interpretiert | Userinput in LDAP-Filter integriert |
Folgen | RCE, Datenlecks | Login-Bypass, Datenexfiltration |
Schutz | Kein unkontrolliertes Rendern, Sandbox | Parametrisierung, Input-Validierung |
Beide zeigen: Injection betrifft nicht nur klassische Datenbanken, sondern jede Art von Abfragesprache.
Reale Vorfälle
- SSTI in Flask-Apps: Mehrere Bug-Bounty-Reports zeigen, dass Entwickler
render_template_string
mit Userinput nutzten → führte zu RCE. - LDAP Injection bei Firmenportalen: Angreifer konnten sich durch manipulierte Filter als Admin einloggen – mit Zugriff auf komplette Unternehmensverzeichnisse.
Was du mitnehmen solltest
- Template Injection erlaubt es, Code innerhalb der Template-Engine auszuführen – bis hin zu Remote Code Execution.
- LDAP Injection missbraucht Verzeichnisdienste, um Logins zu umgehen oder Daten abzugreifen.
- Beide entstehen durch denselben Fehler: Userinput wird ohne Trennung als Teil einer Abfragesprache interpretiert.
- Schutz: Parametrisierung, Whitelists, Sandboxing, Least Privilege.
Im letzten Teil der Serie fassen wir die wichtigsten Erkenntnisse zusammen und schauen uns Best Practices an, wie man Injection generell vermeidet – egal, ob SQL, Command, NoSQL, Template oder LDAP.
Schreibe einen Kommentar