Векторы, эксклюзивные для HTTP-2
Из-за того, что HTTP/2 — бинарный протокол, а не текстовый, существует ряд потенциальных векторов, которые невозможно сконструировать в HTTP/1 из-за ограничений его синтаксиса.
Мы уже видели, как можно внедрить CRLF в значение заголовка. В этом разделе мы покажем некоторые другие векторы, эксклюзивные для HTTP/2, которые вы можете использовать для внедрения полезных нагрузок. Хотя такие запросы официально запрещены спецификацией HTTP/2, некоторые серверы не справляются с их корректной валидацией и блокированием.
Внедрение через имена заголовков
В HTTP/1 имя заголовка не может содержать двоеточие, поскольку этот символ используется парсерами для обозначения конца имени. В HTTP/2 это ограничение отсутствует.
Комбинируя двоеточия с символами \r\n, вы можете использовать поле имени заголовка HTTP/2, чтобы протащить другие заголовки мимо фронтенд-фильтров. После переписывания запроса в синтаксис HTTP/1 на бэкэнде они будут интерпретированы как отдельные заголовки:
Front-end (HTTP/2)
foo: bar\r\nTransfer-Encoding: chunked\r\nX:
ignore
Back-end (HTTP/1)
Foo: bar\r\n
Transfer-Encoding: chunked\r\n
X: ignore\r\nВнедрение через псевдозаголовки
HTTP/2 не использует строку запроса или строку статуса. Вместо этого эти данные передаются через серию псевдозаголовков в начале запроса. В текстовых представлениях сообщений HTTP/2 они обычно помечаются префиксом из двоеточия, чтобы отличать их от обычных заголовков. Всего существует пять псевдозаголовков:
:method— метод запроса.:path— путь запроса. Обратите внимание, что он включает query string.:authority— приблизительный эквивалент заголовкаHostв HTTP/1.:scheme— схема запроса, обычноhttpилиhttps.:status— код статуса ответа (в запросах не используется).
Когда сайты понижают запросы до HTTP/1, они используют значения некоторых из этих псевдозаголовков для динамической сборки строки запроса. Это открывает новые интересные способы построения атак.
Задание неоднозначного хоста
Хотя HTTP/1 заголовок Host фактически заменяется псевдозаголовком :authority в HTTP/2, вы всё равно можете отправить в запросе и заголовок host.
В некоторых случаях это может привести к появлению двух заголовков Host в переписанном HTTP/1-запросе, что, например, открывает возможность обхода фронтенд-фильтров “duplicate Host header”. Это потенциально делает сайт уязвимым к ряду атак на заголовок Host, от которых он ранее мог быть защищён.
Задание неоднозначного пути
Попытка отправить запрос с неоднозначным path невозможна в HTTP/1 из-за того, как парсится строка запроса. Но поскольку путь в HTTP/2 задаётся псевдозаголовком, теперь можно отправить запрос с двумя различными путями следующим образом:
:method
POST
:path
/anything
:path
/admin
:authority
vulnerable-website.com
Если есть расхождение между тем, какой путь проверяется механизмами контроля доступа сайта и какой путь используется для маршрутизации запроса, это может позволить получить доступ к конечным точкам, которые в противном случае были бы недоступны.
Внедрение полной строки запроса
При понижении версии значение псевдозаголовка :method записывается в самое начало результирующего запроса HTTP/1. Если сервер позволяет вам включать пробелы в значение :method, вы можете внедрить совершенно иную строку запроса, как показано ниже:
Front-end (HTTP/2)
:method
GET /admin HTTP/1.1
:path
/anything
:authority
vulnerable-website.com
Back-end (HTTP/1)
Пока сервер терпимо относится к произвольным завершающим символам в строке запроса, это даёт ещё один способ создать запрос с неоднозначным путём.
Внедрение префикса URL
Ещё одна интересная особенность HTTP/2 — возможность явно задавать схему в самом запросе с помощью псевдозаголовка :scheme. Хотя обычно он содержит лишь http или https, вы можете попытаться включить произвольные значения.
Это может быть полезно, когда сервер, например, использует :scheme для динамической генерации URL. В этом случае вы можете добавить префикс к URL или даже полностью его переопределить, вписав настоящий URL в строку запроса:
Request
:method
GET
:path
/anything
:authority
vulnerable-website.com
:scheme
https://evil-user.net/poison?
Response
:status
301
location
https://evil-user.net/poison?://vulnerable-website.com/anything/
Вставка перевода строки в псевдозаголовки
При внедрении в псевдозаголовки :path или :method необходимо убедиться, что результирующий запрос HTTP/1 по-прежнему имеет корректную строку запроса.
Поскольку в HTTP/1 последовательность \r\n завершает строку запроса, простое добавление \r\n посередине просто сломает запрос. После понижения переписанный запрос должен содержать следующую последовательность до первой вставленной вами \r\n:
Просто визуализируйте, где именно ваша вставка попадает в эту последовательность, и включайте все оставшиеся части соответствующим образом. Например, при внедрении в :path вам нужно добавить пробел и HTTP/1.1 перед \r\n, как показано ниже:
Front-end (HTTP/2)
:method
GET
:path
:authority
vulnerable-website.com
Back-end (HTTP/1)
Обратите внимание, что в данном случае мы также добавили произвольный хвостовой заголовок, чтобы подхватить пробел и протокол, которые были автоматически добавлены при переписывании.
Last updated