>
Июнь 2018
Пн Вт Ср Чт Пт Сб Вс
« Апр    
 123
45678910
11121314151617
18192021222324
252627282930  

Использование XSS уязвимостей по максимуму.

Всем давно известно, что чаще всего c помощью XSS атакующий пытается отправить Cookie жертвы, прочитать CSRF токены, провести фишинговую атаку (создав фальшивую форму логина), совершить какое-нибудь действие от имени пользователя и некоторые другие близкие по цели атаки (возможно, это не все возможности, но это все наиболее популярные известные мне на данный момент).


В этой статье хочу поделиться еще одним способом получить выгоду от XSS, которым можно дополнить данный список. Надо отметить, что у этого способа есть один плюс – он не взаимозаменяет предыдущие, то есть его можно использовать после всех выше перечисленных, как дополнение.


Цель этого метода – мониторить страницы от имени пользователя, по которым он переходит на атакуемом сайте, а также мониторить его нажатия клавиш (можно еще движения и клики мышкой, но по мне так это будет лишней, не особо полезной инфой, в большинстве случаев точно).
Теперь по поводу максимальной пользы – я считаю, что алгоритм будет такой:

  • читаем и отправляем Cookie;
  • читаем и отправляем остальную инфу (IP-адрес, установленные плагины, версия и вид браузера, поддержка flash, поддержка silverlight и пр.) [опционально]
  • добываем сведение о внутренней сети, пробиваем роутер [опционально]
  • читаем и отправляем разные токены [опционально];
  • реализовываем фишинг [опционально];
  • делаем что-то “руками”” юзера [опционально];
  • продолжаем шпионить за ним и добывать инфу, пока он не закрыл вкладку или не ушел с сайта;

Все опциональные пункты списка имхо должны выполняться в зависимости от ситуации и конкретных приоритетах в целях, которых надо достичь при помощи XSS, они иногда могут мешать друг другу (если попытаться их скомбинировать, точнее выполнить один за другим) и увеличивают вероятности провала эксплуатации XSS. 
Но вот первый и последний пункты выполнять стоит всегда, при любом раскладе.Собственно основная часть статьи будет про последний пункт из этого списка.

Подходим к цели.

Начну издалека: через JavaScript есть возможность изменять путь в адресной строке без перезагрузки страницы. Например, если пользователь загрузил страницу по адресу


А на этой странице был скрипт:


То в адресной строке содержание станет следующим (без перезагрузки страницы):


Эта возможность, кстати, иногда бывает довольно полезной, когда от пользователей (или более внимательной категории юзеров – админов) надо скрыть быстро почистить URL после того, как он перешел по ссылке, где содержалась Reflected XSS, чтобы он потом, после загрузки страницы, посмотрев в адресную строку, ничего не обнаружил.

То есть, если мы подсунули ему ссылку с XSS типа:

То, перейдя по ссылке, после обнаружения странного поведения страницы, он начнет смотреть в адресную строку, где обнаружит наш вектор и все прочухает. Но дав ему ссылку:


мы лишим его этой возможности.

Но у этой техники есть еще более интересное и мощное применение. Мы будем имитировать юзеру его пребывание на сайте после перехода по ссылке, на самом деле он будет оставаться на одной странице все время, а в это время будет работать сторонний скрипт, добывающий и отсылающий инфу атакующему. Таким образом, XSS будет работать на протяжении всего времени, пока юзер переходит по ссылка на этом домене.

Обозначаем идею.

Общий принцип работы такой: когда юзер заходит на страницу с XSS, скрипт создает iframe с таким же адресом, как это страница и “прикрепляет” его на первый план, у пользователя создается впечатление, будто страница загрузилась нормально, ведь iframe можно увидеть только в коде страницы.

А вспомогательный скрипт контролирует логику бота-шпиона, то есть следит за тем, когда во фрейме поменяется адрес, чтобы поменять его в адресной строке, если же в новоизмененном адресе фрейма другой домен, то можно открыть его на новой влкадке, или же придется перезагружать страницу, чтобы не спалиться.
Таким образом, чтобы XSS перестала выполняться в данный момент, юзер должен или обновить страницу вручную (если XSS – Reflected и передавалась методом POST, в остальных случаях обновление не спасет, и кстати некоторые браузеры сейчас при обновлении старницы могут опять отправить POST запрос повторно) или закрыть вкладку или перейти на другой домен (хотя в этом случае еще можно избежать потери управления). 

Если он переходит в поддомент атакуемого домена, то тут выбор атакующего, то есть XSS будет работать, но есть небольшая вероятность, что юзер просечет несоответствие между адресом. Думаю, что тут по ситуации, например, если атаковался домен google.ru, юзер перешел в облачный файловый сервис гугла, который обычно лежит в поддомене drive.google.ru, то вероятность того, что он заметит подвох при взгляде в адресную строку довольно высока,если он часто пользовался этим сервисом. Иначе можно и рискнуть. Но надо учесть, что читать его данные из фрейма с поддоменом мы уже не сможем, так как Cross Origin Policy не позволит. Зато можем преспокойно полазить по основному домену от его имени в скрытом режиме (нижу будет об этом поподробнее).

Только у данного метода есть ограничения, а именно – он не будет работать, если в ответах веб-сервера сайта есть заголовок X-Frame-Options со значением DENY. Но лично я такие сайты встречал буквально пару раз, сейчас даже у половины SAMEORIGIN не выставлен, не говоря уже о полном ограничении через DENY.

Анализируем идею.

Сейчас многие наверняка вспомнили такую замечательную штуку, как BeEF, в котором есть тоже очень много интересных вещей. Так кстати тоже есть опция форсированного редиректа юзера во фрейме, вот только адрес в адресной строке не изменяется, что может быстро спалить конторку и эта опция немного для других целей служит.
В целом в BeEF’e есть почти все, что необходимо и даже много дополнительных функций, но лично мне хотелось дополнительного функционала, а именно:

  • возможность мониторить код страниц, которые доступны атакуемому юзеру в реальном времени;
  • возможность смотреть все, что он набирает на том сайте (от логина и пароля, до хоткейев и сообщений), то есть keylogger на JS;
  • возможность давать команды на JS своему боту в реальном времени, после просмотра кода полученных страниц;
  • возможность оставлять боту команды локально, чтобы он потом их “забирал” и выполнял без прямого нашего участия;
  • более маленькая вероятность спалиться боту, или возможность бота “прятаться” от любопытных глаз;

Как было упомянуто выше – решил позаимствовать у BeEF’a классную идею очереди выполнения комманд. Например, были проанализированы страницы, которые скинул бот, когда привелегированный юзер лазил у себя в панеле управления со stored XSS, мы оставляем боту команды – JS-код, типа в следующий раз когда юзер зайдет, нажми эту кнопку, запиши сюда такое значение и тд, когда этот юзер в следующий раз заходит на страницу, бот читает команды и выполняет их, а нам во все не обязательно быть у его штурвала – очень удобно.

В основном такой бот, конечно расчитан для статусных юзеров каких-нибудь сайтов, у которых есть дополнительные “рычаги” управления контентом, другими юзерами и тд. Из запросов по функционалу видно, что без серверной части не обойтись.

Реализуем идею.

Данную часть статьи в принципе можно пропустить, так как она просто описывает процесс реализации нужного бота и некоторые его детали, на случай, если кто-то захочет его переделать или допилить под себя. Хотя у бота в начале кода будут переменные, через которые можно выставить некоторые настройки.
Сначала алгоритм действий бота с момента загрузки:

1) Проверка наличия заголовка X-Frame-Options:DENY (если есть, то свертываем удочки);
2) Встраивание фрейма и настройка всех компонентов бота;
3) Удаление скрипта и всех следов в HTML-коде;
4) Налаживание контакта с сверверной частью и начало перессылки данными, реагируя на ответы (получая от сервера команды);

Первый пункт сделал не совсем полноценно, то есть бот проверяет только первую страницу и корневую заголовка. Дело в том, что обычно эти заголовки встраиваются веб-сервером и для всех страниц сразу и очень редко, что для отдельной страницы все делается “вручную”. Да и этот заголовок сам по себе довольно редок. Ну а по второму и третьему особо говорить нечего, ниже все будет.

Есть относительно важный момент, что перед добавлением кода скрипта бота в своем коде надо избавляться от признаков XSS в адресной строке сразу (от JS кода), так как это уменьшает шансы на обнаружение и самое галвное – предотвращает рекурсию, которая возникает при добавлении во фрейм адреса с тем же XSS кодом, который в свою очередь создает еще один фрейм с собой и тд.

Но на всякий случай в коде бота реализована возможность детекта такой фреймовой рекурсии и предотвращения при первой же попытке добавления фрейма в уже созданный, но лучше не надеятся только на нее, а дополнительно удалять код перед загрузкой кода бота. Хотя я проблем еще не встречал.

Функция проверки обновления фрейма. Перепробовал несколько способов экономно решить эту проблему с помощью вешания обработчиков событий на contentWindow или contentDocument, но ничего не удалось, поэтому пришлось писать функцию, которая чекала бы адрес фрейма и сравнивала его с сохраненным до этого, и на основе этого решала, обновиляется ли фрейм (изменился ли адрес) и потом сама себя рекурсивно вызывала.

Частота таких проверок в секунду регулируется переменной delay, которая указана в начале файла кода бота. Но позже, уже написав ее, нашел более эффективное решение – использовать простое решение и повесить onload на фрейм, так что ту функцию я оставил, но закомментировал, на случай, если она потом окажется более востребованной.

Отправка HTML-кода страницы.

Тут схема довольно простоя – после каждой перезагразуки фрейма (включая перую прогрузку) бот отправляет на сервер весь HTML-код страницы вместе с текущем ее адресом, чтобы потом можно было отличать принадлежность кода к нужным страницам.

На сервере реализована логика складирования страниц – сервер для каждого домена создает папку с названием этого домена и туда сохраняем все данные. Коды страниц сохраняются и постоянно обновляются на актуальные версии, но при этом каждый новый день создается уже новая копия страницы, чтобы можно было при необходимости контролировать историю версий. То есть для /news.php 1 сентября состояние будет обновляться, а уже 2 сентября будет создана ее копия, только актуальная уже на этот день и так с каждым днем заново (если юзер посещает эту страницу каждый день). Название страницы состоит из даты и путя до этой страницы относительно корня сайта (то есть без домена).

Кейлоггер на JavaScript’e.

Идея уже была реализована некоторыми энтузиастами, но для меня их наработки не подходили, хотя бы потому что большинство из них были довольно простыми, то есть детектили код нажатой клавиши и  черезString.fromCharCode переводили в символы. Но у такого метода ряд недостатков – управляющие клавиши типа шифта, контрола, пробела и пр, не переводятся ни в какой вид (часто просто в пустой символ), взаимодействие цифро-буквенных клавиш с шифтом некорректно логируется, так как это надо реализовывать программно, а также все нажатые клавиши отображаются в верхнем регистре, что тоже исправлять программно.

В итоге получился кейлоггер, который корректно детектил все клавиши цифр, букв и основных знаков, работая на обоих раскладках, реагирую на шифт и логгируя все основные специальные клавиши. Правда некоторые знаки (в верхней части цифрового ряда, которые печатаются при нажатом шифте и цифре), на некоторых машинах могут отличаться, так как были реализованы по основным стандартом, которые некоторым некоторые компании изменяют.
Каждая порция нажатых символов сохраняется у клиента до тех пор, пока текстовый элемент не потеряет фокус. Далее эта порция отправляется на сервер, где сохраняется в текстовом файле, который также будет создаваться каждый день с новой копией, чтобы не было роста до больших размеров и можно было быстро найти, что юзер набирал в такое время.

По мимо самих клавиш на сервер отправляется с каждой порцией информация об элементе, в котором набирался текст (то есть был ли это ,

You can use these HTML tags

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">