stripslashes() schleust XSS-Angriffe am Filter des Internet Explorer 8 vorbei
Der Microsoft Internet Explorer 8 ist in eine Beta-Version bereits verfügbar und bringt einige Neuerungen mit, unter anderem einen XSS (Cross Site Scripting)-Filter.
Außer der Tatsache, dass der Filter nicht alle im Umlauf befindlichen XSS-Angriffe abwehren können wird, was den Entwicklern bei Microsoft auch klar ist, gibt es einfache Methoden um sogar triviale Angriffe am Filter vorbei zu schleusen.
Interessanter Weise betrifft die gezeigte Methode vor allem PHP-Applikationen, denn sie geht von der Verwendung von „stripslashes()“ bei der Verarbeitung von Nutzereingaben aus. Wie oft diese Funktion tatsächlich pauschal auf Eingabedaten verwendet wird – ob nötig oder nicht – lässt sich erahnen, wenn man nach dem klassischen Problem mit den doppelt „escapten“ Eingaben im Netz sucht:
Bei PHP.NET findet man direkt die erste Anleitung, um die doppelten Slashes zu entfernen:
<br />
<?php
function stripslashes_if_gpc_magic_quotes( $string ) {
if(get_magic_quotes_gpc()) {
return stripslashes($string);
} else {
return $string;
}
}
?><br />
Oder wie wäre es, alle Eingangskanäle zu stripslash-en??
<br />
<?
if (get_magic_quotes_gpc() == 1) {
function stripslashes_deep($value) {
$value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value);
return $value;
}
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
?><br />
In beiden (und ähnlichen) Fällen sind alle glücklich, bis auf die armen Nutzer oder Anwendungen, die Pfade verarbeiten wollen („bilder\bild.jpg“) oder sowas wie „DOMAIN\user“. Darüberhinaus trickst diese pauschale Löschung der Slashes die XSS-Prüfung des IE8 aus. Wie das geht, ist hier zu lesen. Hier sei die Methode an einem Beispiel dargestellt:
Der XSS-Filter des IE8 reagiert auf typische Angriffsmuster:
<br />
index.php?name=<script>alert('XSS');</script><br />
Typischer Angriffs- oder Testvektor
Maskiert man die Buchstaben mit Backslashes, erkennt der IE solche Worte wie „script“ und „alert“ nicht mehr:
<br />
index.php?name=<s\cr\ip\t>al\er\t(‚XSS‘);</s\cr\ip\t><br />
Mit Backslashes unkenntlich gemachter Angriffs- oder Testvektor
Filtert die Webanwendung nun alle Eingaben mit stripslashes() durch, so entsteht wieder der Angriffsvektor und zwar hinter der „Verteidigungslinie“ des Internet Explorer.
<br />
index.php?name=<script>alert('XSS');</script><br />
Angriffs- oder Testvektor nach dem Behandeln mit stripslashes()
PS: Die SSEQ-LIB-Funktion „seq_remove_slashes_“ ist von dieser Schwachstelle nicht betroffen, da hier nur Slashes entfernt werden, die tatsächlich ein Sonderzeichen maskieren.
Das Problem ist sicherlich ein solches, wenn man stripslashes() allein benutzt. Wer jedoch Daten an den Browser ausgibt, sollte ausgiebig von strip_tags() und/oder htmlentities() Gebrauch machen. Und vorher den Code am besten nochmal validieren.
Korrekt. Es geht hier auch hauptsächlich um das interessante Zusammenspiel zwischen Filter und stripslashes().
PS: Filtern? Validieren? Gerade heute wieder ein PHP & MySQL „Tutorial“ ohne den leisesten Ansatz von Sicherungsmaßnahmen gesehen…
Wie genau bewirken die beiden Codeschnipsel denn, dass einer der beiden Fälle (Pfad zerstört bzw. IE8 ausgetrickst) eintritt?
Wenn magic_quotes_gpc deaktiviert sind kommt als Eingabestring für das Script z.B. „bilder\bild.jpg“, stripslashes wird nicht angewandt, also bleibt’s bei „bilder\bild.jpg“. Dito für das „al\er\t(‚XSS‘);“ Beispiel.
Im anderen Fall, magic_quotes_gpc aktiviert, kommt vom Browser „bilder\bild.jpg“, PHP selbst macht daraus für das Script „bilder\\bild.jpg“, und die stripslashes Aktion transformiert das ganze wieder zu „bilder\bild.jpg“. Analog für den „…“ Kram.
Natürlich darf man die erste Funktion nur auf $_GET/$_POST/etc. anwenden und nicht auf bereits bereinigte Daten, und natürlich darf die zweite Variante nur genau einmal ausgeführt werden, aber gerade letzteres ist mit einem „require_once ‚clean_input.php'“ oder ähnlichem kein Problem. Und die stripslashes_if_… Funktion zeugt eh davon, dass man weder seine eigene Zeit, noch die Lesbarkeit des Codes sonderlich wertschätzt, da sind doppelte „stripslashes“ Aufrufe am Ende wahrscheinlich das kleinste Problem.
Danke für den Hinweis. Bei der Behandlung des Themas habe ich zwei Aspekte/Aussagen etwas zu stark vermischt.
Aspekt 1: stripslashes() darf nicht immer und ohne Not verwendet werden, sonst kann der IE8 umgangen werden und solche Zeichenketten wie „bilder\bild.jpg“ werden bei ausgeschalteten „magic_quotes_gpc“ zerstört.
Aspekt 2: Mit einer Funktion wie die aus der SSEQ-LIB kann man auch Daten aus unbekannten Quellen (DB, XML, HTTP-Stream) meist schadlos von Slashes befreien. Dabei gehen dann Zeichenketten wie „bilder\bild.jpg“ nicht kaputt, während andere wie „O\’Reilly“ von Slashes befreit werden. Dazu verzichtet man auf die Entscheidung anhand des Zustandes von „magic_quotes_gpc“, da ansonsten nur Quellen aus den HTTP-Streams korrekt behandelt werden würden.
hi @ all
vor einigen tagen fand ich einen neuen weg, den xss-filter im ie8 rc1 zu umgehen. die maskierung wie von erich in diesem artikel beschrieben, wurde seit dem rc1 gefixt. doch fand ich einige vektoren mit nullbytes (), welche (vermutlich) den xss regular expression filter dazu veranlasst, den rest der url zu ignorieren, die ie-enginee führt aber den gesamten url-string aus.
ich schrieb dazu einen blogpost auf http://www.reverse-engineer.ch/techblog/?p=181 und einen proof of concept unter http://www.reverse-engineer.ch/codelab/ie8-nullbyte-xss/
zudem informierte ich microsoft über diesen bypass. vor einigen minuten erhielt ich die bestätigung von david ross (browser & webapp security engineer bei microsoft). der bug is nun offiziell bei microsoft bekannt und wird (hoffentlich) bald gefixt.
grüsse aus der schweiz, marc
http://www.reverse-engineer.ch/techblog