Pora na zakończenie tematu przykładu z niewłaściwym encodingiem (patrz: #1, #2, #3 i #4). Ponownie, by nie przeciągać, dla tradycyjnego zestawu znaków testowych otrzymujemy:
<script type="text/javascript">
doStuff('!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~');
</script>
<script type="text/javascript">
doStuff('!\"#$%&\'()*+,-.\/:;<=>?@[\\]^_`{|}~');
</script>
Czy można tu coś zepsuć?
Na pierwszy rzut oka, wydaje się, że wszystko jest w porządku. Dane przekazane przez użytkownika są wstawiane w kontekście tagu <script> jako część łańcucha znaków. Łańcuch ten ujęty jest w znak ', który to znak, jeśli wystąpi w danych przekazanych przez użytkownika, przekształcany jest do postaci \'. Czyli wszystko w porządku?
Nie, nie wszystko w porządku. W tym wypadku problem polega na tym, że parser HTML jest ważniejszy od parsera JavaScript. Najłatwiej pokazać to na przykładzie następującego payloadu:
</script><script>alert(/xss/)</script>
W kodzie strony wygląda to w sposób następujący (dla pierwszego przypadku):
<script type="text/javascript">
doStuff('</script><script>alert(/xss/)</script>');
</script>
Pozornie wszystko jest w porządku, dane przekazane przez użytkownika znajdują się wewnątrz łańcucha znaków w kontekście JavaScript. Tylko przeglądarka ma na ten temat nieco inne zdanie. Ona ten fragment kodu widzi w sposób następujący:
Parser HTML natrafiający na zamknięcie tagu script nie interesuje się specjalnie w jakim kontekście on wystąpił. Po prostu uznaje, że jest to koniec tagu. W oparciu o tę prostą sztuczkę można "uciec" z łańcucha znaków, w którym jesteśmy zamknięci przez zamianę znaku ' na \' i po prostu otworzyć nowy tag script, w którym można umieścić własny kod.
Tu warto zwrócić uwagę na drugi przypadek, który przeglądarka zrozumie następująco:
W tym wypadku przeglądarka nie natrafia na kończący tag script, więc opisany wyżej przypadek nie działa. No chyba, że ktoś znajdzie sposób na to, by przeglądarkę jednak oszukać. Jakieś pomysły?
Po użyciu:
alert(/xss/)
Dostaję:
Unterminated string constant
A na stronie poniżej "demo 4" pojawia się:
');
Myślę, że można łatwo to naprawić dodając jeszcze otwierający tag na końcu przykładu:
alert(/xss/)
Chyba, że coś przeoczyłem...