Обложка статьи «Атака HTTP request smuggling: механизм, разновидности и защита»

Атака HTTP request smuggling: механизм, разновидности и защита

Перевод статьи «HTTP request smuggling»

HTTP request smuggling — это атака, при которой злоумышленник вмешивается в обработку последовательности HTTP-запросов, которую веб-приложение получает от одного или нескольких пользователей. Уязвимости, связанные с HTTP request smuggling, часто имеют критический характер, позволяя злоумышленнику обойти меры безопасности, получить несанкционированный доступ к конфиденциальным данным и напрямую скомпрометировать информацию других пользователей приложения.

Примечание HTTP request smuggling впервые была задокументирована в 2005 году, недавно эта тема была снова поднята в исследовании PortSwigger.

Что происходит во время атаки HTTP request smuggling?

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

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

В этой ситуации крайне важно, чтобы фронтенд и бэкенд системы одинаково понимали начало и конец запроса. В противном случае злоумышленник может отправить запрос, который по-разному интерпретируется фронтенд и бэкенд системами:

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

Как возникает уязвимость HTTP request smuggling?

Большинство уязвимостей, связанных с HTTP request smuggling, возникает из-за того, что спецификация HTTP предоставляет два разных способа указать, где заканчивается запрос: заголовок Content-Length и заголовок Transfer-Encoding.

Заголовок Content-Length прост: он определяет длину тела сообщения в байтах. Например:

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

Заголовок Transfer-Encoding может использоваться для указания того, что тело сообщения разбито на блоки. Каждый блок состоит из размера фрагмента в байтах (выраженного в шестнадцатеричном формате), за которым следует новая строка, за которой следует содержимое фрагмента. Сообщение заканчивается блоком, содержащим ноль. Например:

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

b
q=smuggling
0

Поскольку спецификация HTTP предоставляет два разных метода для указания длины сообщений HTTP, одно сообщение может использовать оба метода одновременно так, что они конфликтуют друг с другом. Спецификация HTTP пытается предотвратить эту проблему, заявляя, что если присутствует и заголовок Content-Length, и Transfer-Encoding, то заголовок Content-Length следует игнорировать. Этого может быть достаточно, чтобы избежать двусмысленности, когда в игре находится только один сервер, но не когда два или более сервера объединены в цепочку. В этой ситуации проблемы могут возникнуть по двум причинам:

  1. Некоторые серверы не поддерживают заголовок Transfer-Encoding в запросах.
  2. Некоторые серверы, которые поддерживают заголовок Transfer-Encoding, могут не обрабатывать его, если заголовок каким-то образом обфусцирован.

Если фронтенд и бэкенд серверы ведут себя по-разному в отношении (возможно, обфусцированного) заголовка Transfer-Encoding, то они могут по-разному интерпретировать начало и конец сообщений, что приводит к уязвимостям HTTP request smuggling.

Как выполнить атаку HTTP request smuggling?

Атаки HTTP request smuggling включают в себя размещение заголовков Content-Length и Transfer-Encoding в одном HTTP-запросе и манипулирование ими, чтобы фронтенд и бэкенд серверы обрабатывали запрос по-разному. Способ, которым это будет сделано, зависит от поведения двух серверов:

  • CL.TE: фронтенд сервер использует заголовок Content-Length, а бэкенд сервер — Transfer-Encoding.
  • TE.CL: фронтенд сервер использует заголовок Transfer-Encoding, а бэкенд сервер — Content-Length.
  • TE.TE: фронтенд и бэкенд серверы поддерживают заголовок Transfer-Encoding, но один из серверов может быть вынужден не обрабатывать его, если тот был обфусцирован.

Уязвимости CL.TE

Здесь фронтенд сервер использует заголовок Content-Length, а бэкенд — Transfer-Encoding. В этом случае можно выполнить простую атаку HTTP request smuggling:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED

Фронтенд сервер обрабатывает заголовок Content-Length и определяет, что тело запроса имеет длину 13 байтов — до конца SMUGGLED. Этот запрос перенаправляется на бэкенд сервер.
Бэкенд сервер обрабатывает заголовок Transfer-Encoding и обрабатывает тело сообщения с использованием разбивки на блоки. Он обрабатывает первый блок, который содержит ноль, что указывает на завершение запроса. Следующие байты, SMUGGLED, остаются необработанными, и бэкенд сервер будет обрабатывать их как начало следующего запроса в последовательности.

Здесь можно посмотреть лабораторную работу по уязвимости CL.TE (требуется регистрация).

Уязвимости TE.CL

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

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked

8
SMUGGLED
0

Примечание Чтобы отправить этот запрос с помощью Burp Repeater, сначала нужно перейти в меню Repeater и убедиться, что опция «Update Content-Length» снята. Нужно включить завершающую последовательность \r\n\r\n после последнего 0.

Фронтенд сервер обрабатывает заголовок Transfer-Encoding и тело сообщения с использованием фрагментированного кодирования. Сначала обрабатывается первый блок длиной 8 байт до начала строки, следующей за SMUGGLED. Затем обрабатывается второй блок с нулевой длиной, что принимается за завершение запроса. Этот запрос перенаправляется на бэкенд сервер.

Бэкенд сервер обрабатывает заголовок Content-Length и определяет, что тело запроса имеет длину 3 байта, вплоть до начала строки, следующей за 8. Следующие байты, начиная с SMUGGLED, остаются необработанными, бэкенд сервер будет обрабатывать их как начало следующего запроса в последовательности.

Здесь можно посмотреть лабораторную работу по уязвимости TE.CL (требуется регистрация).

Поведение TE.TE: обфускация TE заголовка

В этом случае и фронтенд, и бэкенд серверы поддерживают заголовок Transfer-Encoding, но один из серверов может быть вынужден не обрабатывать его, поскольку он обфусцирован.
Есть множество способов обфусцировать заголовок Transfer-Encoding. Например:

Transfer-Encoding: xchunked

Transfer-Encoding : chunked

Transfer-Encoding: chunked
Transfer-Encoding: x

Transfer-Encoding:[tab]chunked

[space]Transfer-Encoding: chunked

X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

Каждый из этих методов — едва уловимое отклонение от спецификации HTTP. Реальный код, который реализует спецификацию протокола, редко придерживается его с абсолютной точностью, и для разных реализаций характерно допускать различные отклонения от спецификации. Чтобы выявить уязвимость TE.TE, необходимо найти какой-либо вариант заголовка Transfer-Encoding, который обработает только один из серверов (фронтенд или бэкенд), а другой проигнорирует.

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

Здесь можно посмотреть лабораторную работу по уязвимости TE.TE (требуется регистрация).

Как предотвратить атаку HTTP request smuggling?

Уязвимости в HTTP request smuggling возникают в тех случаях, когда фронтенд сервер пересылает несколько запросов на бэкенд сервер по одному и тому же сетевому соединению, а протокол, используемый для внутренних подключений, несёт в себе риск того, что политика серверов по обработке длины запросов не согласована. Ниже перечислены несколько общих правил предотвращения возникновения уязвимостей в HTTP request smuggling:

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

В некоторых случаях уязвимостей можно избежать, если заставить фронтенд сервер нормализовать неоднозначные запросы или заставить бэкенд сервер отклонять неоднозначные запросы и закрывать сетевое соединение. Однако эти подходы потенциально больше подвержены ошибкам, чем общие правила, указанные выше.

Не смешно? А здесь смешно: @ithumor