На пороге уже стоит 2018 год. Но большинство бородатых уязвимостей продолжает жить в разрабатываемых системах. И не смотря на то что появился OWASP Top-10 2017. И приоритетность определенных вещей сильно поменялась. По прежнему ничего не мешает натыкаться на ситуации, которые были актуальны в 2010.
История началась с банального любопытства к продукту компании, в которой работает мой знакомый. Продукт интересный. Покупают данный продукт очень вдумчиво и за ценники с 6 знаками. Баг-баунти официальной у этой компании нет. Но я подумал, что даже если что-то найду — через знакомого разрулю и передам.
Найти основной продукт компании не составило труда. Есть официальный сайт с демо-приложением. Полез туда смотреть что там есть, попутно обернув весь трафик через прокси в Burp Suit.
Увидев input field, мне сразу же захотелось воткнуть туда xss. Воткнул банальный вектор
<script>alert(xss);</script>
И что вы думаете произошло? Конечно, сработало!
Я поискал еще возможные поля ввода информации, и абсолютно везде выполнялась моя XSS атака. А нет, вру! В одном месте почему-то не сработало. Но, потратив немного времени, я его смог одолеть с другим payload вектором и обходом экранирования. Итак, на руках есть как минимум 8 xss векторов. Можно было это число увеличить в разы, но было очень лениво тратить время на обход функциональности системы. Да и видно было, что проблема комплексная.
Уже хотел пойти искать, через знакомого, ответственных за это безобразие. Но подумал, что если все так плохо с экранированием, то возможно есть еще что-то. Отложил возможный контакт на попозже и полез еще смотреть.
В логах были намеки подозревать приложение в возможности реализовать CSRF атаку. Т.е не было никаких CSRF токенов, которые предотвращают возможность подобной атаки. Чтобы подтвердить мои опасения, нужен был реальный пример. А чтобы к моим замечаниям отнеслись максимально ответственно, нужен был пример, который показывает максимальный урон системе.
Пару слов о CSRF, хоть вы и могли бы загуглить это.
Представьте что вы зашли в веб-клиент своего банка. И тут вам вконтактике присылают ссылочку на "смешных котиков". Вы отложили в сторону номер карты родственника, которому хотели только что перевести деньги, и пошли поглядеть на котиков. Котики были действительно смешные. И после вы решили все же перевести родственнику немного деньжат. Вернувшись в соседнюю вкладку веб-клиента банка, вы пытаетесь сделать перевод, но вот денег у вас уже недостаточно. И вы в жизни не догадаетесь, что обнесли ваш банковский аккаунт котики-бандиты. Эти котики прикидывались смешными, пока их сородичи переводили деньги вашего счета продавцам кошачьего корма и валерьянки.
Это топорный пример. И, безусловно, подобное ни в одном банке уже провернуть не получится. Но этот пример должен вам помочь понять всю серьезность уязвимости CSRF.
А теперь без котиков и с подробностями.
В исследуемом приложении есть простая возможность сделать logout. Можно проверить разлогинивание пользователей через csrf. Вы скажете: что тут такого, это не опасно! Но это и не вектор атаки. Это лишь проверка нашей теории о том, что наша идея работает.
Для этого нам потребовалось смастерить в нашей подсети тестовый сайтик следующего содержания.
<html>
<body>
<form action="https://example.com/client/api/logout">
<input type="submit" value="Submit request" />
</form>
</body>
</html>
Дальше выполняем вход в систему с другого браузера. Открываем в этом браузере тестируемое приложение с активной логин-сессией, а во второй вкладке наш сайтик. Нажимаем на нашу кнопку submit. Вернувшись в предыдущую вкладку с нашим тестовы приложением, мы обнаружим, что уже не залогинены.
Раз наш пример сработал, значит с вероятность 80% сработает и в других местах. 20% я оставил на то, что разработчики в важных местах используют средства защиты от CSRF атаки. Но такое бывает редко. Или CSRF токены есть везде, или их нет вообще.
Т.к наш демо-сайт с приложением позволял залогиниться от администратора системы, я мог посмотреть что может администратор, и, главное, как он это делает. Интересной находкой был сброс пароля пользователю системы. Выглядел он примерно так
<method="POST">
<input name="Id" value="1" />
<input name="newPassword" value="testerok" />
<input name="confirmPassword" value="testerok" />
И если вас не смутило, что для смены пароля вам не нужно вводить старый пароль, то определенно вас должно смутить то, что пользователи передаются через ID.
А дальше сценарий атаки примерно следующий:
- Отправляем администратору сообщение в системе с ссылкой на нашу страницу.
- На нашей странице размещаем CSRF код для смены пароля пользователю.
- Администратор проходит по ссылке.
- У пользователя изменен пароль. При этом администратор даже не поймет, что что-то произошло.
Код страницы
<html>
<body>
<form action="http://example.ru/main/Security/Users/ChangePassword" method="POST">
<input type="hidden" name="Id" value="5" />
<input type="hidden" name="newPassword" value="test3" />
<input type="hidden" name="confirmPassword" value="test3" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
Все, что нам останется — зайти под пользователем, которому администратор "случайно" установил новый пароль. По такому же примеру работает кейс с созданием нового пользователя в системе. Можно все так же скрыто провернуть и создать супер-пользователя! Под которым можно сидеть в системе и сливать кучу ценной инфы о компании — приказы, документы, финансовые сведения.
Отдельно во всей этой истории мне хочется выделить реакцию на проблемы. И скорость их исправления.
На зарепорченные XSS отреагировали достаточно быстро. С ними вообще вопросов не было. А вот с CSRF я от ответственного человека стал получать следующие вопросы и возражения.
Посмотрим, что скажут разработчики. По идее у нас сессия по ip привязана, и одного токена должно быть мало (с) Руководитель отдела тестирования
Только у меня в этот момент дернулся глаз? О какой защите через whitelisted IP может идти речь, если админ со своего компьютера все делает. Это фишка CSRF. Но дальше больше. Ответственный заявил следующее.
Bug#7 Я пока не понимаю, как это реализовать (с) Руководитель отдела тестирования
Речь идет о массовой смене паролей всем пользователям системы. Тут мне пришлось прям со скриншотами приходить и рассказывать, почему не стоит такую возможность вообще оставлять.
Можно разом перебрать все id
Ну и остановиться на тех которые нам не интересны
И, по правде говоря, получать уточняющие вопросы на такие очевидные и всем известные уязвимости было печально.
После всех переписок, уточнений, кучу потраченного времени, я был уведомлен о том, что мне будет выплачено вознаграждение по специальной багбаунти специально для меня. При этом расчет этого вознаграждения по сей день остается для меня какой-то магией. Хотя мне была приведена формула, по которой все посчитали.
Все XSS кроме одной посчитали дублями и просуммировали по понижающему коэффициенту. СSRF по другому коэффициенту.
В итоге я получил 100 Euro.
Но хорошо, что вообще что-то получил!
Из-за «интересной» политики поддержки пользователей, большинство клиентов так и останется без этих критических обновлений и исправлений.
Просто потому, что у этих клиентов нет годового абонемента поддержки. Так что в какой-то крупной компании, использующей этот дорогой продукт, по сей день можно утащить куки или сделать что-то от лица пользователя, подсунув картинку с котиками. Список клиентов внушителен — банки, страховые, промышленные холдинги...
В каком то смысле 0day получилась (уязвимость не имеющая исправления).
На мой взгляд можно бы было поступить разумнее и благороднее. Microsoft вон все еще патчи выпускает для Windows XP.
Раскрывать название компании и клиентов компании я не стал по морально-этическим соображениям.
Ну и представители за репутацию переживают.
Таймлайн:
19 июля — были сделаны репорты
9 августа — подтверждены все репорты и начислено вознаграждение
28 августа — исправлены проблемы с фильтрацией XSS
14 ноября — реализовали исправление CSRF для клиентов у которых есть абонемент поддержки
Автор: Валерий Шевченко