Krótki i gawędziarski wpis odnośnie tego, jak szukać prostych przypadków XSS. Przynajmniej teoretycznie prostych. Jeśli mamy do czynienia z dużą aplikacją, w ramach której można zidentyfikować kilkadziesiąt punktów wejścia (w uproszczeniu - formatek), z których każdy przyjmuje kilka(naście) parametrów, dokładne przeanalizowanie każdego z nich może być niemożliwe przez ograniczenia czasowe. Z drugiej strony dobrze jest zidentyfikować te miejsca, w których dane pochodzące od użytkownika są wypisywane na stronie i w dodatku są wypisywane w kontekście, który na XSS pozwala.
Jak szukać (potencjalnych) XSS
W opisanym scenariuszu wiele razy stosuję prostą technikę. Zebrane w trakcie testów aplikacji adresy (z parametrami) wywołuję na końcu jeszcze raz, tym razem do każdego parametru przekazując kolejno pewien marker. Marker ten powinien spełniać dwa warunki:
- powinien być łatwy do znalezienia,
- powinien przejść przez (większość) walidatorów,
Jeśli chodzi o łatwość znalezienia, to dość dobrze sprawdza się w tym przypadku jakaś krótka kombinacja znaków, które raczej nie występują "naturalnie", na przykład pmq.
Istotny jest drugi warunek. Oczywiście jeśli dla każdego parametru istnieją dobrze określone reguły walidacji, to prawdopodobnie nie uda się znaleźć takiego markera, który przejdzie przez nie wszystkie. W wielu przypadkach jednak wystarczy jeśli:
- marker jest krótki,
- nie zawiera znaków specjalnych,
Ten drugi warunek może wydawać się dziwny, bo przecież chyba chodzi o znalezienie tych miejsc, gdzie można zrobić XSS, a przecież do tego znaki specjalne są potrzebne, prawda? Nie, a przynajmniej nie do końca. Powtórzę jeszcze raz - chodzi o zidentyfikowanie jak największej ilości miejsc, w których dane przekazywane przez użytkownika są wypisywane na stronie. Co więcej mówię tutaj o scenariuszu, w którym o testowanej aplikacji wiem już całkiem sporo. Na przykład to, że na wejściu jest filtr, który znaki < > ' oraz " bezlitośnie i konsekwentnie tępi. Ale też to, że czasami dane wypisywane są w takim kontekście, że do XSS tych znaków nie potrzebuję. I właśnie te miejsca chcę znaleźć. Co prawda zwykle po to, by stwierdzić, że ewentualne XSSy są praktycznie nie do wykorzystania (albo inaczej, Likelihood of Exploit jest Low lub None, patrz Common Weakness Scoring System).
Zdecydowana większość aplikacji, które testuję, to aplikacje w J2EE. W tym przypadku java.lang.NumberFormatException dość skutecznie wybija mi z głowy wykorzystanie do niecnych celów parametrów numerycznych (i analogicznie w innych językach, np. ASP.NET i C#). Nie w każdym przypadku tak jest, o czym kiedyś rozmawialiśmy z Krzyśkiem Kotowiczem. I tu właśnie pora na ciekawostkę właściwą. Jako dobry przykład złego przykładu posłużę się zadaniem dostępnym w ramach SpotTheVuln.com, a konkretnie tym przykładem: Invincible.
Na uwagę zasługują parametry w oraz h ($_SERVER['PHP_SELF'] nie jest taki ciekawy). Szczególnie ciekawa jest linia 28. Co się stanie gdy w parametr w trafi mój marker? Ciekawy fragment kodu się nie wykona, bo wynikiem rzutowania na (int) będzie 0. A co będzie wynikiem rzutowania wartości 1pmq? Domysły można sprawdzić tutaj: http://bootcamp.threats.pl/v/iframer.php.
W ramach ciekawostki, we wpisie Invincible – Cross Site Scripting omówiony jest tylko ten bardziej oczywisty (nagłośniony - o tym, że PHP_SELF jest ZŁE często się mówi) błąd. Na parametry, o których piszę, zwrócona została uwaga dopiero w komentarzach. Wbrew temu, co jest w komentarzu, poprawki jeszcze nie było, dopiero po zwróceniu uwagi na błąd, pojawiła się kolejna wersja pluginu zawierająca stosowną poprawkę.
Jakie są wnioski z tego przykładu? Każdy może wyciągnąć własne we własnym zakresie. Ja tym razem chciałem "sprzedać" taką myśl: narzędzia automatyczne nie są złe, jeśli ich autor/operator wie co robią, jak to robią, po co to robią i jaki skutek mają osiągnąć. A i dostosowanie narzędzia i jego działania do testowanej platformy/aplikacji ma kluczowe znaczenie.
I jeszcze w kontekście prezentacji Pawła Krawczyka z marcowego spotkania OWASP - proponuję w ramach eksperymentu sprawdzić, jak wspominana przez Pawła YASCA poradzi sobie ze znajdowaniem tych błędów. Jeszcze raz powtórzę: narzędzia są bardzo pomocne, jeśli zna się ich ograniczenia.
1234'1234
1234"1234
1234[<]1234
+ zgłaszanie wszystkich takich ciągów zwróconych bez escape'owania lub wewnątrz JS/CSS. Sprawdzało się to zwykle znacznie lepiej niż "fabryczne" testy.