Unzureichende Einschränkung von XML External Entity Reference (XXE)

Beschreibung

Unzureichende Einschränkung von XML External Entity Reference (XXE) tritt auf, wenn XML-Eingaben, die einen Verweis auf eine externe Entität enthalten, von einem schwach konfigurierten XML-Parser verarbeitet werden. Externe Entitäten können auf Dateien im System, interne Netzwerkressourcen oder entfernte URLs verweisen. Wenn XML-Parser diese Verweise ohne ordnungsgemäße Einschränkungen verarbeiten, können Angreifer lokale Dateien lesen (einschließlich sensibler Konfigurationsdateien und Credentials), Server-Side Request Forgery (SSRF) durchführen, um auf interne Dienste zuzugreifen, Denial of Service durch rekursive Entitätserweiterung ("Billion Laughs"-Angriff) verursachen oder möglicherweise Remote Code Execution in bestimmten Konfigurationen erreichen.

Risiko

XXE-Schwachstellen bleiben in Unternehmensanwendungen, die XML-Daten verarbeiten, weit verbreitet. Mehrere IBM WebSphere Application Server-Schwachstellen (CVE-2024-45086, CVE-2024-45072, CVE-2024-22354) ermöglichten XXE-Angriffe, die Dateioffenlegung und SSRF erlaubten. CVE-2025-11700 in N-able N-central ermöglicht Angreifern mit niedrigen Privilegien, beliebige Dateien zu lesen. Diese Schwachstellen sind besonders gefährlich, weil sie auf Dateien außerhalb des Web-Roots zugreifen können, einschließlich /etc/passwd, Datenbank-Credentials und privater Schlüssel. XXE kann auch verwendet werden, um in interne Netzwerke einzudringen, indem der verwundbare Server interne Ressourcen anfordert und effektiv Firewalls umgeht.

Lösung

Deaktivieren Sie externe Entitätsverarbeitung in XML-Parsern. Für Java deaktivieren Sie DTDs vollständig oder setzen Sie XMLConstants.FEATURE_SECURE_PROCESSING. Für Python verwenden Sie die defusedxml-Bibliothek anstelle der Standard-XML-Bibliotheken. Für PHP verwenden Sie libxml_disable_entity_loader(true). Für .NET setzen Sie XmlReaderSettings.DtdProcessing auf DtdProcessing.Prohibit. Verwenden Sie weniger komplexe Datenformate wie JSON, wenn XML-Features nicht benötigt werden. Validieren und bereinigen Sie XML-Eingaben. Implementieren Sie Netzwerksegmentierung, um SSRF-Auswirkungen zu begrenzen. Verwenden Sie Allowlisting für alle erforderlichen externen Entitäten.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Dateioffenlegung

Angreifer können beliebige Dateien auf dem Server lesen, einschließlich Konfigurationsdateien, Credentials und Quellcode.
IntegritätBereich: Server-Side Request Forgery

Angreifer können Anfragen an interne Dienste stellen und auf Ressourcen zugreifen, die nicht dem Internet ausgesetzt sind.
VerfügbarkeitBereich: Denial of Service

Rekursive Entitätserweiterung (Billion Laughs) kann den gesamten verfügbaren Speicher verbrauchen und den Server zum Absturz bringen.

Beispielcode + Lösungscode

Verwundbarer Code

// VERWUNDBAR: Standard-XML-Parser-Einstellungen erlauben XXE
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class XMLProcessor {
    public Document parseXML(String xmlInput) throws Exception {
        // Standard-Factory erlaubt externe Entitäten!
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(xmlInput)));
    }
}

// Angreifer sendet:
// <?xml version="1.0"?>
// <!DOCTYPE foo [
//   <!ENTITY xxe SYSTEM "file:///etc/passwd">
// ]>
// <root>&xxe;</root>
# VERWUNDBAR: Standard-Bibliothek-XML-Parser sind unsicher
from xml.etree import ElementTree

def parse_xml(xml_string):
    # ElementTree ist standardmäßig anfällig für XXE
    root = ElementTree.fromstring(xml_string)
    return root

# VERWUNDBAR: lxml mit gefährlichen Parser-Einstellungen
from lxml import etree

def parse_xml_lxml(xml_string):
    # Standard-lxml-Parser löst externe Entitäten auf
    parser = etree.XMLParser()
    root = etree.fromstring(xml_string.encode(), parser)
    return root
<?php
// VERWUNDBAR: SimpleXML und DOMDocument sind standardmäßig unsicher
function parseXML($xmlString) {
    // Externe Entitäten werden verarbeitet!
    $xml = simplexml_load_string($xmlString);
    return $xml;
}

// Angreifer kann Dateien lesen:
// <?xml version="1.0"?>
// <!DOCTYPE data [
//   <!ENTITY xxe SYSTEM "file:///etc/passwd">
// ]>
// <data>&xxe;</data>
?>

Lösungscode

// SICHER: Externe Entitäten und DTDs deaktivieren
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.XMLConstants;

public class SecureXMLProcessor {
    public Document parseXMLSafe(String xmlInput) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        // DTDs komplett deaktivieren
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

        // Oder externe Entitäten spezifisch deaktivieren
        factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

        // Sichere Verarbeitung aktivieren
        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

        // XInclude deaktivieren
        factory.setXIncludeAware(false);
        factory.setExpandEntityReferences(false);

        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(xmlInput)));
    }
}

// SICHER: SAX-Parser mit Sicherheitsfeatures
import org.xml.sax.XMLReader;
import javax.xml.parsers.SAXParserFactory;

public XMLReader createSecureSAXReader() throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    return factory.newSAXParser().getXMLReader();
}
# SICHER: defusedxml-Bibliothek verwenden
import defusedxml.ElementTree as ET

def parse_xml_safe(xml_string):
    # defusedxml blockiert externe Entitäten standardmäßig
    root = ET.fromstring(xml_string)
    return root

# SICHER: lxml konfigurieren um externe Entitäten zu blockieren
from lxml import etree

def parse_xml_lxml_safe(xml_string):
    # Netzwerkzugriff und Entitätsauflösung deaktivieren
    parser = etree.XMLParser(
        resolve_entities=False,
        no_network=True,
        dtd_validation=False,
        load_dtd=False
    )
    root = etree.fromstring(xml_string.encode(), parser)
    return root

# SICHER: defusedxml für alle XML-Operationen verwenden
from defusedxml import defuse_stdlib
defuse_stdlib()  # Patcht Standard-Bibliothek-XML-Module

# Jetzt ist auch Standard-Bibliothek sicherer
from xml.etree import ElementTree
root = ElementTree.fromstring(xml_string)  # Sicherer nach defuse_stdlib()
<?php
// SICHER: Entitätsladen vor Parsing deaktivieren
function parseXMLSafe($xmlString) {
    // Externes Entitätsladen deaktivieren
    $previousValue = libxml_disable_entity_loader(true);

    // LIBXML_NOENT verwenden um Entitäten nicht zu ersetzen
    // und LIBXML_DTDLOAD um externe DTD nicht zu laden
    $options = LIBXML_NONET | LIBXML_NOENT;

    // Fehler unterdrücken und explizit behandeln
    libxml_use_internal_errors(true);

    $xml = simplexml_load_string($xmlString, 'SimpleXMLElement', $options);

    // Vorherige Einstellung wiederherstellen
    libxml_disable_entity_loader($previousValue);

    if ($xml === false) {
        throw new Exception('Ungültiges XML');
    }

    return $xml;
}

// SICHER: DOMDocument mit Sicherheitseinstellungen
function parseXMLDOMSafe($xmlString) {
    libxml_disable_entity_loader(true);

    $dom = new DOMDocument();
    $dom->loadXML($xmlString, LIBXML_NONET | LIBXML_NOENT);

    return $dom;
}

// SICHER: Best Practice - gegen Schema validieren
function parseXMLWithValidation($xmlString, $schemaPath) {
    libxml_disable_entity_loader(true);

    $dom = new DOMDocument();
    $dom->loadXML($xmlString, LIBXML_NONET | LIBXML_NOENT);

    if (!$dom->schemaValidate($schemaPath)) {
        throw new Exception('XML-Validierung fehlgeschlagen');
    }

    return $dom;
}
?>

Ausgenutzt in der Praxis

IBM WebSphere Application Server (IBM, 2024)

CVE-2024-45086, CVE-2024-45072 und CVE-2024-22354 in IBM WebSphere Application Server ermöglichen XXE-Angriffe, die sensible Informationsoffenlegung, Speicherverbrauch und SSRF-Angriffe gegen interne Dienste ermöglichen.

N-able N-central (N-able, 2025)

CVE-2025-11700 in N-able N-central-Versionen vor 2025.4 ermöglicht Angreifern mit niedrigen Privilegien, bösartiges XML zu erstellen, das beliebige Dateien liest und sensible Konfigurations- und Credential-Informationen exponiert.

Eclipse JGit (Eclipse, 2025)

XXE-Schwachstelle in Eclipse JGit betraf Elastic Enterprise Search und Elasticsearch und demonstrierte Supply-Chain-Auswirkungen, wenn anfällige XML-Verarbeitung in weit verbreiteten Bibliotheken existiert.


Tools zum Testen/Ausnutzen

  • XXEinjector — automatisiertes XXE-Injections-Tool
  • Burp Suite — XXE durch abgefangene Anfragen testen
  • OWASP ZAP — automatisierte XXE-Erkennung

CVE-Beispiele

  • CVE-2024-45086 — IBM WebSphere XXE
  • CVE-2025-11700 — N-able N-central XXE
  • CVE-2014-3574 — Apache POI XXE

Referenzen

  1. MITRE. "CWE-611: Improper Restriction of XML External Entity Reference." https://cwe.mitre.org/data/definitions/611.html
  2. OWASP. "XML External Entity (XXE) Processing." https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing