27
Ciekawy XSS na Wykopie
Przeglądając ostatnio Wykop.pl (polski serwis społecznościowy) natrafiłem na ciekawy link (a właściwie na ciekawą zmienną GET doklejoną do URL). Z ciekawości chciałem zrozumieć do czego ona służy. Okazało się, że próby „zrozumienia” pozwoliły mi na wykonanie XSS’a.
Odkryty przeze mnie XSS był (moim zdaniem) dość nietypowy – właśnie dlatego postanowiłem opisać go trochę dokładniej. Oczywiście, wszystko w myśl zasady responsible disclosure – tak więc opisywana luka została już zgłoszona i załatana.
Próbując zalogować się na Wykop, możemy natrafić na następujący link:
http://www.wykop.pl/zaloguj/?fEr[0]=ZmQwZmh0dHA6Ly93d3cud3lrb3AucGwv |
To, co w nim nietypowego, to zmienna (typu Array): fEr.
Spróbujmy ją lekko zmodyfikować:
http://www.wykop.pl/zaloguj/?fEr[1337]=wykop_payload |
Zerknijmy do źródła strony i policzmy ile razy występuje w nim wykop_payload. Okazuje się, że znajdziemy go tam 3 razy. Nic nadzwyczajnego. Nic nadzwyczajnego nie dzieje się również gdy zmodyfikujemy indeks tablicy fEr:
?fEr[1] ?fEr[128] ?fEr[256] |
Spróbujmy jednak pozbyć się jej na chwilę:
http://www.wykop.pl/zaloguj/?wykop=wykop_payload |
Logicznie rzecz biorąc, podglądając źródło strony, znowu powinniśmy doliczyć się 3. wystąpień wykop_payload. Niespodzianka! Znajdziemy je tylko raz. A to oznacza, że fEr dodaje jakąś nową funkcjonalność [czyt. działa inaczej]. Znaleźliśmy więc dwa dodatkowe miejsca, w których wyświetla się wprowadzany przez użytkownika input. Zwykle, w takich momentach warto te miejsca sprawdzić.
Zmodyfikujmy powyższy link:
http://www.wykop.pl/zaloguj/?wykop=wykop_payload"<> |
okazuje się, że wszystko jest ładnie encodowane. Sytuacja miała się jednak inaczej w przypadku zmiennej fEr.
http://www.wykop.pl/zaloguj/?fEr[1]="><img src=x onerror=alert(0)> |
Javascriptowy alert, który przywitał nas po wprowadzeniu powyższego URL do paska adresu jednoznacznie wskazuje, że tym razem encodingu zabrakło właśnie w tych dwóch miejscach:
<form action="http://www.wykop.pl/zaloguj/?fEr[0]=MWU1YWh0dHA6Ly93d3cud3lrb3AucGwvemFsb2d1ai8%2FZkVyJTVCMCU1RD0lMjIlM0UlM0NpbWcrc3JjJTNEeCtvbmVycm9yJTNEYWxlcnQlMjgwJTI5JTNF&fEr[1]="><img src=x onerror=alert(0)>" method="post" class="default abs bgfff layer shadow pding5_10 dnone"> (...) Nie masz konta? <a href="http://www.wykop.pl/rejestracja/?fEr[0]=MWU1YWh0dHA6Ly93d3cud3lrb3AucGwvemFsb2d1ai8%2FZkVyJTVCMCU1RD0lMjIlM0UlM0NpbWcrc3JjJTNEeCtvbmVycm9yJTNEYWxlcnQlMjgwJTI5JTNF&fEr[1]="><img src=x onerror=alert(0)>">Zarejestruj się/a> |
Nie jest to oczywiście nic nadzwyczajnego. Zabawa zaczyna się dopiero wtedy, gdy dodamy encoding na wartości zmiennych, które wyświetlamy. Okazuje się, że czasem to za mało – musimy pamiętać również o samych zmiennych.
Powyższy błąd został załatany. To jednak jeszcze nie koniec. Chcąc potwierdzić, że łatka została zaaplikowana poprawnie, wpadłem na dość nietypowy pomysł. Wiemy, że XSS wykonuje się jedynie wtedy, gdy mamy do czynienia z tablicą fEr. Wartość tej tablicy jest już poprawnie wyświetlana w przeglądarce użytkownika. Jedyny wektor ataku, który pozostał to sama tablica fEr. A mówiąc precyzyjniej – indeksy tej tablicy.
Indeks tablicy nie musi być jedynie liczbą. W świecie informatyki istnieją przecież również tablice asocjacyjne. Oznacza to, że przed załataniem błędu, XSS wykonywałby się również dla poniższego przykładu:
http://www.wykop.pl/zaloguj/?fEr[wykop]="><img src=x onerror=alert(0)> |
Zastanówmy się, co stałoby się, gdyby to indeks tablicy fEr stał się payloadem.
htp://www.wykop.pl/zaloguj/?fEr[test"><script>alert(0)</script>]=wykop_xss<>" |
Chociaż wartość tablicy fEr była już encodowana, XSS nadal się wykonywał:
<form action="http://www.wykop.pl/zaloguj/?fEr[0]=NjNhOWh0dHA6Ly93d3cud3lrb3AucGwvemFsb2d1ai8%2FZkVyJTVCdGVzdCUyMiUzRSUzQ3NjcmlwdCUzRWFsZXJ0JTI4MCUyOSUzQyUyRnNjcmlwdCUzRSU1RD13eWtvcF94c3MlM0MlM0UlMjI%3D&fEr[test"><script>alert(0)</script>]=wykop_xss<>"" method="post" class="default abs bgfff layer shadow pding5_10 dnone"> (...) Nie masz konta? <a href="http://www.wykop.pl/rejestracja/?fEr[0]=NjNhOWh0dHA6Ly93d3cud3lrb3AucGwvemFsb2d1ai8%2FZkVyJTVCdGVzdCUyMiUzRSUzQ3NjcmlwdCUzRWFsZXJ0JTI4MCUyOSUzQyUyRnNjcmlwdCUzRSU1RD13eWtvcF94c3MlM0MlM0UlMjI%3D&fEr[test"><script>alert(0)</script>]=wykop_xss<>"">Zarejestruj się/a> |
Dlaczego? Ano dlatego, że zaaplikowano łatkę, która zajmuje się wartością tablicy fEr zapominając o samej tablicy. Błąd ten został naprawiony w tempie błyskawicznym – chwilę po zauważeniu.
Na koniec należą się wielkie słowa uznania dla serwisu Wykop.pl. Reakcja na zgłoszone incydenty była bardzo szybka i przebiegła w sposób wzorcowy. Od razu widać, że problem nie został zlekceważony, a programiści wiedzieli w jaki sposób go naprawić. Bardzo się cieszę, że również kawałek polskiego Internetu potrafił udowodnić, że można szybko i sprawnie załatać zgłoszony błąd.