W tym artykule zagłębię się w krótką podróż, która rozpoczęła się po wykryciu tego dziwnego zachowania i ostatecznie doprowadziła do wykrycia luki w zabezpieczeniach desynchronizacji po stronie klienta w jednym z rozwiązań CDN Microsoft Azure, znanym jako Front Door.
Odkrycie
Wszystko zaczęło się, gdy wysłałem następującą prośbę do http://redacted.com :
Skąd taka dziwna prośba? Po prostu bawiłem się w Burp po przeczytaniu fantastycznych badań Jamesa @Albinowaxa Kettle'a na temat ataków desynchronizujących dzięki przeglądarki .
A serwer odpowiedział:
Na pierwszy rzut oka wydaje się, iż nie ma w tym nic niezwykłego. Serwer otrzymał dwa żądania w tym samym połączeniu (podtrzymującym aktywność) i dwukrotnie odpowiedział przekierowaniem 307 z adresu http://na https://.
Ale… Czekaj… W rzeczywistości właśnie wysłałem jedno żądanie POST z treścią! Rozmiar ciała został określony przez Content-Lengthnagłówek.
Otrzymałem jednak dwie odpowiedzi. Oznacza to, iż serwer szczęśliwie zignorował nagłówek Content-Lengthi zinterpretował moje żądanie jako dwa oddzielne żądania.
Wygląda to na idealnego kandydata do ataku Client-Side Desync opisanego we wspomnianych badaniach.
Cytuję @Albinowax:
Klasyczne ataki polegające na desynchronizacji lub przemycie żądań polegają na celowo zniekształconych żądaniach, których zwykłe przeglądarki po prostu nie wysyłają. Ogranicza to te ataki do stron internetowych, które wykorzystują architekturę front-end/back-end. Jednak, jak dowiedzieliśmy się z analizy ataków CL.0, możliwe jest spowodowanie desynchronizacji przy użyciu w pełni zgodnych z przeglądarką żądań HTTP/1.1. Nie tylko otwiera to nowe możliwości przemytu żądań po stronie serwera, ale także umożliwia zupełnie nową klasę zagrożeń – ataki desynchronizujące po stronie klienta.
Desynchronizacja po stronie klienta (CSD) to atak, który powoduje, iż przeglądarka internetowa ofiary desynchronizuje własne połączenie z podatną na ataki witryną internetową. Można to porównać do zwykłych ataków przemycania żądań, które desynchronizują połączenie między serwerem front-end i back-end.
Po przeprowadzeniu bardziej dogłębnej analizy odkryłem, iż ten problem nie jest specyficzny dla rozwiązania klienta, ale raczej ogólny błąd w usłudze używanej przez klienta o nazwie Azure Front Door .
Drzwi wejściowe
Usługa Azure Front Door to globalna, skalowalna sieć dostarczania treści (CDN) i inteligentna platforma dostarczania aplikacji, która zapewnia bezpieczne i wydajne kierowanie ruchu internetowego do usług zaplecza.
Przyjrzyjmy się niektórym konfigurowalnym opcjom.
Jedną z jego funkcji (domyślnie włączoną) jest przekierowanie całego ruchu HTTP na HTTPS.
Technicznie odbywa się to poprzez przekierowanie przeglądarki na https://adres dzięki kodu stanu 307:
Serwer obsługuje połączenia utrzymujące aktywność:
I przekierowuje również żądania POST:
Ale problem polega na tym, iż całkowicie ignoruje Content-Lengthnagłówek:to, co wygląda na dwa żądania, jest w rzeczywistości jednym żądaniem wysłanym przez przeglądarkę internetową, w którym żółte pole zawiera dane dla żądania POST ( Content-Lengthnagłówek wskazuje na koniec danych).
Ale serwer Front Door ignoruje Content-Lengthnagłówek i traktuje go jako dwa oddzielne żądania.
Inną interesującą cechą Front Door (oczywiście nie jest to błąd) jest to, iż wszystkie serwery klientów obsługiwane przez usługę Front Door są dostępne pod jednym adresem IP i są również dostępne w jednym utrzymywanym połączeniu (jest to usługa CDN, prawda?) . Jest to więc całkowicie poprawny zestaw żądań wysyłanych w jednym połączeniu TCP:
UWAGA 1: azure-victim.jeti.pw i azure-attacker.jeti.pw to dwa oddzielne serwery WWW dwóch oddzielnych klientów (użyłem niestandardowych domen dla lepszej widoczności).
UWAGA 2: serwer azure-attacker.jeti.pw nie ma włączonych automatycznych przekierowań HTTPS, dlatego nie odpowiada przekierowaniem (może to mieć znaczenie dla różnych technik eksploatacyjnych).
Wykorzystaj
Atak CSD rozpoczyna się od odwiedzenia przez ofiarę strony internetowej atakującego, po czym jej przeglądarka wysyła dwa żądania między domenami do podatnej witryny. Pierwsze żądanie jest tworzone w celu desynchronizacji połączenia przeglądarki i wywołania szkodliwego żądania/odpowiedzi przez drugie żądanie.
Istnieje wiele sposobów, w jaki osoba atakująca może wykorzystać ten problem z desynchronizacją. Skupię się na dwóch możliwych sposobach.
Kradzież żądań
Wyobraźmy sobie, iż po wizycie ofiary witryna atakującego wysyła żądanie (np. dzięki Java Script fetch API):
Usługa Front Door traktuje to jako dwa osobne żądania, z których drugie jest żądaniem POST z dołączoną treścią (długość 200 bajtów).
UWAGA: pamiętaj, iż azure-attacker.jeti.pw jest skonfigurowany tak, aby nie przekierowywał automatycznie, więc serwer sprawdza Content-Lengthw tym przypadku.
Ponieważ brakuje treści żądania, serwer będzie czekał na 200 bajtów danych, aby zakończyć żądanie. Wszystko, co musi zrobić atakujący, to przekierować użytkownika ofiary na stronę ofiary:
Przeglądarka ofiary wyśle kolejne żądanie GET (w większości przypadków przeglądarka ponownie użyje tego samego połączenia). Oba żądania będą wyglądać następująco:Serwer otrzymał 200 bajtów danych i wysłał żądanie POST do http://azure-attacker.jeti.pw/logger z następującymi danymi :
I skutecznie atakujący ukradł plik cookie sesji ofiary.
„Uniwersalny” XSS poprzez fałszowanie odpowiedzi
Another way of expoiting a CSD vulnerability is to forge responses to the victim’s requests.
Let’s have a look at following request sent by the browser when victim visits malicious website (sent via fetch API):
Front Door service again treats it as two separate requests and sends both to respective customer websites. And receives 2 separate responses.
But the victim’s browser sent only one request so it expects only one response (307 redirect in our case). Second part stays in the connection pool waiting for another request to match (because of the HTTP pipelining).
When attacker redirects a victim, browser makes another request.
Ale na szczęście dla atakującego przeglądarka ma już odpowiedź oczekującą w puli połączeń (w naszym przykładzie odpowiedź zawiera ładunek XSS, który zostanie uruchomiony w kontekście strony internetowej, na którą została przekierowana ofiara).
Ponieważ atakujący może przekierować ofiarę na dowolną witrynę obsługiwaną przez Front Door i sfałszować odpowiedź, myślę, iż można to nazwać „uniwersalnym” XSS :)