Третий апдейт по стажировке Positive Technologies

Время очередного апдейта по стажировке. Третий блок был посвящён атакам на стороне клиента. Лекция содержала в себе брифинг по XSS, CSRF и прочим Session Fixation, которыми обычно атакуют клиентов веб-приложений.

Домашнее задание состояло из двух частей: прохождения не слишком сложного квеста от Google на тему XSS, насчитывавшего шесть этапов, а также частичного прохождения квеста на эксплуатацию уязвимости PRSSI.

PRSSI или Path-Relative Style Sheet Import возникает, когда ссылка на CSS-файл относительна, например:

href=’/challenges/token/chamber.php/../styles.css’

Едва ли мне удастся описать причину возникновения уязвимости лучше, чем это сделал Raz0r или James Kettle из PortSwigger.

Вкратце, если в URL добавить нечто лишнее, например:

из http://example.com/folder/page.php?parameter=value 

сделать http://example.com/folder/page.php/foo/bar?parameter=value

то у сервера и у браузера возникнут разногласия в том, каким будет относительный путь при данном URL, в результате чего html-страница может быть загружена как таблица стилей формата CSS. Конечно, у любого современного браузера в этом случае возникает повреждение чувства прекрасного и ощущение, что что-то идёт не так. Однако есть способ заставить их не обращать на это внимание и это режим совместимости. Заставив браузер работать в этом режиме, у нас появляется возможность загрузить-таки html-страницу, содержащую CSS-стили и они будут применены! Теперь посмотрим, как это можно использовать.

Квест на PRSSI ставит следующее условие: имеется страница, генерирующая при обращении 4 токена:

Для получения зачёта в данном блоке необходимо было стянуть со страницы первые два токена: token0, являющийся параметром в URL и token1, который тоже выглядит как параметр, однако находится за якорем (#) и на сервер не отправляется. Логика получения token0 проста и я не стал изобретать велосипед, а просто позаимствовал решение из статьи на PortSwigger. Создаём html-страницу, явно указывающую браузеру, что мы намерены работать в режиме совместимости, создаём iframe, внутри которого обращаемся на страницу квеста и внедряем CSS-правило, якобы импортирующее файл с нашего сервера, после чего нормализуем строку:

4 цифры после каждого ‘%’ — из-за дабл-энкодинга, а 4 слэша — экранирование, необходимое CSS. Если ссылку на нашу html-страницу послать жертве, то при переходе по ней, внутри iframe сгенерируются token0 и token1 в URL, после чего внедрённое нами CSS-правило попытается импортировать файл с нашего сервера и отправит туда запрос, в котором будет содержаться token0 жертвы. Выглядит это примерно так:

cssi-token0

Легко представить на месте token0 какой-нибудь CSRF-токен или PHPSESSID, а от жертвы, тем временем, не требуется ничего, кроме как перейти по ссылке. Однако token1 куда интереснее.

Поскольку он находится за якорем, то не передаётся на наш сервер, а значит нужно приложить дополнительные усилия, чтобы его раздобыть. Решение этой проблемы в настоящее время существует только для браузеров на движке Gecko. При помощи правила @document, которое следует применять в виде @moz-document, можно применить CSS-стиль только для определённого URL. Для того, чтобы определять этот URL имеется целый арсенал: от «начинается с…» и до regexp. Поскольку действо происходит на стороне клиента, то якорь виден и по нему тоже можно задать условие. Сам token1 состоит из 8 символов [a-f0-9], а значит для определения первого символа можно применить следующий набор правил:

Обнаружив на первой позиции определённый символ, браузер клиента попытается выполнить соответствующее правило и загрузить с нашего сервера ресурс с названием, намеренно совпадающим с данным символом. Аналогичный набор правил нужен и для подбора остальных 7 символов. Поскольку с CSS я знаком не очень близко, я не смог обойти ограничение, когда из 8 сработавших правил применялся только последний стиль (читай, на сервер отправлялся только последний символ). Уверен, что это ограничение можно было бы обойти, но вместо этого я просто создал html-страницу, содержащую 8 ifram’ов, каждый из которых вытаскивает свой символ token1.

В результате, мы видим каждый символ токена жертвы в логах нашего сервера.

cssi-token1

Дальше захотелось разобраться и с token2 — нашёлся способ отобразить его и даже поставить условия, аналогичные тем, что описаны в статье Raz0r’a.

Из-за отсутствия regexp, нельзя пойти тем же путём, что и при получении token1. А перебирать вообще все возможные варианты — очень большое дело. Тут должно быть что-то ещё и я надеюсь, с этим я разберусь чуть позже. В целом, задание оказалось интереснейшим.

Четвёртый блок посвящён уязвимостям мобильных приложений.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *