25-11-2019 / Podcast

IMDSv2 - Amazon EC2 Instance Metadata Service

Wprowadzenie

Jeżeli korzystasz z usług Amazona, a w szczególności z serwerów EC2, jest spora szansa, że termin SSRF nie jest dla Ciebie niczym nowym.

Jeżeli jednak nie wiesz co on oznacza i jakie konsekwencje za sobą niesie - ten podcast jest dla Ciebie.

Opowiem w nim na czym polega podatność Server Side Request Forgery, a także o nowości - Instance Metadata Service w wersji drugiej, która ma pomóc rozwiązać ten problem.

Klucze API

 Klucze API

EC2 pozwala na tworzenie w locie wirtualnych instancji serwerów, które mogą być przez nas używane do różnorakich celów.

Powoli odchodzi się od aplikacji, w których wszystko dzieje się na jednej maszynie.

Nadchodzi czas mikroserwisów, gdzie każda niewielka funkcjonalność zaimplementowana jest jako osobny byt.

Takie podejście ma wiele plusów, ale za nimi podążają nowe problemy, które trzeba rozwiązać.

Jak bowiem zarządzać hasłami i kluczami API w tak dynamicznie zmieniającym się środowisku?

Wpisywanie haseł na sztywno w kodzie aplikacji to nie jest najlepszy pomysł.

Każdorazowa zmiana hasła bowiem wymagałaby restartu aplikacji.

Metadata Service

 Metadata Service

Wiedzieli o tym twórcy EC2, dlatego też udostępnili specjalny mechanizm - Metadata Service, mający rozwiązać ten problem.

Każda maszyna może mieć dostęp do różnych zasobów.

Kiedy zajdzie konieczność skorzystania z nich, nie będzie mogła bezpośrednio się do nich odwołać, ale musi wykonać jedną, dodatkową czynność.

Najpierw wysyła żądanie do Metadata Service, a usługa ta zwraca odpowiednie klucze, które następnie mogą być używane przez aplikacje.

Czyli jeżeli chcemy umieścić jakiś plik w usłudze S3, nasza aplikacja najpierw łączy się z Metadata Service, a następnie wykorzystując tak zdobyte informacje, może połączyć się z usługą S3.

Metadata Service jest dostępny pod konkretnym adresem IP - takim samym dla wszystkich maszyn.

Jest to 169.254.169.254.

Jak na razie wszystko wydaje się być w porządku.

No ale to przecież podcast o bezpieczeństwie.

Server Side Request Forgery

 SSRF

I tu do gry wchodzi SSRF - czyli Server Side Request Forgery.

Na świecie istnieją bowiem różne aplikacje robiące różne rzeczy.

Część z tych aplikacji może dla przykładu pobierać od użytkownika adres strony, a następnie wyświetlać jej treść.

Jest to więc swego rodzaju serwer PROXY, który to może być używany w celu ominięcia cenzury lub też geolokalizacji.

Niektóre strony bowiem działają jedynie gdy klient łączy się ze specyficznego rejonu świata.

Programista udostępniając taką funkcjonalność, może pozwolić na wyświetlanie takiej strony również innym użytkownikom.

 Problem

I tutaj dochodzimy do sedna problemu.

Jeżeli użytkownik może podać dowolny adres - może też podać adres, pod którym dostępne są dane z Metadata Service.

W taki oto sposób pozyskuje dostęp do danych, umożliwiający dostęp do zasobów, do których dostęp ma konkretna instancja EC2.

A to jest niebezpieczne.

Błędy tego rodzaju są coraz popularniejsze, a to wszystko za sprawą rosnącej popularności rozwiązań chmurowych.

Jeżeli jesteś zatem programistą - co powinieneś zrobić?

Jak się obronić?

Istnieją odpowiednie narzędzia, które sprawdzają wprowadzany przez użytkownika adres i weryfikują, czy czasem nie należy on do Metadata Service.

To dobre rozwiązanie, ale ma jeden minus.

Programista musi być świadomy, że jego kod może być użyty do ataku SSRF.

W innym bowiem wypadku - nie użyje odpowiedniej biblioteki.

Z drugiej strony nie można filtrować wszystkich danych wprowadzanych przez użytkownika gdziekolwiek - bo to nie ma sensu.

Nie jest możliwe zatem globalne zabezpieczenie się poprzez używanie jakichś frameworków.

No bo wyobraźmy sobie prosty internetowy notatnik - gdzie użytkownik może zapisywać swoje notatki na później.

Gdybyśmy poszukiwali adresów IP w każdej notatce - niemożliwe byłoby stworzenie notatki na temat błędu SSRF, w którym znajdowałby się konkretny adres IP.

A przecież nie o to chodzi.

IMDSv2

Po paru latach Amazon zauważył jak naglący jest to problem i zaproponował nowe rozwiązanie.

Nazwano je IMDSv21.

Jednocześnie pozostawiono starą wersję v1, ponieważ nowa wprowadza niekompatybilne zmiany.

Na czym więc one polegają?

Problemem w SSRF są miejsca w kodzie strony, które przyjmują adres, a następnie pobierają z niego treść i wyświetlają ją użytkownikowi.

 Metoda GET/POST

Tylko, że przesyłając jakieś dane w Internecie możemy użyć kilku rodzajów metod.

Najpopularniejsza to GET - kiedy to wszystkie podane przez nas parametry są widoczne w adresie URL w przeglądarce.

Takie rozwiązanie nie jest jednak najwygodniejsze podczas przesyłania większej ilości informacji - stąd też metoda POST.

W przypadku błędów użytkownik zazwyczaj kontroluje adres, ale rzadko zdarza się, aby miał wpływ na metodę, która zostanie użyta.

Amazon postanowił więc skorzystać z rzadkiej metody PUT.

 PUT

Teraz, nasza aplikacja podczas pierwszego kontaktu z Metadata Service musi połączyć się korzystając właśnie z tej metody.

Żeby było jeszcze trudniej, musi także dołączyć specjalny nagłówek X-aws-ec2-metadata-token-ttl-seconds.

Tylko tak skonstruowane żądanie zwróci w odpowiedzi specjalny token, ważny przez określoną w nagłówku ilość sekund.

Teraz można już łączyć się z Metadata Service w normalny sposób, tak jak robiono to wcześniej - czyli poprzez metodę GET.

Wymagane jest jednak umieszczenie pobranego wcześniej ciągu znaków w nagłówku X-aws-ec2-metadata-token.

Cały ten mechanizm można więc porównać do pewnego rodzaju logowania.

Najpierw weryfikujemy, czy mamy dostateczne uprawnienia, aby korzystać z usługi.

W tym wypadku - czy możemy łączyć się korzystając z metody PUT, a także dodawać do żądania odpowiedni nagłówek.

Amazon weryfikuje czy wszystko się zgadza i w odpowiedzi zwraca nam token.

Teraz każde kolejne żądanie musi być nim potwierdzone.

Reverse Proxy

 Reverse Proxy

Ale to nie wszystko.

Postanowiono zabezpieczyć się jeszcze przed dodatkowymi atakami.

Obecnie popularne są serwery Reverse Proxy.

W normalnym podejściu do oprogramowania login i hasło użytkownika musi być sprawdzane na każdym serwerze z osobna.

Mamy więc ten sam kawałek kodu w wielu różnych miejscach, co niezbyt dobrze się skaluje.

W nowoczesnym podejściu - użytkownik łączy się z jednym serwerem, który sprawdza jego login i hasło i jeżeli wszystko się zgadza, przekazuje żądanie dalej, do odpowiedniego serwera.

A więc serwer widoczny z przodu jest kluczowy dla bezpieczeństwa.

Inne serwery bowiem nie mają jak zweryfikować danych, które od niego otrzymały.

Jeżeli otrzymują jakieś pakiety - traktują je jako zaufane, zakładając że serwer reverse proxy zweryfikował wszystko w prawidłowy sposób.

Takie serwery często do żądań dokładają specjalny nagłówek X-Forwarded-For, w którym to znajduje się adres IP klienta, od którego pochodzi dane żądanie.

W innym bowiem wypadku nie ma możliwości dowiedzieć się skąd trafiły informacje - wszak serwer reverse proxy pośredniczy w całej wymianie informacji, a więc to jego adres IP jest widoczny dla serwerów aplikacji.

 X-Forwarded-For

W przypadku błędnie skonfigurowanych serwerów reverse proxy możliwe było pobranie danych z Metadata Service.

Wystarczyło tylko przekonać taki serwer, że chcemy się połączyć właśnie z tą usługą.

Teraz nie będzie to możliwe.

Nawet jeżeli zmusimy serwer do wysłania żądania PUT pod odpowiedni adres, otrzymamy błąd jeżeli tylko Amazon wykryje nagłówek X-Forwarded-For.

Od teraz wszystkie żądania z takim nagłówkiem są bowiem ignorowane.

Serwer VPN

Ale to nie koniec zmian.

Serwery EC2 mogą być bowiem przez niektórych używane chociażby jako serwer VPN.

Tutaj ponownie w przypadku błędnej konfiguracji możliwe było pozyskanie tajnych informacji.

Tylko, że w takim wypadku nie pojawia się dodatkowy nagłówek X-Forwarded-For, który można by było wykryć.

Specjaliści z Amazon podeszli do tego tematu nieco inaczej.

Pakiety w sieci Internet rzadko kiedy trafiają do celu bezpośrednio.

W większości przypadków po drodze natrafiają na wiele serwerów i urządzeń pośredniczących.

 TTL

Pakiety IP posiadają pole TTL - tak zwany Time To Live.

Teoretycznie każde urządzenie, przez które przechodzi pakiet, zmniejsza wartość w tym polu o 1.

Jeśli wartość spadnie do 0 - pakiet nie jest przesyłany dalej.

Jest to zabezpieczenie, mające sprawić aby pakiety nie krążyły w sieci w nieskończoność.

Czasami może bowiem dojść do zapętlenia - gdzie pakiet nie dochodzi do ostatniego serwera, ale krąży pomiędzy innymi.

Standardowe pakiety wartość TTL mają dość wysoką - tak aby na spokojnie trafiły tam gdzie powinny.

Wszystkie pakiety z Metadata Service natomiast mają tą wartość ustawioną na 1.

Taką wartość może odczytać nasz serwer, ale jeśli tylko ten pakiet miałby zostać przekazany gdzieś dalej - poza nasz serwer - nie będzie to możliwe.

Wartość TTL spadnie bowiem do 0, a cały pakiet zostanie odrzucony.

Prawda, że sprytne?

Wnioski

Czy zatem cała ta zmiana to rewolucja?

Niekoniecznie.

Dlaczego?

Obie wersje, v1 i v2, pojawią się na kontach klientów i są włączone "by default".

Klient może jednak ograniczyć, aby jego usługi korzystały jedynie z wersji v2.

 Wnioski

I to właśnie to, że standardowo obie wersje będą działały - jest problemem.

Sam mechanizm wygląda w porządku.

Nie zamyka jednak tematu SSRF w całości, a jedynie chroni przed najpopularniejszymi wariantami.

Jeżeli bowiem atakujący ma możliwość wykonania dowolnego kodu na naszej maszynie - bez problemu pozyska dostęp do usługi w wersji v2.

Wszak może wykonać dowolny kod - nie ma więc problemu z nałożonymi ograniczeniami.

Z drugiej jednak strony rozumiem, dlaczego Amazon nie zdecydował się na bardziej drastyczne podejście.

Zmiany są spore i każda witryna, usługa i programista musi się z nimi zapoznać i wprowadzić je do swoich aplikacji, a następnie przetestować ich działanie.

Kto wie, może w przyszłości standardowa konfiguracja zostanie zmieniona?

Do tego czasu, aby ten mechanizm miał jakikolwiek sens, wymagana jest współpraca ze strony właścicieli stron i usług.

Oni to bowiem muszą wykorzystywać wersję V2 a także wyłączyć wersję V1.

A co wy sądzicie na temat zmian?