12:14
17/6/2010

Autorem poniższego artykułu jest Jakub ‘unknow’ Mrugalski – właściciel serwisu UW-Team.org. Chcesz umieścić na Niebezpieczniku swój tekst? Daj nam znać.

Blip.pl to mówiąc w skrócie polski odpowiednik Twittera. Serwis istnieje od połowy 2007 roku i cieszy się coraz większą popularnością. Mniej więcej od startu serwisu istniała w nim luka umożliwiająca przejęcie pełnej kontroli nad kontem dowolnego użytkownika Blipa.

Opisywana poniżej luka została zgłoszona do administracji serwisu i jest już załatana. Artykuł jest więc przykładem tzw. responsible disclosure.

Wstępna analiza serwisu

Aby dodać coś do serwisu, należy najpierw przeanalizować, w jaki sposób przebiega operacja dodawania nowego wpisu na kokpit Blipa. W tym celu posłużyłem się przeglądarką Mozilla Firefox, wyposażoną w plugin HttpFox, służący do analizy zapytań wysyłanych do serwera WWW.

Po zalogowaniu na konto testowe w atakowanym serwisie, włączyłem analizę zapytań we wspomnianym pluginie i dodałem na swój kokpit nowy wpis w standardowy sposób. Moim oczom ukazało się odwołanie:

Analiza żądania

Na powyższym screenie widać, że w momencie dodawania nowego wpisu, do obiektu /updates przesyłane są cztery zmienne. Są to kolejno:

  • authenticity_token – token zabezpieczający
  • user_id – nadawca wiadomości (niespodzianka, to nie INT lecz STRING)
  • update[body] – treść wiadomości
  • recipient_id – odbiorca wiadomości

Mamy tutaj styczność z dwoma tajemniczymi zmiennymi – recipient_id oraz authenticity_token. Pierwsza ze zmiennych zawiera definicję odbiorcy wiadomości (jeśli jest to tekst prywatny) lub jest ustawiona na 0 jeśli dany wpis ma być nowym statusem na Blipie. Druga ze zmiennych to zabezpieczenie mające na celu autoryzowanie każdej wykonywanej akcji. Moje testy wykazały, że przesyłany token jest stały i niezależny od treści wysyłanego zapytania.

Wniosek jest więc prosty. Aby dodać tekst na kokpit dowolnego użytkownika, musimy znać jego login oraz token zabezpieczający.

Przygotowanie do ataku

Gdy dowiedziałem się już co i gdzie należy wysłać aby przeprowadzić udany atak, nie pozostało mi nic innego, jak przygotowanie formularza HTML do wysyłania odpowiednio spreparowanych danych.

Formularz do przesyłania danych

Ważne elementy kodu:

  • linia 4 – definicja adresu docelowego i metody wysyłki danych
  • linie 5-8 – definicja wysyłanych danych (nazwy pól wzięte z HttpFoxa)
  • linia 11 – automatyczne wysyłanie formularza po wejściu na stronę

Formularz po ręcznym uzupełnieniu danych w kodzie strony, natychmiast po jej załadowaniu dodaje wpis na Blip.pl. Sprawdziłem kod na sobie — działał idealnie. Pojawił się tylko jeden mały problem: nie znałem loginu osoby która wejdzie w moją pułapkę, a także nie miałem tajnego tokenu zabezpieczającego.

Wykradanie loginu i tokena z Blipa

Chcąc zautomatyzować działanie wcześniej utworzonego kodu, należy go dynamicznie wypełniać danymi zalogowanego użytkownika. W tym celu niezbędne jest zlokalizowanie położenia tych danych w obrębie serwisu.

Poszukiwania nie trwały zbyt długo. Gdzie Blip może trzymać tajne dane z kodem autoryzacyjnym niezbędnym do podpisywania każdej operacji? Odpowiedź jest prosta — wszędzie!

Każda ze stron serwisu po zalogowaniu, zawiera w swojej stopce token bezpieczeństwa, wpisany tam plaintextem.

Wystarczyło więc pobrać ten kod i wrzucić go do formularza.

Pobranie nazwy użytkownika również nie stwarzało problemu, ponieważ podobnie jak token zabezpieczający, tak i ona występowała na każdej stronie serwisu — tym razem jednak w nagłówku.

Scenariusz ataku na Blip.pl

Newralgiczne dane dotyczące użytkownika są dostępne jedynie dla niego i nikt z zewnątrz nie może ich odczytać. Tego rodzaju “problem” zwykle rozwiązuje się za pomocą ataków XSS. W tym przypadku jednak, po niemal godzinnym poszukiwaniu luk tego typu, okazało się, że Blip jest na nie odporny. [niezupełnie… — przyp. red. :>]

Jaka inna technologia typu client-side może wykonywać operacje w serwisie poza JavaScriptem, którego z racji braku luk XSS nie mogłem tam wstrzyknąć? Oczywiście może to zrobić Flash. Jest tylko jedno “ale”…

Bezpieczeństwo Flasha

Technologia Flash umożliwia operacje na plikach dowolnego serwisu internetowego, pod warunkiem, że jego właściciel wyraził na to zgodę. Tego rodzaju zgodę można wyrazić poprzez umieszczenie pliku “crossdomain.xml” w katalogu głównym domeny.

Aplikacja flashowa przed odwołaniem do danego serwisu, pobiera jego plik crossdomain.xml z regułami bezpieczeństwa, określającymi który serwis i na jakich prawach może operować na konkretnej domenie. Na podstawie zawartych tam informacji, podejmowana jest decyzja o kontynuacji lub przerwaniu żądania.

Idea bezpieczeństwa zaprojektowana przez twórców Flasha jest dość dobra. Niestety jak to zwykle bywa w takich sytuacjach, zawodzi czynnik ludzki. Wielu webmasterom nie chce się napisać szczegółowej polityki bezpieczeństwa i rozwiązują problemy z odbieraniem żądań od zewnętrznych serwisów, dodając wszystkie domeny do zaufanych.

Podobnie było z serwisem Blip.pl — poniższy screen to prawdziwa polityka bezpieczenstwa, jaka obowiązywała tam jeszcze kilka dni temu.

Crossdomain.xml serwisu Blip.pl

Przygotowanie exploita na Blipa

Wiemy już, że exploit pobierający dane z Blip.pl musi być stworzony w technologii Flash i musi zostać uruchomiony przez zalogowanego użytkownika tego serwisu. Przygotowując kod Flashowy będziemy oczywiście potrzebowali… Flasha, a konkretnie jego kompilatora. Jako że nie przepadam za komercyjnymi rozwiazaniami, zdecydowałem się na użycie pakietu SWFTools, w skład którego wchodzi między innymi konsolowy kompilator flasha o nazwie “swfc“.

Gotowy kod złośliwego kodu prezentuje się następująco:

(Flash) Exploit na Blipa

Skrypt w języku ActionScript mieści się w liniach od 9 do 18 i to on jest sednem ataku. Pozostała część kodu to elementy składowe języka stosowanego w kompilatorze “swfc”.

    Krótkie omówienie kodu exploita

    Program startuje od linii numer 16, w której tworzony jest nowy obiekt typu LoadVars. Służy on w ActionScript do ładowania zmiennych z zewnętrznego pliku. Kolejna linia definiuje gdzie znajdują się zmienne do pobrania — wskazujemy oczywiście stronę główną Blipa. Linia numer 18 ustawia callback dla pobierania danych, czyli uchwyt do funkcji, która zostanie wykonana, gdy Flash wczyta żądaną stronę.

    W momencie pobrania danych z Blipa, wywoływana jest funkcja “zapisz” (linia numer 9) z kodem źródłowym serwisu przekazanym jako parametr. W kolejnych krokach funkcji zapisującej ponownie tworzony jest obiekt typu LoadVars, który ku mojemu zdziwieniu potrafi nie tylko ładować zmienne (jak nazwa wskazuje), ale także wysyłać je metodą POST. W linii 11 następuje definicja danych do wysłania, a w linii 12 dane wysyłane są do skryptu “plik.php” znajdującego się w mojej domenie.

Kod jest gotowy, można go skompilować za pomocą polecenia:

swfc kod.as

Gdzie “kod.as” to oczywiście plik w którym zapisałem powyższy kod. Efektem kompilacji będzie wyjściowy plik “exploit.swf“.

Wymiana danych pomiędzy Flashem a PHP

Mamy przygotowane 2 niezależne części naszego ataku: kod pobierający dane z serwisu oraz formularz do ich ponownego przesłania. Potrzebujemy jeszcze jednego elementu, czyli skryptu obrabiającego dane wykradzione przez flasha i umieszczającego je w formularzu. W tym celu przygotowałem poniższy kod:

Parser danych

Kod jest na tyle prosty, że ogranicza się jedynie do wykonania dwóch wyrażeń regularnych — jedno do pobrania tokena (linia 3), a drugie do pobrania loginu (linia 5). Po zgromadzeniu niezbędnych danych generowany jest formularz znany z początku tego artykułu.

Mamy już wszystko co jest potrzebne do ataku. Oba pliki, czyli SWF i PHP wrzucamy na dowolny serwer internetowy, a następnie podajemy “ofiarze” linka do pliku SWF. Po jego kliknięciu, na kokpicie ofiary pojawia się ustalony przez nas tekst.

Skutki ataku

Cel moich testów został osiągnięty — byłem w stanie wysyłać informacje na kokpity użytkowników bez ich zgody. Po dokładniejszym zbadaniu serwisu Blip, okazało się jednak, że zyskałem tym atakiem znacznie większe możliwości niż początkowo myślałem.

Każda z akcji wykonywanych w serwisie autoryzowana jest tokenem, który jest niezmienny dla danego użytkownika. Oznacza to, że raz wykradziony token może być np. magazynowany w bazie danych i wykorzystany w późniejszym czasie np. do rozsyłania spamu lub wykonania dowolnej akcji w serwisie.

Wykorzystując ten błąd agresor jest w stanie:

  • dodawać nowe wpisy na kokpit
  • usuwać wpisy archiwalne
  • dodawać i usuwać osoby z listy “obserwowanych”
  • zmienić hasło użytkownika (Blip nie wymaga znajomości starego hasła!)
  • zmienić skórkę blipbloga na dowolną (np. wstawić tam reklamę)

Opisany tutaj błąd został naprawiony tydzień temu przez programistów blip.pl — należy jednak pamiętać, że na przedstawiony tutaj atak narażone są wszystkie serwisy internetowe mające podobną do Bipa politykę bezpieczeństwa w crossdomain.xml.

Przypis redakcji: na opisany przez unknowa błąd zwracaliśmy Wam uwagę w kwietniu, w tekście Jak poprawnie skonfigurować plik crossdomain.xml, sugerując wtedy między wierszami (a dokładniej screenami), że na atak podatny jest serwis Blip.pl

P.S. Między innymi właśnie na tego typu case-study możecie liczyć podczas naszych szkoleń z atakowania i ochrony webaplikacji.

Przeczytaj także:


23 komentarzy

Dodaj komentarz
  1. to już wiem skąd tyle dziwnych wpisów było :P

  2. Zaiste piękne :)

    Fail #1 to oczywiście crossdomain.xml. (na teraz chyba usunęli ten plik w ogóle)

    Fail #2 – token, który jest stały (w tym momencie stały na czas sesji, a z tego, co piszesz wnioskuję, że kiedyś był stały dla usera).
    O ile pierwszą rzecz naprawili, o tyle druga wciąż pozostawia blip.pl otwartym na CSRF. Trzeba tylko znaleźć jakiegoś XSSa, żeby przechwycić token.

  3. Pod koniec zeszłego roku odkryta została luka XSS w BlipAPI, ale wtedy niebezpiecznik dopiero się rozkręcał więc nic nie wiedzieliście :)

  4. Token stały na czas sesji nie jest przypadkiem rzeczą normalną w Ruby on Rails?

  5. Tak proste a tak skuteczne :)

    Ale skąd im przyszedł pomysł na używanie stałego tokena wpisanego prosto w kodzie strony? Chyba ktoś musiał to po godzinach robić :)

  6. Jeszcze można przechwycić kokpit i prywatne wiadomości.

  7. polecam dodatek Live HTTP Headers do Firefoxa – nie trzeba tworzyć strony wysyłającej taki POST do blipa, wystarczy przez ten dodatek zmodyfikować wysyłany POST ;]

  8. @unknow – Good work :)
    Dzięki za case study, świetnie się czyta :) (widać, że sporo nad tym siedziałeś… tu CSRF, tam flash i crossdomain…)

  9. inurl:crossdomain.xml

    Ciekawe rzeczy się ukazują. :)

  10. @shaql: moim celem było zaatakowanie DOWOLNEGO usera, a nie modyfikacja danych w mojej przeglądarce. Z tego powodu formularz (lub ‘coś’ na jego miejsce – np. CURL) był konieczny.

  11. Mały OT: czy jest jakaś różnica w funkcjonalności pomiędzy HttpFox a TamperData?

  12. @Tomasz: Zwlaszcza jak zajrzysz w nie :) Na przyklad zumi.pl czy viva-tv.pl :). Choc jest wiele dobrze ustawionych :)

  13. Hej,
    nadal nie rozumiem jednej rzeczy: jak tym flashem wyciągnięty jest ten token? Powiedzmy, że mamy login użytkownika, i zupełnie nie rozumiem skąd mamy kod strony po zalogowaniu tego usera (bo tam jest zawarty ten token, tak?)?

  14. @Staszek: trik polega na tym, że flasha musi uruchomić osoba którą chcesz zaatakować. Nie możesz tego zrobić Ty. Jeśli uruchomi to ofiara ataku, to flash wczytuje dokładnie taką wersję strony głównej blipa, jaką widzi ta osoba – a więc z tokenem i jej loginem, które następnie są przesyłane do pliku PHP.

  15. Małe sprostowanie. authenticity_token jest domyślną metodą na ochronę przed CSRF w Ruby on Rails i nie jest niezmienny dla użytkownika. Jest stały tylko w obrębie sesji.

  16. Ciekawie może być jak się ‘scriptkidy’ dorwią do crossdomain.xml na paru stronach…

  17. […] proces przejęcia konta dokładnie opisano w notce pt. “Atak na Blip.pl (przejęcie konta dowolnego użytkownika)“. Dziura na szczęście została naprawiona przed opublikowaniem notki, także generalnie nie […]

  18. Tu warto zwrócić uwagę na jeszcze jedną rzecz. Po przejęciu sesji nie można zmienić lub usunąć konta, bo do tego potrzebne jest hasło użytkownika. Dość naturalną drogą na rozwiązanie tego “problemu” jest wykorzystanie funkcji przypominania/resetowania hasła. W tym celu dobrze byłoby zmienić adres e-mail związany z kontem. Tu akurat zmianę taką można zainicjować bez podawania hasła. Jesteśmy w domu? Prawie :) Choć pojawia się komunikat “Na podany adres e-mail wysłana została wiadomość weryfikująca zmianę”, to wiadomość jest w rzeczywistości wysyłana na adres e-mail obecnie aktywny, a nie ten podany przy zmianie. Ot taka ciekawostka :)

  19. @Unknow: Ale zaraz, zaraz, gdzie ten flash musi byc umieszczony? Jak go ta osoba odpala? Ma byc zamieszczony na blipie? Czy chocby na naszej stronie? I dlaczego zaladowanie strony blipa z flasha laduje ja zalogowana? Ja tutaj ciagle nie widze jak mozna wyciagnac od kogos ten token.

  20. @Staszek
    To jest normalny CSRF, czyli flash jest umieszczony na serwerze www kontrolowanym przez atakującego, a atakujący musi jakoś przekonać usera żeby tam wszedł (np. wysyłając jakiegoś socjotechnicznego mejla/privmsg typu “to ty na tych fotkach? http://ev.il/fotki.jpg“)

  21. @Gynvael Coldwind: Czyli wystarczy, ze user otworzy strone na moim serwerze, i na tej stronie bedzie flash, ktory sie polaczy z blipem, i blip zwroci flashowi zalogowana strone?! Kto to wymyslil, przeciez to masakra… Bez sensu to jest, flash powinien byc jak najbardziej uruchamiany w jakims sandboxie, myslalem, ze mniej wiecej tak wlasnie jest…

  22. […] pod kątem znajdowania podatności (tu warto wspomnieć o opublikowanym niedawno na Niebezpieczniku ataku na Blipa, który wpisuje się w tą […]

  23. […] pomoc zaoferował Unknow z Uw-Team.org (którego znacie m.in. z kapitalnych artykułów o atakach na Blip i analizie złośliwych aplikacji na Facebooku). Bez pomocy Unknowa dziś najprawdopodobniej […]

Twój komentarz

Zamieszczając komentarz akceptujesz regulamin dodawania komentarzy. Przez moderację nie przejdą: wycieczki osobiste, komentarze nie na temat, wulgaryzmy.

RSS dla komentarzy: