Как стать автором
Обновить
178.18
Инфосистемы Джет
российская ИТ-компания

HTTP Request Smuggling: как особенности в обработке HTTP-заголовков приводят к атакам CL.TE и TE.CL

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров1.5K

HTTP Request Smuggling или контрабанда HTTP-запросов — тип уязвимости, который возникает из-за несоответствий в обработке HTTP-запросов между фронтендом и бэкендом. Каким образом различия в интерпретации заголовков позволяют атакующим использовать эту уязвимость? Как HTTP Request Smuggling можно использован в сочетании с Web Cache Poisoning? И на что обратить внимание, чтобы предотвратить подобные атаки? Разберем вместе на примере лабораторных работ с PortSwigger.

Введение в HTTP и его эволюция

Протокол HTTP (HyperText Transfer Protocol) — основа современного веба. Первая версия HTTP/0.9 была крайне простой и поддерживала только GET-запросы. С появлением HTTP/1.0 клиенты получили возможность отправлять более сложные запросы. Но для каждого из них требовалось устанавливать новое TCP-соединение, что создавало значительную нагрузку на сеть, особенно при загрузке страниц с множеством ресурсов — изображения, скрипты и стили.

В HTTP/1.1 появилась поддержка постоянных соединений (Persistent Connections). Это позволило использовать одно TCP-соединение для нескольких запросов и ответов, что значительно улучшило производительность. Также появилась возможность конвейерной обработки запросов (HTTP Pipelining), но из-за проблем с прокси-серверами и блокировкой очередей эта функция не получила широкого распространения.

С развитием протокола добавлялись новые функции, которые улучшили производительность, но также привели к появлению новых уязвимостей — например, HTTP Request Smuggling. Эта уязвимость возникает из-за различий в обработке запросов между разными компонентами системы — балансировщиками нагрузки и серверами приложений. Усложнение процесса обработки запросов, включая использование заголовков Content-Length и Transfer-Encoding, увеличило риск их неправильной интерпретации.

Современные версии протокола, такие как HTTP/2 и HTTP/3, продолжают развиваться, предлагая новые механизмы для повышения производительности и безопасности. Однако, несмотря на эти улучшения, уязвимости, связанные с неправильной обработкой запросов, остаются актуальными из-за сложности взаимодействия между разными компонентами системы.

Основы HTTP-запросов и особенности их обработки

HTTP-сообщения — это основной способ обмена данными между клиентом и сервером в рамках протокола HTTP. Они делятся на два типа:

  • запросы, которые инициирует клиент для выполнения действий на сервере;

  • ответы, которые сервер возвращает в результате обработки запроса.

Структура HTTP-сообщений — как запросов, так и ответов — состоит из нескольких  частей:

● Строка запроса (Start Line). В запросе она содержит метод — например, GET, POST — путь к ресурсу и версию HTTP. В ответе указывается версия протокола, код состояния и его текстовое описание.

● Заголовки (Headers). Это набор пар «ключ-значение» которые передают метаданные о запросе или ответе. Например, заголовки могут указывать: тип содержимого (Content-Type), размер данных (Content-Length) или кэширование (Cache-Control).

● Пустая строка (Empty Line). Она разделяет заголовки и тело сообщения, сигнализируя о завершении метаданных.

● Тело запроса (Body). Необязательная часть, которая содержит данные, связанные с запросом или ответом. Например, в POST-запросе тело может включать данные формы, а в ответе — содержимое запрашиваемого ресурса.

Ключевые заголовки — Content-Length и Transfer-Encoding — важны в обработке сообщений. Заголовок Content-Length указывает размер тела в байтах, а Transfer-Encoding: chunked позволяет передавать данные частями (chunks). Однако одновременное использование этих заголовков может привести к конфликтам, например, к уязвимостям типа HTTP Request Smuggling, когда фронтенд и бэкенд по-разному интерпретируют запрос.

Кроме того, HTTP-сообщения используют специальные символы \r\n — возврат каретки и перевод строки — для разделения строк и частей сообщения. Например:

POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 10\r\n
\r\n
wr3dmast3r

Концепция HTTP Request Smuggling

HTTP Request Smuggling — это тип уязвимости, который возникает из-за несоответствий в обработке HTTP-запросов между фронтендом, например, балансировщиком нагрузки или reverse proxy, и бэкендом — сервером приложения. Фронтенд выступает в роли посредника, который принимает запросы от клиентов и передает их на бэкенд для дальнейшей обработки.

Однако, если фронтенд и бэкенд по-разному интерпретируют заголовки Content-Length и Transfer-Encoding, это может привести к уязвимостям. Например:

● Фронтенд может использовать заголовок Content-Length для определения размера тела запроса.

● Бэкенд, в свою очередь, может полагаться на заголовок Transfer-Encoding: chunked, который указывает, что тело запроса передается частями.

Если запрос содержит оба заголовка одновременно, это может привести к тому, что часть запроса останется необработанной и «перетечет» в следующий запрос. В результате у атакующего появится возможность внедрить вредоносные данные или манипулировать поведением сервера.

Согласно RFC 2616, если запрос содержит оба заголовка — Content-Length и Transfer-Encoding — сервер должен игнорировать Content-Length и использовать Transfer-Encoding. Однако на практике фронтенд и бэкенд могут не следовать этому правилу, что и приводит к уязвимостям.

Представьте, что фронтенд — это охранник на входе в здание, а бэкенд — сотрудник внутри. Если охранник и сотрудник по-разному интерпретируют инструкции, атакующий может обмануть охранника и пронести в здание запрещенный предмет. Точно так же, при HTTP Request Smuggling, атакующий может «протащить» вредоносный запрос, используя разницу в интерпретации данных между фронтендом и бэкендом.

Важно отметить, что HTTP Request Smuggling не эксплуатирует уязвимости в самом веб-приложении. Вместо этого она использует особенности интерпретации HTTP-сообщений веб-серверами. Это инфраструктурная уязвимость, которая возникает из-за некорректной настройки или взаимодействия между компонентами веб-серверов.

С помощью этой уязвимости при атаке можно достичь такие цели:

● повышение привилегий;
● обход механизмов безопасности;
● доступ или изменение данных;
● кража сессии;
● отравление кэша.

Это лишь некоторые из возможных вариантов использования уязвимости. В зависимости от контекста приложения и особенностей взаимодействия между фронтендом и бэкендом, атакующий может найти и другие способы применения HTTP Request Smuggling.

Разница между CL.TE и TE.CL HTTP Request Smuggling

Рассмотрим два варианта HTTP Request Smuggling, характерных для HTTP/1.1: CL.TE и TE.CL. Но отметим, что подобные уязвимости могут возникать и в других версиях протокола. Ключевой момент — разница в интерпретации заголовков Content-Length (CL) и Transfer-Encoding (TE) между фронтендом и бэкендом. В зависимости от того, какой сервер использует какой заголовок, атакующий может манипулировать запросами, чтобы внедрить вредоносные данные.

Давайте разберем, как это работает в случаях CL.TE и TE.CL, а также, почему важно правильно учитывать символы, особенно при использовании chunked-кодирования. Понимание этих механизмов поможет лучше защитить инфраструктуру от подобных атак.

CL.TE (Frontend: Content-Length, Backend: Transfer-Encoding). В этом сценарии фронтенд использует заголовок Content-Length для определения размера тела запроса, а бэкенд — заголовок Transfer-Encoding: chunked для обработки тела запроса как chunked-данных.

Рассмотрим пример запроса:

POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 43\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n
GET /admin HTTP/1.1\r\n
Host: example.com

Фронтенд видит Content-Length: 43, считает, что тело запроса составляет 43 байта и передает весь запрос на бэкенд. Бэкенд видит Transfer-Encoding: chunked и начинает обрабатывать тело запроса как chunked-данные — первый chunk: 0\r\n\r\n — это конец chunked-данных. Всё, что идет после — GET /admin HTTP/1.1\r\n Host: example.com — бэкенд интерпретирует как начало нового запроса. В результате бэкенд обрабатывает второй запрос — GET /admin — который «внедрил» атакующий.

В этом случае атакующему нужно убедиться, что размер тела запроса, указанный в Content-Length, соответствует данным, которые фронтенд передаст на бэкенд. Остальные данные «перетекают» в следующий запрос.

Пример подсчета символов
Пример подсчета символов

TE.CL (Frontend: Transfer-Encoding, Backend: Content-Length). В этом сценарии фронтенд использует заголовок Transfer-Encoding: chunked для обработки тела запроса, а бэкенд использует заголовок Content-Length для определения размера тела запроса.

Рассмотрим пример запроса:

POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
7e\r\n
GET /admin HTTP/1.1\r\n
Host: example.com\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 20\r\n
\r\n
exploit=exploit\r\n
0\r\n
\r\n

Фронтенд видит Transfer-Encoding: chunked и обрабатывает тело запроса как chunked-данныепервый chunk: 7e (шестнадцатеричное значение, равное 126 байтам). Фронтенд читает следующие 126 байт, включая строку GET /admin HTTP/1.1 и всё, что идет после. Затем видит завершающий chunk (0\r\n\r\n) и завершает обработку запроса.

Бэкенд видит Content-Length: 4 и читает только первые 4 байта тела запроса — 7e\r\n. Оставшиеся данные — GET /admin HTTP/1.1 и так далее — бэкенд не обрабатывает, и они «перетекают» в следующий запрос. Когда следующий пользователь отправляет запрос, бэкенд начинает его обработку с «перетекших» данных, что может привести к неправильной интерпретации запроса.

В этом случае атакующий использует chunked-кодирование, чтобы фронтенд обработал весь запрос, а бэкенд прочитал только часть данных, указанную в Content-Length. Значение 7e (126 в десятичной системе) используется для указания размера chunk. Это позволяет фронтенду обработать большой объем данных, в то время как бэкенд прочитает только первые 4 байта.

Пример подсчета символов
Пример подсчета символов

Ключевые различия между CL.TE и TE.CL

Важно правильно подсчитывать символы, потому что в CL.TE-атаке необходимо, чтобы размер тела запроса, указанный в Content-Length, соответствовал данным, которые фронтенд передаст на бэкенд. Остальные данные «перетекают» в следующий запрос.

В TE.CL-атаке атакующий использует chunked-кодирование, чтобы фронтенд обработал определенный объем данных, а бэкенд прочитал только часть, указанную в Content-Length. Для этого требуется точный расчета размера chunk и понимание как фронтенд и бэкенд интерпретируют данные.

Классический пример отравления запроса

Рассмотрим пример, где атакующий отправляет запрос с двумя заголовками: Content-Length и Transfer-Encoding. Фронтенд и бэкенд интерпретируют запрос по-разному, что приводит к отравлению следующего запроса.

Вот как это выглядит:

Что здесь происходит:

  1. Атакующий отправляет запрос с заголовками Content-Length: 6 и Transfer-Encoding: chunked. Тело запроса содержит chunked-данные: 0\r\n\r\nG.

  2. Фронтенд — например, балансировщик нагрузки — интерпретирует запрос на основе Content-Length: 6 и считает, что тело запроса составляет 6 байт. Он передает весь запрос на бэкенд, включая символ «G».

  3. Бэкенд, в свою очередь, использует Transfer-Encoding: chunked и ожидает chunked-данные. Он обрабатывает 0\r\n\r\n как конец запроса и игнорирует символ «G». В результате символ «G» остается необработанным и «перетекает» в следующий запрос.

  4. Когда другой пользователь отправляет следующий запрос, бэкенд начинает его обработку с символа «G». Это приводит к тому, что запрос интерпретируется как GPOST вместо POST, из-за чего возникает ошибка.

Практика

Рассмотрим подобные атаки в деле на примере двух уязвимых приложений, в которых уязвимости HTTP Request Smuggling используется в комбинации с Web Cache Poisoning.

Lab: Exploiting HTTP request smuggling to perform web cache poisoning

Эта лабораторная работа включает фронтенд- и бэкенд-серверы, при этом фронтенд-сервер не поддерживает chunked-кодирование. Он настроен на кэширование определенных ответов.

Цель — выполнить атаку с использованием уязвимости HTTP Request Smuggling, которая приведет к отравлению кэша. В результате последующий запрос на загрузку JavaScript-файла должен перенаправляться на сервер атакующего.

Подтверждение уязвимости. На главной странице веб-приложения можно проверить наличие HTTP Request Smuggling. Во-первых, нам нужно определить, какие заголовки использует веб-приложение, например:

CL.TE — интерфейс использует заголовок Content-Length, серверная часть использует заголовок Transfer-Encoding.
TE.CL — интерфейс использует заголовок Transfer-Encoding, серверная часть использует заголовок Content-Length.

Обращаем внимание на эти две настройки, при проверке данной уязвимости они важны:

Запрос для проверки атаки:

Следующий после него запрос:

Так как следующий по порядку запрос возвращает код состояния 404, можно понять, что веб-приложение уязвимо для подделки HTTP-запросов CL.TE.

Изучение структуры приложения. При анализе истории HTTP-запросов можно заметить, что всё, что находится в директории /resources/* — кэшируется. Например, JavaScript-файлы, такие как /resources/js/tracking.js:

При просмотре функции отображения постов в блоге можно заметить функцию перехода к следующему посту:

При нажатии на ссылку отправляется GET-запрос на /post/next с параметром postId, после чего происходит перенаправление на следующий пост:

Web Cache Poisoning. Это атака, при которой атакующий манипулирует кэшем сервера, чтобы заставить его сохранить вредоносные данные. Когда другие пользователи запрашивают закэшированный ресурс, они получают подмененные данные, что может привести к перенаправлению на вредоносный сайт или выполнению вредоносного JS-кода.

Цель атаки — заставить сервер кэшировать вредоносный JavaScript-файл, который будут загружать другие пользователи. Для этого можно использовать HTTP Request Smuggling, чтобы подменить содержимое кэшируемого файла.

Попробуем использовать HTTP Request Smuggling для подмены заголовка Host в запросе с перенаправлением:

Когда мы отправили второй запрос, веб-приложение ответило нашим замаскированным запросом (/post/next?postId=5), и перенаправило нас на evil.com. Учитывая эту информацию, если мы сможем использовать перехват HTTP-запросов для заражения веб-кэша, мы сможем перенаправлять пользователей куда угодно.

Размещаем эксплойт:

Для атаки мы сначала отправляем с HTTP Request Smuggling отравленный запрос, который будет выполнять перенаправление на наш веб-сервер. После этого нам нужно отравить кэшируемый файл /resources/js/tracking.js, чтобы в кэш попало наше перенаправление, далее будет происходить импорт нашей полезной нагрузки на сайт.

Запрос на HTTP Request Smuggling:

Следующий отправленный запрос в приложении будет иметь перенаправление:

Результат:

Lab: Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability

Эта лабораторная работа включает два сервера: фронтенд, например, балансировщик нагрузки или reverse proxy, и бэкенд — сервер приложения. Важно отметить, что бэкенд-сервер не поддерживает chunked-кодирование. На сервере также есть админ-панель по пути /admin, но доступ к ней блокируется фронтенд-сервером.

Цель — используя уязвимость HTTP Request Smuggling, провести атаку, которая позволит получить доступ к админ-панели на бэкенд-сервере и удалить пользователя carlos.

Подтверждение уязвимости. Здесь мы можем попытаться определить, уязвимо ли веб-приложение для перехвата HTTP-запросов. Во-первых, нам нужно определить, какой тип HTTP-запроса используется, например:

CL.TE интерфейс использует заголовок Content-Length, серверная часть использует заголовок Transfer-Encoding.
TE.CL интерфейс использует заголовок Transfer-Encoding, серверная часть использует заголовок Content-Length.

Запрос на проверку HTTP Request Smuggling:

Сервер возвращает код состояния 500. Поэтому мы можем предположить, что веб-приложение уязвимо для подделки HTTP-запросов TE.CL.

Эксплуатация уязвимости

Проверяем админ-панель:

Пробуем обойти ограничение с помощью HTTP Request Smuggling:

Следующий запрос:

Мы смогли обойти блокировку доступа к директории /admin — это уже что-то. Попробуем использовать localhost во втором запросе:

Следующий запрос:

Отлично, мы получили доступ к админ-панели, осталось удалить пользователя:

Следующий запрос:

Рекомендации по защите

HTTP Request Smuggling — серьезная уязвимость, которая может привести к компрометации данных и нарушению работы серверов. Понимание механизмов HTTP и правильная настройка серверов — ключ для предотвращения таких атак. Регулярное тестирование и обновление инфраструктуры помогут минимизировать риски и обеспечить безопасность ваших приложений. Также рекомендуется использовать современные версии протокола — HTTP/2 и HTTP/3 — у которых есть встроенные механизмы для предотвращения подобных атак.

Четыре совета:

  1. Запретить повторное использование соединений с бэкендом. Это исключит возможность «перетекания» данных между запросами, а это — основа для атак типа Smuggling.

  2. Перейти на HTTP/2 для взаимодействия с бэкендом. Этот протокол использует бинарный формат и строгую структуру сообщений, что снижает вероятность ошибок интерпретации.

  3. Унифицировать ПО на фронтенде и бэкенде. Использование одинакового программного обеспечения минимизирует различия в обработке запросов, что снижает риск уязвимостей.

  4. Внедрить WAF (Web Application Firewall) с функцией обнаружения аномалий. Современные WAF способны анализировать трафик и блокировать подозрительные запросы, включая попытки HTTP Request Smuggling.

Дополнительные ссылки:

HTTP Desync Attacks: Smashing into the Cell Next Door — DEF CON

HTTP 1 Vs HTTP 2 Vs HTTP 3

PortSwigger — HTTP Request Smuggling

Теги:
Хабы:
+15
Комментарии0

Публикации

Информация

Сайт
jet.su
Дата регистрации
Дата основания
1991
Численность
1 001–5 000 человек
Местоположение
Россия