O co chodzi w tym XSS
Mam wrażenie, że czasami jest pewien problem ze zrozumieniem tego, czym jest ten XSS i co daje on atakującemu. Podejrzewam, że dla większości osób w jakiś sposób zorientowanych w temacie bezpieczeństwa stwierdzenie możliwość wykonania koduw kontekście atakowanej aplikacji mówi wszystko. Z drugiej strony są osoby, dla których to zdanie brzmi mniej więcej tak: bla bla bla, bla bla bla, bla bla. Postaram się w prosty sposób to zagadnienie wyjaśnić.
Zamierzchła przeszłość
Dawno, dawno temu nie było czegoś, co nazywa się same-origin policy. W rezultacie dwie różne pochodzące z różnych domen mogły swobodnie komunikować się ze sobą. Cofnięcie się w czasie tak daleko jest dość ciężkim zadaniem, ale jeśli chodzi o historię XSS, to można zacząć od tego artykułu: History of Cross Site Scripting. A konkretnie można skupić się na tym fragmencie:
Netscape introduced JavaScript in 1995. Soon after, hackers realize that when someone surfs their website they can force load any website (webmail, banks, auction sites) in a frame and use JavaScript to cross boundaries between the two sites – hence the name “cross site scripting.”
Wyglądać to mogło mniej więcej tak:
W tym momencie atakujący mógł na przykład odczytać lub zmodyfikować fragment osadzonej w ramce strony. Mógł również wywołać na niej dowolną akcję, na przykład tak: kliknij mnie (i zobacz, co zmieniło się w ramce). Oczywiście działało to również w drugą stronę, a więc strona osadzona w ramce miała dostęp do strony, która ją osadzała.
Co powinno się stać (powinno – bo nie sprawdzałem w każdej przeglądarce, czy rzeczywiście tak się stało, nie będzie to również raczej działać w przypadku, gdy ktoś czyta ten post przez jakiś czytnik RSS):
- skrypt ze strony osadzającej wpisał tekst na stronie osadzanej (okienko wyszukiwania),
- skrypt ze strony osadzającej wysłał formularz na stronie osadzanej (formularz wyszukiwania),
- skrypt ze strony osadzającej odczytał wyniki wyszukiwania (tytuły),
Podsumowując – zanim został wprowadzony dodatkowy mechanizm bezpieczeństwa, jedna strona mogła osadzić inną stronę w ramce i ją “skryptować”. A ponieważ te strony pochodziły z różnych domen (“sajtów”), mieliśmy piękny przykład cross-site scripting.
Same-Origin Policy
Oczywiście nic co piękne nie trwa wiecznie (dyskusję na temat tego co i dla kogo jest piękne odłożę na bok). Możliwość, by dwie kompletnie niezwiązane ze sobą strony mogły wzajemnie(!) sobą sterować była oczywiście niepożądana, stąd idea same-origin policy. Właśnie przez ten mechanizm zabezpieczenia powyższa demonstracja odbywała się na mojej własnej stronie, a nie jakimś zewnętrznym serwisie.
W przeglądarkach, z których korzystamy obecnie, dwie strony mogą “skryptować się” wzajemnie w taki sposób, jak demonstrowałem wyżej, jeśli pochodzą z tego samego źródła. A źródło jest określane na podstawie:
- protokołu (http:// i https:// to nie to samo źródło)
- nazwy domeny,
- portu (nie we wszystkich przeglądarkach),
Dokładniej na temat różnych wersji same-origin policy można poczytać sobie tutaj: Browser Security Handbook, part 2: Same-origin policy.
Tu warto dodać, że stworzone zostały mechanizmy, które pozwalają stronom komunikować się mimo tego, że pochodzą z różnych źródeł. Ale to już trochę inna bajka.
UWAGA: To jest TEN SAM origin
Wydaje mi się, że czasami może pojawiać się pewne niezrozumienie jak traktowane są skrypty osadzane w ten sposób:
Są one traktowane jak część strony, która osadza taki skrypt, a więc znajdują się w tym samym “źródle”. Dlatego też:
- jeśli osadzasz jakiś “gadżet” w ten sposób – dajesz komuś dostęp do DOM swojego dokumentu,
- jeśli pobierasz na swoją stronę zabezpieczoną HTTPS (SSL) zewnętrzny element (skrypt) po HTTP – dajesz komuś dostęp do DOM swojego dokumentu (patrz: Transport Layer Protection Cheat Sheet: Rule – Do Not Mix TLS and Non-TLS Content),
To o co TERAZ chodzi w tym Cross-Site Scripting
Teraz cross-site scripting jest trochę mniej cross-site. Ogólnie chodzi o to, by móc wstrzyknąć kod JavaScript do atakowanej przez nas strony, dzięki czemu nasz skrypt będzie miał pełen dostęp do DOM dokumentu. A w rezultacie znów będzie mógł zrobić wszystko. No, prawie wszystko (patrz między innymi: LockingtheThroneRoom, ale też httpOnly).
Obecnie celem atakującego staje się więc wstrzykniecie swojego kodu na stronę, którą chce zaatakować. Może to zrobić na wiele sposobów, w zależności choćby od tego, z jakim typem XSS mamy do czynienia (reflected, stored, DOM-based). Może również próbować atakować zasoby umieszczane na atakowanej stronie (wspominane już “gadżety”), jak również sposób w jaki te gadżety są przez przeglądarkę pobierane (ponownie – wspominany już brak HTTPS).
Jak wygląda typowy sposób wykorzystania podatności XSS? Chodzi mi tu o sposób ataku, a nie to, co jest jego celem. Innymi słowy chodzi mi o to, w jaki sposób payload jest przekazywany, a nie o to, co payload robi. Sposobów jest oczywiście wiele, ale ograniczmy się do dwóch typowych przypadków dla wersji reflected oraz stored. Właściwie już kiedyś (więcej) o tym pisałem (patrz: Scenariusze wykorzystania Cross-Site Scripting), ale przypomnę to w kilku zdaniach.
W przypadku reflected xss payload pochodzi bezpośrednio z żądania użytkownika. Na przykład może być zawarty w jednym z parametrów żądania. Dane pochodzące od użytkownika nie są odpowiednio walidowane i jednocześnie brak jest odpowiedniego encodingu/oczyszczania danych. W rezultacie dane pochodzące od użytkownika są interpretowane jako kod HTML/JavaScript i w ten prosty sposób atakujący uzyskał możliwość wykonania swojego kodu. Najbardziej typowym sposobem ataku jest przygotowanie odpowiedniego linka i skłonienie ofiary do tego, by go kliknęła (tu przydatna może być socjotechnika).
Ataki typu reflected XSS są coraz trudniejsze do przeprowadzenia, ponieważ przeglądarki implementują filtry “anti-xss”, których celem jest zablokowanie wykonania skryptu, jeśli pochodzi on z żądania klienta. Oczywiście nie jest to rozwiązanie w 100%25 skuteczne, jednak mechanizm ten znacznie utrudnia praktyczne wykorzystanie podatności.
Bardziej interesujący, przynajmniej z mojego punktu widzenia, jest przypadek ze stored xss. Tutaj payload przekazywany w żądaniu do serwera jest zapisywany po stronie aplikacji (np. w bazie). Dane zapisane w bazie są wykorzystywane do konstruowania strony i w rezultacie payload trafia do ofiary. Typowym przykładem może być osadzenie payloadu XSS w komentarzu pod artykułem, danych opisowych aukcji czy w opisie profilu konkretnego użytkownika. Od tej pory każdy odwiedzający daną stronę zostanie “zaatakowany” przy pomocy osadzonego payloadu. Stored XSS jest szczególnie wdzięczną podatnością, jeśli uda ją się połączyć z błędami kontroli dostępu lub osadzenie payloadu jest możliwe w danych dostępnych “publicznie”, oglądanych przez dużą liczbę użytkowników. Jak może wyglądać przypadek połączenia podatności XSS z błędem kontroli dostępu? Powiem tak – jeśli na przykład w bankowości internetowej jest możliwość osadzenia payloadu XSS w opisie rachunku, to problem jest niewielki (w zasadzie – self xss). Jeśli jednak w wyniku dodatkowego błędu kontroli dostępu jest możliwość osadzenia tego payloadu w danych opisowych konta innego użytkownika, wówczas otwierają się całkiem ciekawe możliwości ataku (targetowanego pod konkretną ofiarę).
Jeśli wstrzyknięcie kodu uda się atakującemu, wracamy do punktu wyjścia (patrz demonstracja). Będzie on między innymi w stanie automatyzować działanie zaatakowanej aplikacji, jak również odczytywać i/lub modyfikować dane wpisane przez użytkownika, wyświetlane użytkownikowi (...). I między innymi dlatego, by atakujący jednak nie mógł tego zrobić, pojawiło się Content Security Policy. Pozostaje tylko czekać, aż wszystkie przeglądarki zaczną obsługiwać ten mechanizm, a strony – z niego korzystać. A wtedy być może termin cross-site scripting znowu nabierze innego znaczenia. Na przykład takiego: Postcards from the post-XSS world.
P.S. Po głębszym namyśle mam wrażenie, że dla przeciętnego użytkownika ten wpis również można zastąpić frazą bla bla bla występującą wielokrotnie...
Oryginał tego wpisu dostępny jest pod adresem O co chodzi w tym XSS
Autor: Paweł Goleń