Unsachgemäße Kontrolle der Code-Generierung ('Code Injection')

Beschreibung

Code Injection ist eine Schwachstelle, die auftritt, wenn Software ein Codesegment ganz oder teilweise unter Verwendung von extern beeinflussten Eingaben einer vorgelagerten Komponente konstruiert, aber Spezialelemente, die die Syntax oder das Verhalten des beabsichtigten Codesegments modifizieren könnten, nicht oder nicht korrekt neutralisiert. Anders als Command Injection, die auf Betriebssystem-Shells abzielt, zielt Code Injection auf den Interpreter der Programmiersprache selbst (z.B. Pythons eval(), PHPs eval(), JavaScripts eval() oder kompilierte Code-Generierung). Erfolgreiche Ausnutzung ermöglicht Angreifern die Ausführung beliebigen Codes im Kontext der Anwendung, was potenziell zu vollständiger Systemkompromittierung mit den vollen Privilegien des Anwendungsprozesses führt.

Risiko

Code Injection stellt eine der schwerwiegendsten Schwachstellenklassen dar und ermöglicht Angreifern die Ausführung beliebigen Codes mit Anwendungsprivilegien. Moderne Webanwendungen, die serverseitige Skriptsprachen verwenden, sind besonders anfällig, wenn sie dynamisch Code aus Benutzereingaben generieren oder interpretieren. Angreifer können sensible Daten stehlen, Anwendungsverhalten modifizieren, persistente Backdoors etablieren, zu internen Systemen pivotieren oder die kompromittierte Anwendung für weitere Angriffe nutzen. Template Injection in serverseitigen Template-Engines (Jinja2, Twig, Freemarker) ist eine zunehmend häufige Code-Injection-Variante. Die Auswirkung ist typischerweise vollständige Anwendungskompromittierung, gleichwertig mit Remote Code Execution.

Lösung

Verwenden Sie niemals eval(), exec() oder ähnliche Code-Ausführungsfunktionen mit benutzerbereitgestellten Eingaben. Gestalten Sie die Anwendungslogik so um, dass dynamische Code-Generierung vermieden wird. Wenn dynamische Funktionalität erforderlich ist, verwenden Sie sichere Alternativen: für mathematische Ausdrücke verwenden Sie dedizierte Parser-Bibliotheken, für Template-Rendering verwenden Sie sandboxed Template-Engines mit Auto-Escaping, für Konfiguration verwenden Sie strukturierte Datenformate (JSON, YAML) mit ordnungsgemäßem Parsing. Implementieren Sie strikte Eingabevalidierung mit Allowlists. Wenden Sie das Least-Privilege-Prinzip auf Anwendungsprozesse an. Setzen Sie Runtime Application Self-Protection (RASP) als Defense-in-Depth ein. Für Template-Engines deaktivieren Sie gefährliche Features und stellen Sie sicher, dass Auto-Escaping aktiviert ist.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Eingeschleuster Code kann auf alle für die Anwendung verfügbaren Daten zugreifen, einschließlich Datenbankinhalte, Konfigurationsdateien, Umgebungsvariablen und Benutzerdaten.
IntegritätBereich: Integrität

Beliebige Code-Ausführung ermöglicht Modifikation der Anwendungslogik, Datenbeschädigung, Malware-Installation und Erstellung persistenter Backdoors.
VerfügbarkeitBereich: Verfügbarkeit

Angreifer können Anwendungen zum Absturz bringen, Ressourcen verbrauchen, Daten löschen oder Ransomware einsetzen, die die Systemverfügbarkeit beeinträchtigt.
ZugriffskontrolleBereich: Vollständige Systemkompromittierung

Code Injection führt typischerweise zu vollständiger Kompromittierung mit der Fähigkeit, jede Aktion auszuführen, die der Anwendungsprozess ausführen kann.

Beispielcode + Lösungscode

Anfälliger Code

from flask import Flask, request
import subprocess

app = Flask(__name__)

@app.route('/calculate')
def calculator():
    # ANFÄLLIG: eval() mit Benutzereingabe
    # Angriff: expression=__import__('os').system('cat /etc/passwd')
    expression = request.args.get('expression')
    result = eval(expression)  # Beliebige Code-Ausführung!
    return f"Ergebnis: {result}"

@app.route('/template')
def render_template():
    # ANFÄLLIG: Template-Injection (Python f-string Missbrauch)
    # Angriff: name={self.__init__.__globals__['os'].popen('id').read()}
    name = request.args.get('name')
    template = f"Hallo, {name}!"
    return eval(f'f"{template}"')

# ANFÄLLIG: PHP-Beispiel
# <?php
# $code = $_GET['code'];
# eval($code);  // Direkte Code-Ausführung
# ?>

Korrigierter Code

from flask import Flask, request, abort, render_template_string
import ast
import operator

app = Flask(__name__)

# Sicherer Evaluator für mathematische Ausdrücke
ALLOWED_OPERATORS = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
    ast.Pow: operator.pow,
    ast.USub: operator.neg,
}

def safe_eval_math(expression):
    """Evaluiert sicher nur mathematische Ausdrücke"""
    try:
        tree = ast.parse(expression, mode='eval')
    except SyntaxError:
        raise ValueError("Ungültige Ausdruckssyntax")

    def _eval(node):
        if isinstance(node, ast.Expression):
            return _eval(node.body)
        elif isinstance(node, ast.Constant):
            if isinstance(node.value, (int, float)):
                return node.value
            raise ValueError("Nur numerische Konstanten erlaubt")
        elif isinstance(node, ast.BinOp):
            op_type = type(node.op)
            if op_type not in ALLOWED_OPERATORS:
                raise ValueError(f"Operator nicht erlaubt")
            return ALLOWED_OPERATORS[op_type](_eval(node.left), _eval(node.right))
        elif isinstance(node, ast.UnaryOp):
            if isinstance(node.op, ast.USub):
                return -_eval(node.operand)
            raise ValueError("Unärer Operator nicht erlaubt")
        else:
            raise ValueError(f"Ausdruckstyp nicht erlaubt: {type(node)}")

    return _eval(tree)

@app.route('/calculate')
def calculator():
    expression = request.args.get('expression', '')

    # Eingabelänge validieren
    if len(expression) > 100:
        abort(400, 'Ausdruck zu lang')

    # Nur sichere Zeichen erlauben
    if not all(c in '0123456789+-*/().^ ' for c in expression):
        abort(400, 'Ungültige Zeichen im Ausdruck')

    try:
        result = safe_eval_math(expression)
        return f"Ergebnis: {result}"
    except ValueError as e:
        abort(400, str(e))

@app.route('/template')
def render_template():
    name = request.args.get('name', 'Gast')

    # Eingabe validieren
    if len(name) > 50:
        name = name[:50]

    # Sicheres Template-Rendering mit Auto-Escaping verwenden
    # Jinja2s render_template_string mit Autoescape verhindert Injection
    return render_template_string(
        "Hallo, {{ name }}!",
        name=name
    )

Ausgenutzt in der Praxis

Server-Side Template Injection-Angriffe (Verschiedene, 2015-heute)

Template-Injection-Schwachstellen in populären Frameworks (Jinja2, Freemarker, Velocity, Smarty) wurden ausgenutzt, um Remote Code Execution zu erreichen. Bemerkenswerte Vorfälle umfassen RCE in Ubers Jinja2-Templates und mehreren Unternehmensanwendungen, die Java-Template-Engines verwenden.

Log4Shell (Apache Log4j, 2021)

CVE-2021-44228 (Log4Shell) demonstrierte Code-Injection durch JNDI-Lookup-Funktionalität in Log-Nachrichten. Obwohl technisch ein Deserialisierungs-/JNDI-Problem, ermöglichte es Code-Injection durch Log-Nachrichtenformatierung und betraf Millionen von Anwendungen weltweit.


Tools zum Testen/Ausnutzen

  • Tplmap — Automatisiertes Tool zur Erkennung und Ausnutzung von Server-Side Template Injection, das mehrere Template-Engines unterstützt.

  • Burp Suite — Web-Sicherheitstestplattform mit aktivem Scanning für Code-Injection-Schwachstellen.


CVE-Beispiele

  • CVE-2021-44228 — Log4j JNDI Code-Injection (Log4Shell) ermöglicht Remote Code Execution.

  • CVE-2022-22965 — Spring Framework Code-Injection (Spring4Shell) durch Data Binding.

  • CVE-2019-11581 — Atlassian Jira Template-Injection ermöglicht serverseitige Code-Ausführung.


Referenzen

  1. MITRE. "CWE-94: Improper Control of Generation of Code." https://cwe.mitre.org/data/definitions/94.html

  2. PortSwigger. "Server-side template injection." https://portswigger.net/web-security/server-side-template-injection

  3. OWASP. "Code Injection." https://owasp.org/www-community/attacks/Code_Injection