Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Kolejny XSS w www.google.com (Custom Search Engine)
Błąd został znaleziony w Custom Search Engine (CSE). Jest to usługa uruchomiana przez Google w 2006 roku, pozwalająca na spersonalizowanie strony wyszukiwarki i ograniczenie zakresu wyszukiwania na przykład tylko do własnej domeny.
Internet Explorer i manipulacja nagłówkiem Host
Internet Explorer ma bardzo specyficzne zachowanie związane z interpretacja nagłówka Location w przekierowaniach. Prowadzi to do niespotykanej w innych przeglądarkach możliwości manipulacji nagłówkiem Host.
Przypomnijmy sobie, jak standardowo wygląda odpowiedź serwera z przekierowaniem.
HTTP/1.1 302 Found Date: Fri, 06 Mar 2015 08:30:23 GMT Server: Apache/2.2.22 (Debian) X-Powered-By: PHP/5.4.36-0+deb7u3 Location: http://example.com/login.php Vary: Accept-Encoding Content-Length: 0 Connection: close Content-Type: text/html
Najistotniejsza jest linia 5 – z nagłówkiem Location, bowiem znajduje się w niej informacja dla przeglądarki pod jaki zasób ma wysłać kolejne żądanie.
Analiza zachowania IE wskazuje na to, że ta przeglądarka buduje kolejne żądanie umieszczając w nagłówku Host wszystko to, co znajduje się pomiędzy http:// a kolejnym znakiem slasha (/) lub końcem linii. W powyższym przypadku byłoby to example.com. Wygląda to jak zupełnie prawidłowe zachowanie. Proponuję jednak małą zagadkę: co zrobi Internet Explorer, gdy otrzyma poniższą odpowiedź?
HTTP/1.1 302 Found Date: Fri, 06 Mar 2015 08:35:32 GMT Server: Apache/2.2.22 (Debian) X-Powered-By: PHP/5.4.36-0+deb7u3 Location: http://example.com%2flogin.php Vary: Accept-Encoding Content-Length: 0 Connection: close Content-Type: text/html
Znak / został zamieniony na jego reprezentację w URL-encodingu %2f. W zasadzie przeglądarka nie powinna wykonać żadnego żądania w odpowiedzi na to przekierowanie, gdyż wartość nagłówka Location jest wyraźnie niepoprawna. Tak zachowują się inne popularne przeglądarki (Chrome, Firefox). Internet Explorer z kolei wysyła kolejne żądanie – w dodatku o całkiem ciekawej treści.
GET /login.phphp/ HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Accept-Language: pl-PL User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko Accept-Encoding: gzip, deflate Host: example.com/login.php DNT: 1 Connection: Keep-Alive Cache-Control: no-cache
Wow! Okazało się, że IE w nagłówku Host umieścił URL-zdekodowaną formę ciągu znaków pobranego wcześniej z nagłówka Location! Ponadto „dziwnie” wypełnił pierwszą linię żądania – bo skąd wzięło się tam login.phphp skoro nigdzie nie było takiego stringa w żądaniu? Z opisu umieszczonego niegdyś na stronie odkrywcy błędu wynika, że IE nakłada na siebie dwie postaci ścieżki zapytania: postaci przed wykonaniem URL-decode i po jego wykonaniu (Rys 1.).
Oczywiście błąd pozwalający na wrzucanie dowolnych ciągów znaków do nagłówka Host możemy wykorzystać do wykonania XSS-a jeżeli jest on na stronie gdzieś przepisywany bez enkodowania.
Podsumowując: jeśli wyślemy odpowiedź http z nagłówkiem Location: http://example.com%2F<script>alert(1)<%2fscript> i wartość tego nagłówka zostanie gdzieś przepisana w odpowiedzi – mamy XSS-a.
W praktyce jednak możemy spodziewać się, że serwery będą odpowiadały kodem 400 Bad Request, ze względu na fakt, iż taki nagłówek Host jest wyraźnie niepoprawny (Rys 2.).
Manipulacja nagłówkiem Host w serwerach Google
Serwery Google, podobnie jak pokazałem na Rys 2. nie lubiły, gdy wysyłało im się znaki niealfanumeryczne w nagłówku Host. Zacząłem szukać możliwości na obejście tego problemu. Rozwiązaniem okazały się numery portów. Jak wiadomo, po nazwie hosta można dodać dwukropek wraz z numerem portu, np. mail.google.com:1024. Serwery Google nie walidowały wartości znajdujących się po dwukropku, mogłem więc dopisać tam cokolwiek chciałem. Od razu udało mi się znaleźć kilka miejsc, gdzie nagłówek Host był przepisywany na stronie. Niestety – z enkodowaniem ;)
Potrzebowałem więc odnaleźć miejsce, w którym owo enkodowanie nie będzie wykonywane. Zanim jednak do niego przejdę, opiszę jeszcze jedno zachowanie serwera Google’a, które było mi potrzebne do wykorzystania podatności.
Serwery Google i średnik w ścieżce
Serwery Google domyślnie normalizują ścieżkę wysyłaną w zapytaniach. Na przykład, żądanie GET /test/../test2 HTTP/1.1 nie zostanie obsłużone przez serwer aplikacyjny, tylko wpierw nastąpi przekierowanie do ścieżki znormalizowanej, a więc /test2 (Rys 4.).
Okazuje się jednak, że to zachowanie można „wyłączyć” dodając znak ; w ścieżce. Serwer najwyraźniej kończy interpretacje ścieżki na średniku (traktując średnik jako separator tzw. path parameters) i za nim można umieścić już dowolny ciąg znaków. Przykładowo, dla żądania GET /test/;/../test2 HTTP/1.1 serwer nie odpowie już przekierowaniem, ale błędem 404 – co dowodzi, że próbował po prostu wykonać zapytanie dla tej ścieżki bez normalizacji (Rys 5.).
XSS w Google CSE
Przejdźmy wreszcie do właściwego XSS-a w Google Custom Search Engine. Było to jedyne miejsce, w którym udało mi się znaleźć przepisywanie nagłówka Host bez enkodowania (Rys 6.)
Przygotowałem więc stronę, która odpowiadała następującym przekierowaniem:
HTTP/1.1 302 Found Server: Apache/2.2.22 (Debian) Location: https://www.google.com%3a443%2fcse%2ftools%2fcreate_onthefly%3b%3c%2ftextarea%3e%3cscript%3ealert(1)%3c%2fscript%3e
Oczekując, że w kolejnym żądaniu zostanie wysłany nagłówek Host: www.google.com:443/cse/tools/create_onthefly;</textarea><script>alert(1)</script>. W istocie ten nagłówek został wysłany, ale IE był czujny… (Rys 7.)
Musiałem zatem zastosować sztuczkę, o której pisałem wspomniałem wcześniej w tekście. Sztuczka ta była też opisywana przez Black2Fana. Filtr XSS-owy z IE porównuje zawartość paska adresu z tym, co znajduje się na stronie. Jeżeli wykryje, że skrypt, który ma zostać wykonany, znajduje się w adresie – odrzuca je jako próba ataku XSS. Okazuje się jednak, że można to porównanie łatwo oszukać stosując wielokrotnie ciąg znaków ../ po średniku. Dzieje się tak dlatego, że IE sam normalizuje ścieżkę, którą wyświetla w pasku adresu. Oznacza to, że gdyby w pasku adresu miało się znaleźć http://example.com/;<script>alert(1)</script>/../../, to IE zostawi tam tylko http://example.com/ i filtr XSS-owy nie będzie już „widział”, że złośliwy skrypt został wysłany w adresie.
Ostatecznie utworzyłem stronę, która odpowiadała nagłówkiem:
Location: https://www.google.com%3a443%2fcse%2ftools%2fcreate_onthefly%3b%3c%2ftextarea%3e%3csvg%2fonload%3dalert%28document%2edomain%29%3e%3b%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f
(gdzie wartość dekoduje się do Location: https://www.google.com:443/cse/tools/create_onthefly;</textarea><svg/onload=alert(document.domain)>;/../../../../../../../../../../../../../../)
Zaś wynik wykonania tego skryptu możecie zobaczyć na filmiku poniżej:
Kalendarz
- 2015-01-27 (01:12) – zgłoszenie błędu do Google,
- 2015-01-27 (16:03) – potwierdzenie błędu przez członka Google Security Teamu,
- 2015-02-25 – potwierdzenie, że błąd został naprawiony,
- 2015-03-06 – publikacja na Sekuraku.
Podsumowanie
W artykule pokazałem XSS-a w domenie www.google.com, który wykorzystywał znany od kilku lat problem w Internet Explorerze pozwalający na manipulację nagłówkiem Host. Ponadto musiałem znaleźć sposób, by dało się go wykorzystać na serwerach Google (poprzez numer portu) oraz obejście filtra XSS-owego.
bug bounty ile wyniosło ? :)
Znając życie $5k ;)
Może warto byłoby zgłosić jeszcze do Microsoftu? Niech poprawią filtr XSS i to dziwne zachowanie.
Do Microsoftu zostało to już zgłoszone dwa lata temu; stwierdzili, że poprawią to „w kolejnej wersji”.
Poza tym MS najwyraźniej nie spieszy się z łataniem błędów tego typu, na co dowodem jest universal XSS[1] niepoprawiony od października zeszłego roku.
[1]: http://sekurak.pl/uzywasz-internet-explorera-mozesz-miec-xss-a-w-kazdej-domenie/
Gratuluję wspaniałej pracy autora:) Bardzo ciekawy artykuł i bardzo zrozumiały opis problemu. Oby więcej takich postów :)
Amazing find and I believe it worth more than $5K. I would be extremely thankful if you can translate this to English :) … Google translate isn’t bad but I there are a lot of stuff missing :S