W lutym wykrył błąd, pod koniec miesiąca zgłosił go, a kilka dni później znalazł kolejny. W połowie marca Google przyznało mu rację, ale dopiero dwa miesiące później naprawiło błąd i wypłaciło nagrodę młodemu programiście. Co Ezequiel Pereira znalazł w kodzie Google’a?

“Google nagrodziło mnie i wypłaciło 36,337 tys. dolarów!” — cieszy się Ezequiel Pereira, 18-letni początkujący programista z Urugwaju. Wykrył buga w zabezpieczeniach Google’a, o czym powiadomił właścicieli strony. Ci przeanalizowali jego odkrycie i przyznali mu rację. Zobaczcie, co dokładnie młody Ezequiel Pereira znalazł w kodzie.

“Jakiś czas temu zauważyłem, że każdy Google App Engine (GAE) zawiera w headerze “X-Cloud-Trace-Context”. Założyłem więc, że każda strona z takim headerem prawdopodobnie działa w oparciu o GAE” — zaczyna swoją opowieść na blogu. Pereira z wcześniejszego założenia wywnioskował, że strona appengine.google.com także działa w oparciu o GAE, ale wykonuje kilka akcji, które nie są dostępne dla innych użytkowników tego silnika. “Postanowiłem sprawdzić, jak mimo wszystko wykonać te akcje” — dodaje początkujący dev.

Na początku, Ezequiel zaczął uczyć się, w jaki sposób GAE wykonuje akcje, jak np. pisanie logów, czy korzystanie z tokenów OAuth. W ten sposób dowiedział się, że w środowisku Java 8 robi to wysyłając Protocol Buffer bezpośrednio do serwera HTTP zlokalizowanego tutaj: http://169.254.169.253:10001/rpc_http.

W miejscu wiadomości, Pereira wpisał „apphosting.ext.remote_api.Request”, gdzie:

  • service_name = nazwa API do wywołania
  • method = nazwa metody API do wywołania
  • request = wewnętrzne żądanie PB (w formacie binarnym)
  • request_id = ticket bezpieczeństwa (podawany na każde żądanie GAE), wymagany, choć opisany jako opcjonalny

Jeśli chodzi o ticket bezpieczeństwa, to Pereira podaje taki przykład:

Biorąc pod uwagę powyższe odkrycie, jeśli Pereira chciałby uzyskać dostęp do OAuth tokena w zakresie testowym, wykonałby te kroki:

1. Wygeneruj „apphosting.GetAccessTokenRequest” z wiadomością:
scope =
[„https://www.googleapis.com/auth/xapi.

2. Wygeneruj „apphosting.ext.remote_api.Request” z wiadomością:
service_name = „app_identity_service”
(API da ci dostęp do GAE Service Account)
method = „GetAccessTokenRequest”
request = wiadomość PB z poprzedniego kroku, zakodowana w formacie binarnym
request_id = ticket bezpieczeństwa

3. Wyślij zapytanie do HTTP

4. Odpowiedź będzie brzmiała „apphosting.GetAccessTokenResponse”

Wszystko to utwierdziło młodego deva w przekonaniu, że “appengine.google.com” wykonuje akcje, które trudno wykonać innemu użytkownikowi, ale nadal nie wiedział, co mogłoby być tymi akcjami. Pomyślał, że appengine.google.com może używa po prostu innego serwera. Sprawdził to i dowiedział się, że czwarty port serwera jest otwarty, więc postanowił się do niego dostać. W odpowiedzi na wysłane polecenia otrzymał “dziwny zbiór danych”, ale po przyjrzeniu się mu zrozumiał, że to gRPC serwis.

“Próbowałem w Javie stworzyć klienta gRPC, który będzie działał w oparciu o GAE, ale miałem z tym spore problemy, ponieważ biblioteka wydawała się niepełna” — pisze Ezequiel Pereira. Mimo kolejnych problemów, nie poddał się i stworzył klienta w C++. Z tego testu dowiedział się tylko, że API “apphosting.APIHost” ma opcję na JSON. “Ze względu na to, że nic innego się nie dowiedziałem, założyłem, że akcje GAE wewnętrznie kontaktują się z innym serwerem lub używają usług RPC (HTTP / gRPC) do wywoływania ukrytych API / metod” — dodaje. Kolejne założenia Ezequiela brzmiało: GAE musi używać ukrytego API. Nie wiedział jednak, jak je znaleźć.

Przyjrzał się więc bliżej Protocol Buffer w poszukiwaniu jakiegokolwiek śladu ukrytego API. Znalazł obiecujący plik “apphosting/base/appmaster.proto” oraz API nazwane “AppMaster”, ale po kilku testach okazało się, że to nie to, czego od początku szuka. Zaczął więc przyglądać się bliżej plikom binarnym. “Były ogromne i pełne niezrozumiałych dla mnie komend, ale po zauważeniu, że “java_runtime_launcher_ex” ma sporo komend, wpadłem na pomysł, żeby przyjrzeć im się bliżej.

Na początku było to bardzo trudne, ale wymyśliłem, że stworzę bibliotekę Java w C++ z metodą, która odczytującą argumenty przekazane do programu. Wykonanie tego było bardzo proste, a to dzięki społeczności StackOverflow, która rozmawiała wcześniej o tym problemie. Wystarczyło wykorzystać poniższe kilka linijek.

Oto co zobaczył Pereira po wpisaniu powyższej komendy:

Wynik dał Ezequielowi do myślenia. Zrozumiał z niego, że “longservice” to interfejsy API dostępne za pośrednictwem wewnętrznego punktu końcowego HTTP. “Zauważyłem także, że “stubby” było infrastrukturą RPC, dzięki której “appengine.google.com” wykonuje wewnętrze akcje” — pisze na blogu. Poznał więc nazwę wewnętrznego API, ale nie wiedział jakie metody wykorzystuje.

Próbował wywołać kilka z nich, ale za każdym razem otrzymywał komunikat o błędzie. Zaczął więc szukać informacji o nim w sieci i znalazł post z 2010 roku z taką wiadomością: The API call stubby.Send() took too long to respond and was cancelled.

Wpisał więc metodę “Send”, ale i tak nie podziałała. “Byłem pewny, że musi istnieć, więc komunikat pewnie starał się zakryć informację o tym, że istnieje” — napisał na blogu. Szukał więc różnic między komunikatami o błędach. Znalazł je wysyłając request “apphosting.APIRequest.pb” z klienta gRPC. Zobaczył komunikat o błędzie dotyczącym nieistniejącej metody. “Jak jednak wykorzystać te informacje?” — zastanawiał się młody programista.

Przypomniał sobie, że w ramach akcji Google, której celem było wykrycie błędów bezpieczeństwa, otrzymał dostęp do staging-appengne.sandbox.googleapis.com oraz do test-appengine.sandbox.googleapis.com. Po małym researchu, postanowił wykonać te kroki.

1. Pobrać wersję z manualnym skalowaniem

2. Zmienić header “Host” na “<PROJECT-NAME>.prom-<qa/nightly>.sandbox.google.com”.

3. Jeśli aplikacja działa na “save-the-expanse.appspot.com”, powinieneś zmienić <PROJECT-NAME> na “save-the-expanse”. Tak samo zmień <qa/nightly> na “qa”. Dla przykładu, Pereira przetestował “the-expanse.prom-nightly.sandbox.google.com”.

Błąd nr 1

“Kiedy opublikowałem aplikację klienta gRPC, odkryłem, że w środowisku nie-produkcyjnym GAE [staging/test, do którego dostał dostęp, ponieważ brał udział w programie Google’a], mam dostęp do “stubby.Send!” — cieszy się Ezequiel Pereira. “Po szybkich testach (polegających głównie na czytaniu komunikatów o błędach i próbowaniu naprawienia ich) znalazłem sposób na proste wywołanie Subby” — pisze na blogu.

1. Wywołaj “stubby.GetSubId” za pomocą wiadomości JSON PB:

W <HOST> ustaw jaką metodę chcesz wywołać (np. “google.com:80”, “pantheon.corp.google.com:80”, “blade:monarch-cloud_prod-streamz”). Wydaje się, że “blade:<SERVICE>” jest wewnętrznym DNSem dla użytkowników Google.

2. Poprzednie żądanie zwróci nam wiadomość JSON PB “stub_id”.

3. Wywołaj “stubby.Send” z następującą wiadomością JSON PB:

Żeby sprawdzić jakie wartości kryją się za “stubby_method”, ustaw “/ServerStatus.GetServices” z pustym “stubby_request”. Ujrzysz wtedy “rpc.ServiceList” z listą wszystkich serwisów i metod.

4. Jeśli wpisałeś wszystko poprawnie, powinieneś zobaczyć wiadomość JSON PB “stubby_response”.

“Po odkryciu tego, wykonałem kilka testów, ale nie znalazłem niczego groźnego. Mimo to, zgłosiłem lukę Google’owi, a ten nadał jej priorytet P1” — pisze Pereira. Po zgłoszeniu, Ezequiel przejrzał jeszcze raz wszystko, co mogłoby narazić bezpieczeństwo Google’a. Znalazł kolejny błąd.

Błąd nr 2

Pereira odkrył drugie ukryte API. Przeszukując definicje PB natknął się na log “app_config_service”. Później znalazł “apphosting/base/quotas.proto”. Po kilku próbach znalazł “APP_CONFIG_SERVICE_GET_APP_CONFIG”, które okazało się ukrytą metodą “app_config_service.GetAppConfig”. Młody dev szukał dalej luki i znalazł m.in. “app_config_service.ConfigApp” oraz “app_config_service.SetAdminConfig”. To odkrycie także zaraportował Google’owi, który przyjął zgłoszenie, ale zablokował Ezequeielowi dostęp do API.

Po kilku dniach przedstawiciel Google odezwał się z podziękowaniem za wykrycie bugów i z informacją o nagrodzie za poświęcony czas na ich znalezienie. Poziom wynagrodzenia uzależniony jest od stopnia niebezpieczeństwa wykrytych bugów (w ubiegłym roku jeden z devów w nagrodę dostał 112 tys. dolarów). Pereira nie pierwszy raz dostał kasę od Google’a w ramach akcji szukania błędów. Rok temu, w wieku 17-lat, dostał 10 tys. dolarów. Nudził się w szkole i postanowił poszukać bugów w kodzie Google’a. Opłacało się, a zdobyte wtedy środki przeznaczył na sfinansowanie nauki w amerykańskiej szkole.

Zapraszamy do dyskusji
Nie ma więcej wpisów

Send this to a friend