Статья Эксплуатация HTTP header injection через response queue poisoning

1689365415678.png

Это перевод

Введение

Инъекция в HTTP-header часто недооценивается и ошибочно классифицируется как средняя уязвимость, на уровне XSS или, что еще хуже, Open Redirection. В этой статье автор расскажет о простой технике, с помощью которой ему удалось использовать уязвимость, связанную с инъекцией в HTTP-header, сделать ее критической и получить вознаграждение в размере 12.500 долларов США.
Эта техника применима как к инъекции HTTP-header на front-end-серверах, так и на back-end-серверах.

С чего всё началось

Все началось с того, что один человек неожиданно прислал мне письмо с информацией об инъекции в заголовке запроса, основанной на пути, и спросил, есть ли у меня идеи по ее использованию. Уязвимость находилась на крупном сайте с высокой посещаемостью, обслуживающем критически важную функциональность, который мы будем называть "redacted.net":

Код:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0a%0d%0a HTTP/1.1
Host: redacted.net

HTTP/1.1 200 OK

GET /%20HTTP/1.1%0d%0anothost:%20redacted.net%0d%0a%0d%0a HTTP/1.1
Host: redacted.net

HTTP/1.1 400 Bad Request
Обычно я не занимаюсь подобными письмами, так как обычно багхантер попадает в затруднительное положение из-за того, что уязвимость действительно не может быть использована, и у меня нет никаких приемов, чтобы помочь. Однако , что уязвимости инъекции заголовка можно переделать в request smuggling. Кроме того, целевой сайт находился под программой bug bounty, которая известна своими конкурентными выплатами, и автор отчета - - согласился на разделение вознаграждения 50/50, если я смогу помочь.

Преобразование инъекции заголовка в HTTP request smuggling

Концепция проста - с помощью нескольких простых шагов можно преобразовать инъекцию заголовка запроса в более серьезный HTTP-desync.
Во-первых, определите, где происходит инъекция, и добавьте все необходимое для чистого выхода из контекста:

Код:
GET /%20HTTP/1.1%0d%0a%0d%0a HTTP/1.1

HTTP/1.1 400 Bad Request
Connection: close
Затем добавьте необходимые заголовки, чтобы гарантировать, что внутренняя система сохранит соединение открытым после ответа на первоначальный запрос:

Код:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0a HTTP/1.1

HTTP/1.1 200 OK
Connection: keep-alive
В этот момент мы можем указать второй запрос, полностью контролируемый нами, так что мы готовы к классической атаке request smuggling. Единственное существенное отличие заключается в том, что нам нужно будет учесть, что сервер добавит дополнительные заголовки/тело после нашей инъекции. Вот два из множества вариантов межпользовательской эксплуатации.

Указание вредоносного префикса для отравления, либо запроса следующего пользователя, либо веб-кэша:

Код:
GET /%20HTTP/1.1%0d%0aHost:%20redacted.net%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/redirplz%20HTTP/1.1%0d%0aHost:%20oastify.com%0d%0a%0d%0aContent-Length:%2050%0d%0a%0d%0a HTTP/1.1

Или создать префикс, который, объединившись с остальным мусором, создаст полноценный второй запрос, чтобы вызвать response queue poisoning.
Я выбрал последний вариант, что привело к тому, что я периодически получал ответы, предназначенные для других аутентифицированных пользователей. У меня есть прекрасный скриншот, показывающий это, но, к сожалению, я не смог получить разрешение назвать цель.
Этого оказалось достаточно, чтобы доказать критичность проблемы для компании, которая исправила ее менее чем за 24 часа и выплатила вознаграждение в размере $12 500.
Если у вас возникнут проблемы с применением этой техники, вам могут быть полезны эти два близких по тематике материала:

Header Injection ответа сервера и проблема stacked-response

Как мы уже видели, превратить инъекцию заголовков запросов в десинхронизацию довольно просто. Иногда модернизация инъекции заголовков ответов происходит так же просто. Однако в других случаях она загадочным образом не работает. Недавно я обнаружил защитный механизм, который, как мне кажется, объясняет это и намекает на возможное решение.
Когда веб-браузеры считывают ответ, если они встречают больше данных, чем сервер обещал в заголовке Content-Length, они усекают ответ и закрывают соединение. Я назвал эту проблему проблемой "сложенных ответов" и обнаружил, что она усложняет, но не делает невозможным использование уязвимости Client-Side Desync.
Теперь я подозреваю, что некоторые крупные внешние серверы имеют аналогичный механизм, что имеет два последствия для безопасности:
Обычные атаки на десинхронизацию не затрагиваются, но response-queue poisoning уменьшается
Трудно преобразовать инъекцию заголовка ответа в HTTP desync.
Если ваши попытки вызвать десинхронизацию с помощью инъекции заголовка ответа не увенчались успехом, возможно, вы столкнулись с этим механизмом. Чтобы обойти его, необходимо задержать инжектированный ответ так, чтобы его не увидело front-end's over-read.
Одним из возможных подходов к решению этой проблемы является введение большого количества новых строк, которые обычно обрабатываются серверами без запуска процесса обработки запроса/ответа.
В конечном счете, этот аспект требует дальнейших исследований. Если вы столкнетесь с этой проблемой в рамках программы "bug bounty" и застрянете, я буду рад, если смогу помочь. Следует также отметить, что если сайт, на котором вы обнаружили инъекцию заголовка, не имеет front-end, то эти методы не будут работать как таковые, но, возможно, вам удастся добиться десинхронизации на стороне клиента.

Заключение

Я подозреваю, что эти техники были известны, но были забыты вместе с HTTP Request Smuggling, что объясняет, почему некоторые люди называют инъекции в заголовки ответа "response splitting", хотя на самом деле они никогда не разделяют ответ. Для более глубокого изучения феномена забытых знаний в области безопасности обратитесь к статье .
Надеюсь, эти методы окажутся для вас полезными, и комьюнити будет радо услышать, если вы добьетесь успеха в их применении.
 
Последнее редактирование модератором:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!