Billion Laughs

Ein Billion-Laughs-Angriff ist ein Denial-Of-Service-Angriff mittels präparierten XML-Dokument.

Die Beschreibung hier bezieht sich auf das XML-Format. Betroffen sind aber alle Formate, die eine Art von rekursiver (Makro-)Expansion unterstützen (wie bspw. YAML mittels Anchors und References).

Allgemeines

Ein Denial-Of-Service-Angriff sorgt dafür, daß ein System Resourcen (Speicher, Rechenzeit, etc.) in Übermaß konsumiert und damit nur noch eingeschränkt, langsam oder überhaupt nicht mehr reagiert.

XML-Grundlagen

Entitäten in XML-Dokumenten sind Namen, eingeschlossen in einem führenden Ampersand (&) und einem abschliessenden Semikolon (;). &lt; ist bspw. eine vordefinierte Entität zum Encodieren von < in XML-Inhalten. (Ohne diese Encodierung würde der XML-Parser hier den Start eines öffnenden oder schliessenden XML-Elements erkennen.). Weitere Entitäten sind bspw. auch die dezimalen oder hexadezimalen Darstellungen von Sonderzeichen. So wäre bspw. &#169; (als dezimale Form) bzw. &#xA9; (als hexadezimale Form) das Copyright-Zeichen (©).

Entitäten können aber auch im XML-Dokument definiert werden:

<!DOCTYPE myDocument [
    <!ENTITY foo "bar">
]>
<root>
    <text>&foo;</text>
</root>

In diesem Beispiel wird eine XML-Entität namens foo definiert, welcher der Text bar zugewiesen wird. An allen Stellen im XML-Dokument, an denen der Parser &foo; findet wird der Text bar eingetragen. Das ist erstmal kein Problem.

Das Problem

XML erlaubt es jedoch auch XML-Entitäten mit anderen XML-Entitäten zu definieren:

<!DOCTYPE myDocument [
    <!ENTITY bar "bar">
    <!ENTITY foo "&bar;">
]>
<root>
    <text>&foo;</text>
</root>

Hier setzt der Billion-Laughs-Angriff auf. Er erzeugt eine riesige Datenmenge im Speichern des Rechners.

Was passiert bei dem nachfolgenden XML-Dokument?

<!DOCTYPE myDocument [
    <!ENTITY lol0 "lol">
    <!ENTITY lol1 "&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;">
    <!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;">
]>
<root>
    <text>&lol9;</text>
</root>

lol9 wird durch 10x lol8 ersetzt. Jedes lol8 wird durch 10x lol7 ersetzt, jedes davon wiederum durch 10x lol6 usw. Am Ende sind es dann 109 lol0, die durch ein x ersetzt werden. Das ist am Ende ein Text mit 1 Milliarde x!

Lösungen

Es gibt ein paar Lösungen, von denen man auswählen kann:

  • Keine XML-Dokumente aus unsicheren Quellen zulassen. Das klingt erstmal sinnvoll, aber es gibt Fälle, in denen genau das erforderlich ist, beispielsweise bei Diensten, die GPX-Daten verarbeiten.
  • Keine Expansion von Entitäten erlauben. Damit sollten nur vordefinierte Entitäten expandiert werden, aber keine selbstdefinierten. Dies ist meiner Erfahrung nach die sinnvollste Lösung, wenn XML-Dokumente aus Fremdquellen verarbeitet werden sollen.
  • Begrenzung der Anzahl der Expansionen. Damit kann festgelegt werden, wieviele Expansionen durchgeführt werden können, bevor der Parser abbricht. Nicht jeder XML-Parser unterstützt dies und Unterschiede zwischen den XML-Parsern sind mögllich. (z.B. Begrenzung der Anzahl aller Expansionen im gesamten Dokument ⇔ Begrenzung der Expansionen pro gefundener Entität im Dokument)

oppol.abryok+blog-MjE2LjczLjIxNi4yMDE@gmail.com