Как-то мне стало интересно, сколько же стоят корпоративные блоги на Хабрахабре. Я зашел на эту страницу и перешел по ссылке заказать. Автоматом, вместо ожидаемых данных, ввел вектор для тестирования XSS и получил выполнение JS у себя в браузере. Но это не всё так интересно, как методы защиты на Хабре от последствий XSS.
Защита. HTTP Only
Выполнив XSS в двух полях на шаге 2 и в четырех на шаге 3 стало интересно, что можно с этим сделать. Наиболее стандартный вектор атаки при возможности провести XSS — это «слить» сессию авторизации и подставить себе. Обратившись к кукам я увидел, что для PHPSSESID используется флаг HTTP Only, что запрещает обратиться к данной куке через JS. Т.е. даже внедрив злобный JS код мы не можем «слить» сессию пользователя и подставить к себе (чтобы быть авторизованным под пользователем, классический вектор атаки). Есть методы обхода этой защиты, на некоторых версиях апача (а тут nginx, так что отпадает) и через использование плагинов в браузере, но все вектора ломает следующий пункт.
hint: Чтобы phpsessid имел флаг HTTP Only нужно выставить в php.ini следующее значение: session.cookie_httponly = true
Защита. Anti-CSRF protection
Так как мы имеем дело с XSS через POST, то в таких случаях используется эксплуатирование XSS через CSRF. Атакующий создает у себя на сайте идентичную форму, как и на уязвимом ресурсе, с уже заполненными данными (помещая в уязвимые поля вектор для XSS) и помещает ее в скрытый фрейм на своем же сайте. Когда атакуемый юзер откроет сайт с этим фреймом и формой — он автоматически отправит данные на Хабр и выполнит в своем браузере злобный JS. Но, есть отличие — поле HTTP Referer будет содержать домен сайта атакующего.
В статье На пути к созданию безопасного веб-ресурса. Часть 1 — серверное ПО я рассматривал следующее правило в nginx (которое можно реализовать прямо на уровне веб-приложения) как грязный хак:
# ANTI CSRF HACK
valid_referers blocked example.com www.example.com;
if ($invalid_referer) {
set $possible_csrf 1;
}
if ($request_method = POST) {
set $possible_csrf "${possible_csrf}2";
}
if ($possible_csrf = 12) {
return 403;
}
И вот он, яркий пример — Хабрахабр, использует это правило. Т.е. мы не можем отправить POST запрос на сервер с другого сайта — получим 403. В итоге, мы можем исполнить JS код только у себя в браузере.
hint: защита от CSRF спасает от последствий XSS через POST, что сводит уязвимость на нет.
Атака. Cookie injection
Но всё же, может еще есть лазейки? Продолжив изучать, как работает форма, наткнулся, что данные, заполненные в форме заявки, временно сохраняются в какой-то кэш на сервере (может, memcache). Этот кэш связан не с пользовательской сессией (PHPSESSID), а с другой — habrsession_id. Т.е. сгенерив уже форму с XSS вектором и подставив нашу куку habrsession_id другому юзеру мы, теоретически, можем провести атаку. Но мы не можем (в стандартных условиях) установить значение cookie на другом домене. Но есть способ — Cookie injection.
Заключается он в анализе JS кода приложения и вызовов установки значения document.cookie. Если найдется DOM XSS или такие условия, которые позволят внедрить своё значение Cookie (например, какая-то тестовая кука которая выставляет себе значение titile'а текущего окна (мы можем открыть окно через window.open со своим title, встречаются случаи в реальных системах), атакующий может записать свое значение habrsession_id атакуемому и выполнить JS. На данный момент все XSS исправлены. Если что-то найдете — сообщайте службе поддержки, очень оперативно отвечают.
hint: в статье В поисках лазеек: гид по DOM Based XSS описаны моменты, откуда ждать подвоха с DOM XSS.
P.S. И хинт не по теме топика: Пока писал топик, не сохранял его и случайно нажал ф5. В итоге, на одном из моментов, потерял весь текст статьи (когда уже её почти дописал, кнопка «восстановить» не помогла). Мгновенно сделал дамп процесса через обычный диспетчер задач, открыл его через HxD, нашел по ключевым словам своей текст статьи (русский текст был в json) и подставил сюда. Львиную долю статьи восстановил.