Niewłaściwy encoding #1

Pierwsze wyjaśnienie odnośnie ćwiczeń z nieprawidłowego encodingu. Na pierwszy ogień pójdzie pierwsze miejsce, w którym wprowadzone dane są wypisywane. Jako string testowy wykorzystam następujący zestaw znaków:

!“#$%25&'()*+,–./:;<=>?@[]^_`{|}~

Na wyjściu natomiast dostaje się coś takiego:

demo 1

Jak widać, specjalnie traktowane są tylko nieliczne znaki, które są przekształcane w następujący sposób:

& –> & < –> < > –> >

Byłoby to zabezpieczenie wystarczające, gdyby dane te były wypisywane w kontekście HTML. Problem w tym, że nie są. Są wypisywane w kontekście atrybutu HTML, który, tak się dodatkowo składa, zawiera kod JavaScript.

Jak w takim przypadku uczynić ZŁO? Sposobów jest wiele. Pokażę dwa proste przykłady. Jak ktoś chce magii, proszę bardzo: http://blog.kotowicz.net/.

Pierwszy przykład jest trywialny, payload, który go demonstruje, wygląda następująco:

'+alert(/xss/)+'

W kodzie strony przypadek wygląda następująco:

demo 1

W chwili, gdy ofiara kliknie na tak przygotowany link, w pierwszej kolejności wyświetli się alert. Zamiast tej funkcji można umieścić choćby payload oparty na funkcji eval z dodatkowym unescape. Na przykład mogłoby wyglądać to tak:

'+eval(unescape('%2561%256c%2565%2572%2574%2528%252f%2578%2573%2573%252f%2529'))+'

Ten powyższy payload dedykuję Wysokiej Klasy Specjalistom, którzy “rozwiązali” problem z XSS poprzez zablokowanie słowa alert. W mojej bezgranicznej złośliwości zrobiłem dokładnie takiego samego PoC co w oryginalnym raporcie, właśnie z użyciem tego typu “wyrafinowanych sztuczek”. Swoją drogą czekam, kiedy zacznie być blokowany mój ulubiony znacznik, mroczne pmq.

Co jest główną wadą wyżej zademonstrowanego sposobu? Z punktu widzenia atakującego oczywiście? Tak, chodzi o to, że ofiara musi kliknąć w ten element. Można jednak nieco zwiększyć swoje szanse na sukces. Tak (i to jest ten drugi sposób):

“ onmouseover=“alert(/xss/)” style=“z-index: 100; position: absolute; top: 0; left: 0; width: 100%25; height: 100%25” foo=”

W rezultacie da to następujący kod:

demo 1<

Te powyższe dwa przykłady to nie są bynajmniej wszystkie sposoby, na jakie można w tym konkretnym miejscu zrobić kuku. Wystarczająco dobitnie pokazują jednak to, że encoding prawidłowy (lepsze określenie: wystarczający) w kontekście “czystego” HTML nie musi być wystarczający w innym kontekście. Tu – w kontekście atrybutu HTML (drugi przypadek) lub funkcji JavaScript (pierwszy przypadek).

Oryginał tego wpisu dostępny jest pod adresem Niewłaściwy encoding #1

Autor: Paweł Goleń