23
XSS via URL
Czy kiedykolwiek zastanawiałeś się, w jaki sposób dane, wpisane do paska adresu przeglądarki są przez nią traktowane? Zrobimy dziś mały eksperyment, pokazujący pewne zagrożenie z serii ataków Cross-Site Scripting, które związane jest bezpośrednio z URI wprowadzanym przez użytkownika.
Stwórzmy prosty plik PHP, który odpowiada za wyświetlenie interesującego nas elementu: $_SERVER[‚REQUEST_URI’].
<?php echo $_SERVER['REQUEST_URI']; ?> |
Na pierwszy rzut oka powyższy przykład podatny jest na atak typu XSS. Brak jakiegokolwiek enkodowania/escape’owania + możliwość kontroli danych wprost od użytkownika (w końcu to końcowy użytkownik kontroluje to, co wpisuje jako adres URL do przeglądarki). Spróbujmy więc przeprowadzić jakiś prosty PoC:
poc.php?<script>alert(1)</script> |
Wszystko wskazuje na to, że nasza przeglądarka w większości przypadków (a tym dlaczego nie we wszystkich przypadkach – za chwilę) powinna wyświetlić uroczy alert(). Okazuje się jednak, że zamiast niego, wyświetla:
/poc.php?%3Cscript%3Ealert(1)%3C/script%3E |
Wprowadzony przez nas ciąg znaków poddany został procesowi URL-encode. Potrzebne do przeprowadzenia ataku znaki >< zostały zamienione na odpowiedniki %3E oraz %3C. Dlaczego tak się stało? Czy ma to coś wspólnego ze zmienną $_SERVER? Czas na zapowiedziany eksperyment.
Przygotujmy kilka przeglądarek. Np. Firefox, Chrome i Internet Explorer. Odpalmy narzędzie Wireshark i obserwujmy pakiety HTTP, które przechwycone zostały w momencie odwiedzania powyższego zasobu:
GET /poc.php?%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 |
GET /poc.php?%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1 Host: 127.0.0.1 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36 |
GET /poc.php?<script>alert(1)</script> HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Accept-Language: pl-PL User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko Accept-Encoding: gzip, deflate Host: 127.0.0.1 |
Okazuje się, że część przeglądarek dokonuje URL-enkodowania jeszcze przed wysłaniem danych do serwera. Innym zachowaniem cechuje się przeglądarka Internet Explorer. Oznacza to, że powyższy alert() wykona się właśnie w tej przeglądarce. Pozostałe (Firefox, Chrome) – jak zaobserwowaliśmy na przechwyconych przez narzędzie Wireshark pakietach – dokonają URL-enkodowania (co w tym przypadku pozwoli zapobiec atakowi XSS).
Poniższy skrypt pozwoli poeksperymentować Wam z różnymi przeglądarkami.
Nie tylko REQUEST_URI
Podobny problem występuje w przypadku nagłówka Referer.
Tym razem, dla zachowania różnorodności, nagłówek Referer otrzymamy w wyniku prostego skryptu JS.
/* index.html */ // (...) window.location = "xssPoC.html?aaa<>\"bbb"; // (...) /* xssPoC.html */ // (...) var linkElem = document.createElement('a'); linkElem.href = "xss.html"; document.body.appendChild(linkElem); linkElem.click(); // (...) /* xss.html */ // (...) alert(document.referrer); // (...) |
Uruchamiając powyższy kod w różnych przeglądarkach, zauważymy podobną jak w przypadku REQUEST_URI rzecz. Otóż nagłówek Referer, również został poddany URL-enkodowaniu w przypadku przeglądarek Firefox i Chrome, natomiast IE wyświetlił go bez zmian.
Zajmijmy się przypadkiem bezpośrednio z życia wziętym. Stosunkowo dawno temu (kwiecień), polski CERT opublikował narzędzie umożliwiające sprawdzenie, czy nasz klient (w tym przypadku przeglądarka) podatna jest na głośny w tamtych czasach atak Heartbleed – http://www.cert.pl/heartbleed/.
Po kliknięciu w button „Run test” aplikacja wyświetlała wynik testu oraz nagłówki zapytania wysłane do serwera. Jednym z tych nagłówków jest Referer i to on będzie dla nas najbardziej interesujący.
Odwiedzając adres http://www.cert.pl/heartbleed/?test=abc i klikając w przycisk „Run test„, wyświetlony zostanie nagłówek:
Referer: http://www.cert.pl/heartbleed/?test=abc |
Wygląda więc na to, że mamy możliwość kontroli nad danymi wyświetlanymi po stronie webaplikacji. Co stanie się, w przypadku wprowadzenia np. takiego adresu:
http://www.cert.pl/heartbleed/?x<h1 onmouseover=window.location='http://google.pl'>aaa |
Jak już zapewne wiemy, część przeglądarek dokona URL-enkodowania znaków >< – wtedy nie stanie się nic złego. Problem nastąpi jednak w momencie, gdy użytkownik korzysta z przeglądarki Internet Explorer. Scenariusz ataku może wyglądać następująco.
1. Atakujący nakłania użytkownika korzystającego z przeglądarki IE do odwiedzenia powyższego linku.
2. Użytkownik klika w link „Run test” i czeka na wyniki testu.
3. Po wyświetleniu rezultatu, użytkownik klika w button „Show/Hide advanced information„, pokazujący szczegółowe nagłówki wysłane do serwera.
4. Wśród pokazanych nagłówków znajduje się Referer, którego wartość zawiera tagi html/elementy javascript (<h1> oraz atrybut onmouseover). Z uwagi na brak enkodowania/escape’owania wyświetlanych danych, przeglądarka parsuje przekazane dane do postaci HTML. Użytkownikowi wyświetla się duży napis (z uwagi na <h1>). Kiedy wskaże na niego kursorem (onmouseover), nastąpi przekierowanie do innej domeny (window.location).
Poniżej przedstawiono dwa przykładowe payloady, prezentujące podatność:
Zgłoszony błąd (19.04) poprawiony został bardzo szybko (już 23.04 został załatany). Czas reakcji zasługuje na olbrzymią pochwałę.