Атаки десинхронизации на стороне клиента
Классические атаки десинхронизации или контрабанды запросов опираются на намеренно некорректные запросы, которые обычные браузеры просто не отправляют. Это ограничивает такие атаки сайтами с архитектурой фронтенд/бэкэнд. Однако, как мы узнали из CL.0 атак, вызвать десинхронизацию можно, используя полностью совместимые с браузером HTTP/1.1-запросы. Это не только открывает новые возможности для серверной контрабанды запросов, но и формирует целый новый класс угроз — атаки десинхронизации на стороне клиента.
Что такое десинхронизация на стороне клиента?
Client-side desync (CSD) — это атака, которая заставляет браузер жертвы десинхронизировать собственное соединение с уязвимым сайтом. Это отличается от обычной контрабанды запросов, при которой десинхронизируется соединение между фронтенд и бэкэнд серверами.

Иногда веб-серверы можно побудить отвечать на POST-запросы, не считывая тело. Если затем они позволяют браузеру переиспользовать то же соединение для дополнительных запросов, возникает уязвимость десинхронизации на стороне клиента.
На общих чертах CSD-атака включает следующие этапы:
Жертва посещает веб-страницу на произвольном домене, содержащую вредоносный JavaScript.
JavaScript заставляет браузер жертвы отправить запрос на уязвимый сайт. В его теле содержится контролируемый атакующим префикс запроса — подобно обычной контрабанде запросов.
Вредоносный префикс остаётся в сокете TCP/TLS сервера после того, как он ответил на исходный запрос, десинхронизируя соединение с браузером.
Затем JavaScript инициирует последующий запрос по отравленному соединению. Этот запрос добавляется к вредоносному префиксу, вызывая опасный ответ сервера.
Поскольку эти атаки не опираются на различия парсинга между двумя серверами, уязвимыми могут оказаться даже односерверные сайты.
Тестирование CSD
Из-за дополнительной сложности, связанной с использованием браузера для осуществления атаки, при тестировании CSD важно действовать методично. Хотя порой может возникнуть соблазн поспешить, мы рекомендуем следующий порядок действий. Это позволит вам поэтапно подтвердить свои предположения о каждом элементе атаки.
Определите эксплуатируемый гаджет.
Постройте рабочий эксплоит в Burp.
Воспроизведите эксплоит в вашем браузере.
И Burp Scanner, и расширение HTTP Request Smuggler могут автоматизировать большую часть процесса, но полезно уметь делать всё вручную для лучшего понимания.
Поиск векторов CSD
Первый шаг — найти или сконструировать запрос, который заставляет сервер игнорировать заголовок Content-Length. Самый простой способ — отправить запрос, в котором указанный Content-Length длиннее фактического тела:
Если запрос просто зависает или истекает по таймауту, это говорит о том, что сервер ждёт оставшиеся байты, обещанные заголовками.
Если вы получаете немедленный ответ, вероятно вы нашли CSD-вектор. Это требует дополнительной проверки.
Как и в случае с уязвимостями CL.0, наиболее вероятными кандидатами мы нашли конечные точки, не ожидающие POST-запросов, например статические файлы или редиректы на уровне сервера.
Альтернативно, вы можете попытаться вызвать такое поведение, спровоцировав ошибку на сервере. В этом случае помните, что вам всё равно нужен запрос, который браузер отправит как кросс-доменный. На практике это значит, что вы можете менять только URL, тело и некоторые мелочи вроде заголовка Referer и завершающей части заголовка Content-Type.
Вы также можете попытаться вызвать ошибки сервера, пытаясь подняться выше корня веб-сайта. Помните, что браузеры нормализуют путь, поэтому нужно URL-кодировать символы для обхода:
Подтверждение вектора десинхронизации в Burp
Важно понимать, что некоторые защищённые серверы отвечают, не дожидаясь тела, но всё же корректно парсят его по прибытии. Другие некорректно обрабатывают Content-Length, но сразу закрывают соединение после ответа, из-за чего их нельзя эксплуатировать.
Чтобы отфильтровать такие случаи, попробуйте отправить два запроса по одному соединению и посмотреть, удастся ли использовать тело первого запроса, чтобы повлиять на ответ на второй — так же, как вы бы делали при тестировании на CL.0.
Построение PoC в браузере
После того как вы нашли подходящий вектор в Burp, важно убедиться, что вы можете воспроизвести десинхронизацию в браузере.
Зайдите на сайт, с которого вы планируете запускать атаку на жертву. Он должен быть на домене, отличном от уязвимого сайта, и доступен по HTTPS. В лабораторных работах используйте предоставленный exploit-сервер.
Откройте инструменты разработчика и перейдите на вкладку Network.
Сделайте следующие настройки:
Включите Preserve log.
Кликните правой кнопкой по заголовкам и включите колонку Connection ID.
Это обеспечит логирование каждого запроса браузера на вкладке Network с указанием, какое соединение использовалось, что поможет в отладке.
Переключитесь на вкладку Console и используйте
fetch(), чтобы воспроизвести пробный запрос, который вы тестировали в Burp. Код может выглядеть примерно так:
Помимо указания метода POST и добавления вредоносного префикса в тело, обратите внимание на следующие опции:
mode: 'no-cors'— гарантирует, что идентификатор соединения каждого запроса будет виден на вкладке Network, что помогает отладке.credentials: 'include'— браузеры обычно используют отдельные пулы соединений для запросов с куками и без. Эта опция гарантирует отравление пула «with-cookies», который и нужен для большинства эксплойтов.
При запуске команды вы должны увидеть два запроса на вкладке Network. Первый должен получить обычный ответ. Если второй получит ответ на вредоносный префикс (в данном случае 404), это подтверждает, что вы успешно вызвали десинхронизацию из браузера.
Обработка редиректов
Как уже упоминалось, конечные точки, вызывающие редиректы на уровне сервера, — частый вектор для CSD. При построении эксплойта это создаёт небольшую проблему: браузер будет следовать редиректу, нарушая последовательность атаки. К счастью, есть простой обход.
Установив для исходного запроса опцию mode: 'cors', вы можете намеренно вызвать CORS-ошибку, которая помешает браузеру следовать редиректу. Затем продолжите последовательность, вызвав catch() вместо then(). Например:
Минус подхода в том, что вы не увидите идентификатор соединения на вкладке Network, что может затруднить отладку.
Эксплуатация CSD
После того как вы нашли подходящий вектор и проверили предположение в браузере, можно приступать к поиску эксплуатируемых гаджетов.
Клиентские варианты классических атак
С помощью этих техник вы можете проводить большую часть тех же атак, что и при серверной контрабанде. Всё, что нужно, — чтобы жертва посетила вредоносный сайт, заставляющий её браузер запустить атаку.
Отравление кэша на стороне клиента
Ранее мы показывали, как с помощью серверной десинхронизации можно преобразовать внутрисайтовый редирект в открытый, перехватив импорт JavaScript-ресурса. Того же эффекта можно добиться, используя только десинхронизацию на стороне клиента, однако сложнее отравить нужное соединение в нужный момент. Гораздо проще использовать десинхронизацию, чтобы отравить кэш браузера. Так не важно, какое соединение он использует для загрузки ресурса.
В этом разделе мы рассмотрим процесс построения атаки. В общих чертах он включает:
Поиск подходящего CSD вектора и десинхронизация соединения браузера.
Отравление кэша редиректом
После того как вы нашли подходящий CSD вектор и убедились, что можете воспроизвести его в браузере, нужно определить подходящий гаджет для редиректа. Далее отравление кэша довольно прямолинейно.
Сначала подправьте PoC так, чтобы провезённый префикс вызывал редирект на домен, где вы разместите вредоносную нагрузку. Затем измените последующий запрос на прямой запрос целевого файла JavaScript.
Итоговый код может выглядеть так:
Это отравит кэш, хотя и бесконечным редиректом обратно на ваш скрипт. Проверить это можно, открыв скрипт в браузере и изучив вкладку Network в инструментах разработчика.
Запуск импорта ресурса
Погружение жертвы в бесконечный цикл может быть слегка раздражающим, но это не является серьезным уязвимостью. Теперь доработайте скрипт так, чтобы, когда браузер вернётся с уже отравленным кэшем, он был перенаправлен на страницу уязвимого сайта, которая инициирует импорт ресурса. Это легко реализовать условными конструкциями, исполняя разный код в зависимости от того, открывалось ли уже ваше окно.
Когда браузер попытается импортировать ресурс на целевом сайте, он возьмёт отравленную запись кэша и будет снова перенаправлен на вашу вредоносную страницу в третий раз.
Доставка полезной нагрузки
На этом этапе вы заложили основу атаки, но финальная задача — понять, как доставить пейлоад.
Изначально браузер жертвы загружает вашу вредоносную страницу как HTML и исполняет вложенный JavaScript в контексте вашего домена. Когда позже он попытается импортировать JavaScript-ресурс на целевом домене и получит редирект на вашу страницу, вы заметите, что скрипт не выполняется. Это потому, что вы всё ещё отдаёте HTML, когда браузер ожидает JavaScript.
Для реального эксплойта нужно уметь отдавать чистый JavaScript с той же конечной точки, обеспечив, чтобы он исполнялся только на финальном этапе и не мешал подготовительным запросам.
Один из подходов — создать полиглот-нагрузку, обернув HTML в комментарии JavaScript:
Когда браузер загружает страницу как HTML, выполняется только JavaScript внутри тегов <script>. Когда же он в итоге загрузит это в JavaScript-контексте, выполнится только alert(), а остальное будет воспринято как произвольные комментарии разработчика.
Подробнее о том, как эту уязвимость нашли в дикой природе, смотрите в работе PortSwigger Research Browser-Powered Desync Attacks: A New Frontier in HTTP Request Smuggling.
Пивотинг атак на внутреннюю инфраструктуру
Большинство серверных атак десинхронизации манипулируют заголовками HTTP так, как это возможно только с помощью инструментов вроде Burp Repeater. Например, нельзя заставить браузер отправить запрос с полезной нагрузкой log4shell в заголовке User-Agent:
Это означает, что такие атаки обычно ограничены сайтами, доступ к которым у вас есть напрямую. Однако, если сайт уязвим к CSD, вы сможете добиться желаемого эффекта, заставив браузер жертвы отправить такой запрос:
Поскольку все запросы исходят из браузера жертвы, это потенциально позволяет пивотить атаки на любой сайт, к которому у неё есть доступ — включая сайты во внутренних доверенных сетях или скрытые за IP-ограничениями. Некоторые браузеры работают над защитой от таких атак, но охват у них, вероятно, будет лишь частичным.
Как предотвратить CSD
Некоторые меры для предотвращения уязвимостей десинхронизации на стороне клиента и других форм атак десинхронизации смотрите в разделе Как предотвратить уязвимости контрабанды HTTP-запросов.
Что дальше?
Вы узнали об CL.0 и CSD атаках, но есть ещё один потенциальный вектор десинхронизации, который включает как серверные, так и клиентские эксплойты на сайтах, изначально кажущихся защищёнными. Подробнее в разделе Атаки десинхронизации на основе паузы.
Last updated