Продвинутая контрабанда запросов

В этом разделе вы расширите изученные концепции и научитесь более продвинутым техникам контрабанды HTTP-запросов. Мы также рассмотрим разнообразные атаки на базе HTTP/2, ставшие возможными благодаря уникальным возможностям Burp по тестированию HTTP/2. Не переживайте, если вы новичок в HTTP/2 — по ходу дела мы разберём все основы.

В частности, мы рассмотрим:

Чтобы вы могли отработать изученное на практике, по ходу материала вы найдете намеренно уязвимые лабораторные задания. Они основаны на реальных уязвимостях, впервые представленных на Black Hat USA 2021 Джеймсом Кеттлом.

Исследования PortSwigger

Контрабанда запросов в HTTP/2

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

Длина сообщения в HTTP/2

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

Хотя вы не увидите этого в Burp, сообщения HTTP/2 «по проводу» отправляются как серия отдельных фреймов. Каждый фрейм предваряется явным полем длины, которое сообщает серверу, сколько байтов нужно прочитать. Следовательно, длина запроса — это сумма длин его фреймов.

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

Понижение версии HTTP/2 (HTTP/2 downgrading)

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

http2-downgrading.jpg

Примечание о представлении сообщений HTTP/2

Поскольку HTTP/2 — бинарный протокол, мы позволили себе небольшую вольность, чтобы представлять сообщения HTTP/2 в человекочитаемом виде по всему материалу:

  • Мы показываем каждое сообщение как единое целое, а не как отдельные фреймы.

  • Мы показываем заголовки в виде обычных текстовых полей имени и значения.

  • Мы добавляем двоеточие перед именами псевдозаголовков, чтобы отличать их от обычных заголовков.

Это близко к тому, как Burp представляет сообщения HTTP/2 в Inspector, но учтите, что «по проводу» они выглядят иначе.

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

Запросы HTTP/2 не обязаны явно указывать свою длину в заголовке. При понижении версии это означает, что фронтенд-серверы часто добавляют заголовок HTTP/1 Content-Length, вычисляя его значение с использованием встроенного в HTTP/2 механизма определения длины. Интересно, что запросы HTTP/2 также могут включать собственный заголовок content-length. В этом случае некоторые фронтенд-серверы просто переиспользуют это значение в результирующем HTTP/1 запросе.

Спецификация предписывает, чтобы любой заголовок content-length в запросе HTTP/2 соответствовал длине, рассчитанной встроенным механизмом, но это не всегда корректно валидируется до понижения версии. В итоге может оказаться возможным провозить запросы путём внедрения вводящего в заблуждение заголовка content-length. Хотя фронтенд будет использовать неявную длину HTTP/2, чтобы определить конец запроса, бэкэнд HTTP/1 вынужден опираться на заголовок Content-Length, полученный из вашего внедрённого значения, что приводит к десинхронизации.

Front-end (HTTP/2)

:method

POST

:path

/example

:authority

vulnerable-website.com

content-type

application/x-www-form-urlencoded

content-length

0

Back-end (HTTP/1)

Tip

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

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

Блочное кодирование (chunked transfer encoding) несовместимо с HTTP/2, и спецификация рекомендует удалять любой заголовок transfer-encoding: chunked, который вы попытаетесь внедрить, либо блокировать запрос целиком. Если фронтенд-сервер этого не делает и затем понижает запрос для бэкэнда HTTP/1, который поддерживает блочное кодирование, это также может привести к атаке контрабанды.

Front-end (HTTP/2)

:method

POST

:path

/example

:authority

vulnerable-website.com

content-type

application/x-www-form-urlencoded

transfer-encoding

chunked

Back-end (HTTP/1)

Если сайт уязвим к контрабанде запросов H2.CL или H2.TE, вы потенциально можете использовать это поведение для проведения тех же атак, что мы разбирали в в предыдущих материалах.

Скрытая поддержка HTTP/2

Браузеры и другие клиенты, включая Burp, обычно используют HTTP/2 только при общении с серверами, которые явно объявляют поддержку через ALPN как часть TLS-рукопожатия. Некоторые серверы поддерживают HTTP/2, но из-за неправильной конфигурации не заявляют об этом должным образом. В таких случаях может показаться, что сервер поддерживает только HTTP/1.1, поскольку клиенты по умолчанию откатываются к нему. В результате тестировщики могут упустить доступную поверхность атаки HTTP/2 и пропустить проблемы на уровне протокола, как было в примерах, которые мы рассмотрели выше.

Чтобы настроить Burp Repeater использовать HTTP/2 и вручную протестировать такую неправильную конфигурацию:

  1. Откройте Settings и перейдите в Tools > Repeater.

  2. В разделе Connections включите опцию Allow HTTP/2 ALPN override.

  3. В Repeater откройте панель Inspector и раскройте раздел Request attributes.

  4. Переключателем установите Protocol в HTTP/2. Теперь Burp будет отправлять все запросы на этой вкладке по HTTP/2, независимо от того, объявляет ли сервер поддержку.

Примечание

Если вы используете Burp Suite Professional, Burp Scanner автоматически обнаруживает случаи скрытой поддержки HTTP/2.

Отравление очереди ответов

Response queue poisoning — мощная атака контрабанды запросов, позволяющая красть произвольные ответы, предназначенные другим пользователям, потенциально компрометируя их аккаунты и даже весь сайт.

Контрабанда запросов через внедрение CRLF

Даже если сайты принимают меры против базовых атак H2.CL или H2.TE, например валидируют content-length или удаляют любые заголовки transfer-encoding, бинарный формат HTTP/2 открывает новые способы обхода таких мер защиты.

В HTTP/1 иногда можно эксплуатировать расхождения в обработке одиночных символов перевода строки (\n) серверами, чтобы провезти запрещённые заголовки. Если бэкэнд считает это разделителем, а фронтенд — нет, некоторые фронтенды вовсе не заметят второй заголовок.

Такого расхождения нет при обработке полной последовательности CRLF (\r\n), потому что все серверы HTTP/1 единодушны, что это завершает заголовок.

С другой стороны, поскольку сообщения HTTP/2 бинарные, а не текстовые, границы каждого заголовка базируются на явных заранее заданных смещениях, а не на символах-разделителях. Это значит, что \r\n больше не имеет особого значения внутри значения заголовка и, следовательно, может быть включён внутрь значения без разделения заголовка:

foo

bar\r\nTransfer-Encoding: chunked

На первый взгляд это безобидно, но при переписывании в запрос HTTP/1 \r\n снова будет интерпретирован как разделитель заголовков. В результате бэкэнд-сервер HTTP/1 увидит два отдельных заголовка:

Разделение запросов в HTTP/2

Когда мы рассматривали отравление очереди ответов, вы узнали, как разделить один HTTP-запрос на ровно два полных запроса на бэкэнде. В том примере разделение происходило внутри тела сообщения, но при понижении HTTP/2 вы можете вызвать разделение и в заголовках.

Этот подход более универсален, потому что вы не зависите от использования методов, которым позволено тело запроса. Например, вы можете даже использовать GET:

:method

GET

:path

/

:authority

vulnerable-website.com

foo

Это также полезно в случаях, когда content-length валидируется, а бэкэнд не поддерживает блочное кодирование.

Учёт переписывания на фронтенде

Чтобы разделить запрос в заголовках, нужно понимать, как фронтенд-сервер переписывает запрос, и учитывать это при ручном добавлении любых заголовков HTTP/1. Иначе один из запросов может оказаться без обязательных заголовков.

Например, необходимо убедиться, что оба запроса, получаемые бэкэндом, содержат заголовок Host. Фронтенд-серверы обычно удаляют псевдозаголовок :authority и заменяют его новым заголовком HTTP/1 Host при понижении. Существуют разные подходы к этому, и от них зависит, куда нужно поместить внедряемый вами заголовок Host. Рассмотрим следующий запрос:

:method

GET

:path

/

:authority

vulnerable-website.com

foo

При переписывании некоторые фронтенды добавляют новый Host в конец текущего списка заголовков. С точки зрения HTTP/2 фронтенда это после заголовка foo. Обратите внимание, что это также после точки, в которой на бэкэнде произойдёт разделение. Значит, первый запрос останется вовсе без Host, а контрабандный запрос получит два. В этом случае нужно расположить внедряемый Host так, чтобы он оказался в первом запросе после разделения:

:method

GET

:path

/

:authority

vulnerable-website.com

foo

Аналогично потребуется отрегулировать расположение любых внутренних заголовков, которые вы хотите внедрить.

Tip

В примере выше мы разделили запрос так, чтобы сработало отравление очереди ответов, но таким же способом можно провозить префиксы для классических атак контрабанды. В этом случае ваши внедрённые заголовки могут конфликтовать с заголовками запроса, который на бэкэнде будет присоединён к вашему префиксу, что приведёт к дублированию заголовков или преждевременному завершению запроса. Чтобы снизить риск, добавьте в контрабандный префикс завершающий параметр тела вместе с заголовком Content-Length, немного превышающим тело. Запрос жертвы всё равно будет присоединён к вашему префиксу, но будет усечён до заголовков.

Туннелирование HTTP-запросов

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

Контрабанда 0.CL

Атаки десинхронизации 0.CL возникают, когда фронтенд игнорирует заголовок Content-Length, который бэкэнд обрабатывает. Долгое время считалось, что такой сценарий неэксплуатируем из-за взаимной блокировки соединений между серверами.

Однако, комбинируя атаку 0.CL с гаджетом раннего ответа (early-response gadget) — техникой, заставляющей бэкэнд отвечать до получения полного тела запроса — атакующие могут снять взаимную блокировку, а затем с помощью двойной десинхронизации построить полноценный эксплойт. Этот прорыв делает возможной эксплуатацию сценариев 0.CL.

За техническими подробностями см. сопроводительный доклад: HTTP/1.1 Must Die.

Last updated