Możliwość zdalnego wykonania kodu jest jednym z rzadziej spotykanych i wyżej wycenianych rodzajów błędów w aplikacjach internetowych. Odkrycie takiego błędu na serwerach Facebooka jest bez wątpienia przypadkiem wartym bliższej analizy.
Facebook znany jest z wysokiego poziomu bezpieczeństwa swojej infrastruktury. Duży zespół, szybka reakcja na zgłoszone problemy i tysiące ekspertów z całego świata testujących od kilku lat całą platformę w ramach programu Bug Bounty sprawiają, że odnalezienie nowego błędu nie jest trywialne. Jak zatem brazylijski badacz trafił na możliwość zdalnego wykonania kodu?
Najwyższa nagroda w historii
Kilka godzin temu Facebook ogłosił, że wypłacił 33 500 USD nagrody w ramach programu Bug Bounty dla brazylijskiego badacza. Reginaldo Silva odnalazł na serwerach Facebooka błąd, pozwalający na zdalne odczytanie pliku znajdującego się na serwerze oraz przesłał pomysł na to, jak błąd ten wykorzystać do zdalnego wykonania kodu po stronie serwera. Zespół Facebooka potwierdził istnienie problemu i doceniając sposób, w jaki Reginaldo zgłosił problem i jego znaczenie postanowił przyznać najwyższą nagrodę w historii programu. Sam bohater historii podzielił się z internautami historią swojego ciekawego odkrycia.
Historia odkrycia
Historia odkrycia błędu zaczyna się we wrześniu 2012, kiedy to Reginaldo zlokalizował błąd typu XML External Entity (XXE) Expansion w kodzie Drupala odpowiadającym za obsługę OpenID. Błąd ten polega na możliwości wskazania na lokalny zasób (w tym wypadku plik), który zostanie pobrany z serwera i przesłany do klienta. W ten sam sposób można także np. nawiązywać połączenia sieciowe (wskazując na zdalne zasoby) czy też przeprowadzić atak typu DDoS.
Reginaldo odkryty błąd odpowiedzialnie zgłosił, dostał nawet swoje pierwsze CVE, a kilka dni później doznał olśnienia – przecież podobny błąd może występować w innych implementacjach OpenID. Znalazł go np. na serwerach StackOverflow a następnie także na serwerach Google: App Engine i Blogger. Google było podatne tylko na atak DDoS, ale i tak zasłużył na swoje pierwsze Bug Bounty w wysokości 500 dolarów. Kiedy zaczął analizować popularne implementacje OpenID okazało się, że błąd istnieje w bibliotekach napisanych w Javie, C#, PHP, Ruby, Pythonie, Perlu i wielu innych. Zgłosił ten problem autorom bibliotek oraz społeczności OpenID i błąd został w większości przypadków załatany.
No dobrze, a co z Facebookiem?
Reginaldo pamiętał, że Facebook kiedyś oferował możliwość użycia OpenID, ale nie mógł już znaleźć tej funkcji na serwerze (została wyłączona). Dopiero ponad rok później przez przypadek natrafił na ciekawy link w funkcji odzyskiwania hasła:
https://www.facebook.com/openid/receiver.php
Był to link, umożliwiający zalogowanie się do Facebooka poprzez konto Google. Reginaldo natrafił jednak na poważny problem. Aby jego exploit zadziałał, musiał zmusić serwer Facebooka do odpytania serwera dostawcy OpenID znajdującego się pod jego kontrolą, a mechanizm Facebooka kontaktował się tylko z serwerami Google. Dopiero wnikliwa lektura standardu OpenID pozwoliła mu znaleźć opcję, dzięki której zmusił Facebooka do kontaktu ze swoim serwerem poleceniem
GET /openid/receiver.php?provider_id=1010459756371 &context=account_recovery&protocol=http&request_id=1 &openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0 &openid.mode=id_res&openid.op_endpoint=...(redacted)... HTTP/1.1
a dzięki odpowiedniemu zachowaniu własnego serwera w odpowiedzi od Facebooka dostał…
root:x:0:0:root:\/root:\/bin\/bash\n \ bin:x:1:1:bin:\/bin:\/sbin\/nologin\n \ daemon:x:2:2:daemon:\/sbin:\/sbin\/nologin\n \ adm:x:3:4:adm:\/var\/adm:\/sbin\/nologin\n \ lp:x:4:7:lp:\/var\/spool\/lpd:\/sbin\/nologin\n \ sync:x:5:0:sync:\/sbin:\/bin\/sync\n \ shutdown:x:6:0:shutdown:\/sbin:\/sbin\/shutdown\n \ halt:x:7:0:halt:\/sbin:\/sbin\/halt\n \ mail:x:8:12:mail:\/var\/spool\/mail:\/sbin\/nologin\n \ uucp:x:10:14:uucp:\/var\/spool\/uucp:\/sbin\/nologin\n \ operator:x:11:0:operator:\/root:\/sbin\/nologin\n \ games:x:12:100:games:\/usr\/games:\/sbin\/nologin\n \ gopher:x:13:30:gopher:\/var\/gopher:\/sbin\/nologin\n \ ftp:x:14:50:FTP User:\/var\/ftp:\/sbin\/nologin\n \ nobody:x:99:99:Nobody:\/:\/sbin\/nologin\n \ dbus:x:81:81:System message bus:\/:\/sbin\/nologin\n \
Ekspresowa naprawa
Reginaldo po krótkim zastanowieniu przesłał zgłoszenie o błędzie do zespołu bezpieczeństwa Facebooka. Kiedy kilka godzin później wrócił z obiadu błąd był już załatany. Facebook był w stanie w ciągu 3,5 godziny zweryfikować błąd, stworzyć szybką łatę oraz wdrożyć ją na wszystkich serwerach. Wystarczyło dodać wpis:
libxml_disable_entity_loader(true);
Z jednej strony trzeba przyznać Facebookowi, że czas reakcji i wdrożenia łaty mają imponujący i trudno sobie wyobrazić, by ktoś był w stanie go znacząco skrócić. Z drugiej strony błąd wygląda na dość trywialny i aż dziwne, że nie został wykryty poprzez wewnętrzne procedury weryfikacji (szczególnie biorąc pod uwagę fakt, że był znany od ponad roku).
Reginaldo niestety nie zdążył przetestować swojego pomysłu na zdalne wykonanie kodu z użyciem tego błędu, jednak kiedy przesłał koncepcję przeprowadzenia takiego ataku Facebookowi, inżynierowie potwierdzili, że faktycznie mógł się on udać. Z tego też względu nagroda wypłacona Reginaldo była odpowiednio wyższa.
Dziękujemy Peterowi za podesłany link
Komentarze
„Google było podatne tylko na tak DDoS”
Chochlik się wkradł
Dzięki, poprawione
no nie do konca.. bo to nie jest atak Distributed Denial of Service…
poprawnie powinno byc DoS… wywalasz serwis nie sypiac masa zapytan, tylko jednym ale konkretnym ;p
Co na serwerze Facebooka robi Gopher?
Wybaczcie, ale razi mnie 33,500 USD. W Polsce w takim miejscu stawiamy kropkę, nie przecinek. :)
Wybaczamy. Spacja wstawiona, nasze przeoczenie.
Michal: A tak naprawdę to stawiamy spację a nie przecinek :)