Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Clickjacking i dwie kropki – opis błędu w Facebooku
Jedną z wielu funkcji udostępnianych przez Facebooka, obok takich jak pisanie nowych postów, czatowanie ze znajomymi czy wrzucanie nowych zdjęć, jest możliwość wykorzystania logowania na konto facebookowe z użyciem Registration Plugin. Rozwiązanie takie ma być wygodniejsze dla użytkowników, którzy nie muszą wpisywać swoich danych dziesiątki razy na różnych stronach, ale pozwolą Facebookowi udostępnić ich publiczne dane innym stronom. Przyjrzyjmy się jak wygląda proces rejestracji do jednej ze stron.
Registration Plugin
Poniższy link umożliwia zarejestrowanie się danymi z Facebooka w aplikacji FriendFeed:
Po kliknięciu „Zarejestruj się”, generowane jest zapytanie POST do adresu wskazanego w parametrze redirect_uri, zawierające widoczne na ekranie dane publiczne o użytkowniku oraz access_token, który, z użyciem facebookowego API, umożliwi aplikacji dostęp do listy znajomych.
Jak podaje Facebook w jednym z postów na blogu o tym pluginie, założenie jest takie, że plugin będzie osadzany w elemencie iframe na stronach, które będą chciały korzystać z tego typu logowania. Oznacza to, że z definicji ta strona jest podatna na Clickjacking.
Krok 1. Clickjacking
Clickjacking to atak, w którym na stronie zostaje umieszczony niewidoczny iframe, nad którym znajduje się inny widoczny obiekt – np. napis „Kliknij tutaj, aby wygrać 1000$”. W rzeczywistości, gdy użytkownik klika na ten napis, kliknięcie jest przechwytywane przez iframe będący pod spodem; wykonywana jest więc akcja z zupełnie innej podstrony niż mogło się wydawać.
Najlepiej będzie to zobrazować na przykładzie – spod adresu http://jsfiddle.net/Lg657ypz/show/. Po wejściu na stronę widzimy tylko niewinnie wyglądający przycisk „click me plox”.
Na pierwszy rzut oka trudno byłoby powiedzieć, że z tą stroną coś jest nie tak. Jednak gdy użyjemy przycisku „click!” w górnej części strony, zobaczymy, że w rzeczywistości pod „Click me plox” kryje się strona rejestrująca z Facebooka.
Zatem, po kliknięciu „Click me plox”, użytkownik zarejestrowałby się w pluginie friendfeed, co z całą pewnością nie byłoby oczekiwanym przez niego rezultatem.
Krok 2. Redirect_uri
Clickjacking sam w sobie nie byłby aż tak groźny w przypadku tego błędu. Zarejestrowanie się do niepożądanej strony można łatwo odkręcić, korzyści dla atakującego też nie są zbyt duże – w przedstawianym przeze mnie przypadku, użytkownik zostałby zarejestrowany do aplikacji FriendFeed, która jest i tak zarządzana przez Facebooka. Dane prywatne więc nigdzie nie wyciekają.
Jak wcześniej wspominałem, po zarejestrowaniu się, Facebook przekierowywał pod zasób wskazywany przez parametr redirect_uri. Co istotne, okazało się, że parametr ten nie jest sprawdzany względem białej listy (a więc nie ma stałej listy dopuszczalnych wartości), a jest w jakiś sposób walidowany. Konkretniej: dopuszczane były tylko poddomeny domeny głównej friendfeed.com. W przypadku podania domeny nienależącej do friendfeed.com, Facebook odpowiadał tylko białą stroną.
Pomyślałem, że skoro jest dopuszczalna pewna dowolność w adresach, to być może funkcja walidująca redirect_uri zawiera jakiś błąd, który będzie się dało wykorzystać do wyjścia na inną domenę. Okazało się, że intuicja mnie nie zawiodła, choć błąd jest do wykorzystania w niewielkiej części systemów.
Próbowałem stosować różne tricki w adresach do redirecta i okazało się, że przepuszczane są dowolne adresy, które zawierają sekwencję wielu kropek w nazwie domeny. Na przykład adres http://sekurak..pl/ został uznany za poprawny.
Początkowo uznałem, że niewiele mi to daje, gdyż nazwa domenowa sekurak..pl nie jest poprawna i nie powinna w ogóle przejść przez rozwiązywanie nazw. Postanowiłem jednak sprawdzić jak zachowują się różne przeglądarki i znalazłem dosyć interesującą ciekawostkę: Chrome na OSX i Linuksie traktuje każdą sekwencję wielu kropek w nazwie domeny tak, jakby była tam jedna kropka! Jeśli nie wierzycie, a używacie Chrome na jednym z tych dwóch systemów, to spróbujcie kliknąć na tego linka ;) (wprawdzie w odpowiedzi dostaniecie Bad Request, ale zapytanie http zostanie wysłane; żadna inna przeglądarka nie wyśle nawet zapytania, bo nie rozwiąże nazwy DNS).
Pozostało więc tylko przygotować Proof of Concept, w którym użytkownik zostaje przekonany do kliknięcia na rejestrację z użyciem Clickjackingu, a wychodzące zapytanie POST z jego danymi osobowymi zostaje przekierowane moją domenę bentkowski.info (albo bentkowski..info ;)). Dowód, że atak działał, na poniższym filmiku:
Podsumowanie
W artykule pokazałem, w jaki sposób można było doprowadzić do wycieku danych osobowych użytkownika Facebooka wykorzystując w sumie trzy problemy:
- Clickjacking w formularzu rejestracyjnym,
- Dopuszczanie niepoprawnych nazw domen w parametrze redirect_uri,
- Traktowanie niepoprawnych nazw domen jako poprawnych przez Chrome na OSX i Linuksie.
Jest to też dosyć ciekawy przypadek, że podatności client-side warto sprawdzać na różnych konfiguracjach przeglądarek i systemów operacyjnych.
Błąd został zgłoszony w ramach facebookowego programu bug bounty i został już naprawiony.
Piotr S
Ładnie opisane.
Między innymi z uwagi na podejście facebooka do „zagrożeń” związanych z clickjackingiem używam disconnecta i każdemu polecam.
No third-party cookies i po kłopocie.
Czyli problemem bylo nieustawione na stronie x-frame-options?
Ile $ wpadło?
X-frame-options na pewno pozostanie nieustawione, bo, zgodnie z tym co pisałem, tamta podstrona w założeniach ma być umieszczana w iframe w innych domenach. Dlatego x-frame-options zabiłoby jej sens.
A problemem było niepoprawne walidowanie redirect_uri i to specyficzne zachowanie Chrome’a.
Dzięki, ciekawe i przystępnie opisane. Zastanawiam się: skoro działało na Linuksie i OSX, to co z Chrome na Androidzie? Biorąc pod uwagę niszowość Linuksa i OSX miał to być szanse największy wektor ataku.
Fakt, nie pomyślałem wcześniej o mobilnych. Ale sprawdziłem na androidowym Chromie i nie działało tam. Być może będzie to jeszcze zależne od wersji Chrome’a/Androida.
atak nie będzie działał jeśli ktoś nie ma konta na fb ;] ;] ;] ;] ;]
Kto jest autorem odkrycia ? Michal czy xorb?
50% xorb, 50% ja ;)
Wciągasz rogale?