Поиск и эксплуатация уязвимостей заголовка Host

Как тестировать уязвимости заголовка Host

Чтобы проверить, уязвим ли сайт к атаке через заголовок Host, вам понадобится прокси, такой как Burp, и инструменты ручного тестирования вроде Burp Repeater и Burp Intruder.

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

Передайте произвольный заголовок Host

При тестировании Host header injection, первым шагом проверьте, что произойдёт, если вы укажете произвольное доменное имя в заголовке Host.

Некоторые прокси получают целевой IP-адрес напрямую из заголовка Host, что практически делает подобное тестирование невозможным: любые изменения этого заголовка приведут к отправке запроса на совершенно другой IP-адрес. Однако Burp Suite корректно разделяет заголовок Host и целевой IP-адрес. Это разделение позволяет передавать любой произвольный или некорректно сформированный заголовок Host, при этом гарантируя, что запрос отправится на нужную цель.

Tip

Целевой URL отображается либо в верхней части панели, либо на вкладке Target в Burp Intruder. Вы можете отредактировать цель вручную, нажав на значок карандаша.

Иногда вы всё равно сможете получить доступ к целевому сайту, даже если передадите неожиданный заголовок Host. Причин может быть несколько. Например, серверы иногда настроены с дефолтным вариантом на случай получения запросов к незнакомым доменам. Если вашим целевым сайтом оказывается значение по умолчанию — вам повезло. В этом случае можно начать изучать, что приложение делает с заголовком Host и подлежит ли такое поведение эксплуатации.

С другой стороны, поскольку заголовок Host — фундаментальная часть работы веб-сайтов, его подмена часто означает, что вы не сможете добраться до целевого приложения. Фронтенд-сервер или балансировщик нагрузки, получив ваш запрос, может просто не знать, куда его переслать, что приведёт к ошибке вида Invalid Host header. Это особенно вероятно, если доступ к вашей цели осуществляется через CDN. В этом случае переходите к техникам, описанным ниже.

Проверьте некорректную валидацию

Вместо ответа Invalid Host header ваш запрос может быть заблокирован какой-то защитной мерой. Например, некоторые сайты валидируют соответствие заголовка Host значению SNI из рукопожатия TLS. Но это не всегда значит, что они защищены от атак через заголовок Host.

Постарайтесь понять, как сайт обрабатывает заголовок Host. Иногда это позволяет выявить лазейки, позволяющие обойти валидацию. Например, некоторые алгоритмы обработки опускают порт из заголовка Host, значит проверяется только доменное имя. Если также можно указать нечисловой порт, вы можете оставить доменное имя без изменений, чтобы гарантированно достичь целевого приложения, при этом вводя полезную нагрузку через порт.

GET /example HTTP/1.1
Host: vulnerable-website.com:bad-stuff-here

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

Либо можно воспользоваться менее защищённым поддоменом, который вам уже удалось скомпрометировать:

Для дополнительных примеров распространённых ошибок валидации доменов ознакомьтесь с материалами по SSRF и Мисконфигурации CORS

Отправьте неоднозначные запросы

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

Ниже несколько примеров того, как можно сформировать неоднозначные запросы.

Внедряйте дубликаты заголовка Host

Можно попробовать добавить дублирующиеся заголовки Host. Часто это просто приведёт к блокировке запроса. Однако, поскольку браузер вряд ли когда-либо отправит такой запрос, разработчики могут не предусмотреть этот сценарий. В этом случае вы можете обнаружить любопытные особенности поведения.

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

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

Передавайте абсолютный URL

Хотя стартовая строка запроса обычно содержит относительный путь на запрошенном домене, многие серверы также понимают запросы с абсолютными URL.

Неоднозначность, вызванная одновременной передачей абсолютного URL и заголовка Host, тоже может приводить к расхождениям между системами. Формально при маршрутизации приоритет должна иметь стартовая строка, но на практике это соблюдается не всегда. Такие расхождения можно использовать также, как дублирующиеся заголовки Host.

Учтите, что иногда нужно поэкспериментировать с разными протоколами. Серверы могут вести себя по-разному в зависимости от того, содержит ли стартовая строка HTTP или HTTPS.

Добавляйте переносы строк

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

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

Сайт может блокировать запросы с несколькими заголовками Host, но вы можете обойти эту проверку, сделав отступ у одного из них. Если фронтенд проигнорирует заголовок с отступом, запрос будет обработан как обычный запрос к vulnerable-website.com. Теперь предположим, что бэкенд игнорирует ведущий пробел и в случае дубликатов отдаёт приоритет первому заголовку. Такое расхождение может позволить передавать произвольные значения через перенесённый заголовок Host.

Другие техники

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

Подробнее

HTTP request smuggling

Внедряйте заголовки переопределения Host

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

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

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

Иногда X-Forwarded-Host можно использовать для внедрения, обходя любую валидацию, применяемой к самому заголовку Host.

Хотя X-Forwarded-Host де-факто является стандартом для такого поведения, вы можете встретить и другие заголовки со схожим назначением, включая:

  • X-Host

  • X-Forwarded-Server

  • X-HTTP-Host-Override

  • Forwarded

Tip

В Burp Suite вы можете использовать функцию «Guess headers» расширения Param Miner, чтобы автоматически зондировать поддерживаемые заголовки с помощью его обширного встроенного списка слов.

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

Как эксплуатировать заголовок Host

Определив, что вы можете передавать произвольные имена хостов целевому приложению, можно искать способы эксплуатации.

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

Отравление сброса пароля

Иногда можно использовать заголовок Host для атак отравления сброса пароля.

Отравление веб-кэша через заголовок Host

При тестировании потенциальных атак через заголовок Host вы часто наткнётесь на поведение, которое выглядит уязвимым, но напрямую не эксплуатируется. Например, вы можете обнаружить, что заголовок Host отражается в разметке ответа без HTML-кодирования или даже используется прямо в импортируемых скриптах. Отражённые уязвимости на стороне клиента, такие как XSS, обычно неэксплуатируемы, когда вызваны заголовком Host. Нет пригодного способа заставить браузер жертвы отправить некорректный заголовок Host.

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

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

Отдельно стоящие кэши обычно включают заголовок Host в ключ кэша, поэтому подход чаще работает на интегрированных кэшах уровня приложения. Тем не менее, описанные выше техники иногда позволяют отравить даже самостоятельные веб-кэши.

Отравление веб-кэша подробно разобрано в отдельной теме.

Эксплуатация классических уязвимостей на стороне сервера

Любой HTTP-заголовок — это потенциальный вектор эксплуатации классических уязвимостей на стороне сервера, и заголовок Host не исключение. Например, попробуйте стандартные приёмы тестирования на SQL-инъекцию через заголовок Host. Если значение заголовка попадает в SQL-запрос, это может быть эксплуатируемо.

Доступ к ограниченной функциональности

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

Доступ к внутренним сайтам с помощью брутфорса виртуальных хостов

Иногда компании по ошибке размещают публично доступные сайты и приватные внутренние сайты на одном сервере. У серверов обычно есть и публичный, и приватный IP-адрес. Поскольку внутреннее имя хоста может резолвиться в приватный IP-адрес, такой сценарий не всегда можно обнаружить, просто посмотрев записи DNS:

В некоторых случаях у внутреннего сайта может не быть публичной DNS-записи вовсе. Тем не менее злоумышленник обычно может обратиться к любому виртуальному хосту на любом доступном ему сервере, если сможет угадать имена хостов. Если скрытое доменное имя обнаружено другими способами, его можно запросить напрямую. Иначе можно использовать инструменты вроде Burp Intruder для брутфорса виртуальных хостов с помощью простого списка поддоменов.

SSRF, основанная на маршрутизации

Иногда заголовок Host можно использовать для SSRF атак, основанных на маршрутизации. Их также называют «Host header SSRF» и они подробно изучены командой PortSwigger Research в работе Cracking the lens: targeting HTTP's hidden attack-surface.

Классические уязвимости SSRF обычно основаны на XXE или уязвимой бизнес-логике, которая отправляет HTTP-запросы к URL, полученному из контролируемого пользователем ввода. SSRF, основанная на маршрутизации, напротив, опирается на эксплуатацию промежуточных компонентов, распространённых в облачных архитектурах, включая внутренние балансировщики нагрузки и реверс-прокси.

Хотя эти компоненты развернуты с разными целями, по сути они принимают запросы и пересылают их на соответствующий бэкенд. Если они пересылыют запросы, основываясь на заголовке Host, не валидируя его, то можно заставить их маршрутизировать запросы на произвольную систему.

Такие системы — отличные цели. Они занимают привилегированную сетевую позицию: получают запросы напрямую из публичной сети и при этом имеют доступ ко многим, если не ко всем, ресурсам внутренней сети. Это делает заголовок Host мощным вектором SSRF атак, потенциально превращая простой балансировщик в шлюз ко всей внутренней сети. Вы можете использовать Burp Collaborator для идентификации таких уязвимостей. Если вы укажете домен своего сервера Collaborator в заголовке Host и затем получите DNS-запрос от целевого сервера или другого промежуточного узла, это указывает на возможность маршрутизации запросов к произвольным доменам.

Убедившись, что вы можете заставить промежуточный компонент маршрутизировать запросы на произвольный публичный сервер, следующий шаг — попытаться получить доступ к системам, доступным только изнутри. Для этого нужно определить приватные IP-адреса, используемые во внутренней сети цели. В дополнение к IP-адресам, раскрываемым самим приложением, вы можете сканировать имена хостов компании и проверять, не резолвятся ли некоторые из них в приватные IP-адреса. В крайнем случае вы всё равно можете определить валидные адреса, просто перебирая стандартные приватные диапазоны, например 192.168.0.0/16.

Нотация CIDR

Диапазоны IP-адресов обычно выражают в нотации CIDR, например, 192.168.0.0/16.

IPv4-адреса состоят из четырёх 8-битных десятичных значений — октетов, разделённых точками. Значение каждого октета — от 0 до 255, значит минимально возможный IPv4-адрес — 0.0.0.0, а максимальный — 255.255.255.255.

В нотации CIDR минимальный адрес диапазона записывается явно, после него указывается число бит, начиная с начала адреса, фиксированных для всего диапазона. Например, 10.0.0.0/8 означает, что первые 8 бит (первый октет) фиксированы. Иными словами, этот диапазон включает все IP-адреса от 10.0.0.0 до 10.255.255.255.

Атаки на состояние соединения

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

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

Многие реверс-прокси используют заголовок Host для маршрутизации запросов на правильный бэкенд. Если они предполагают, что все запросы по соединению предназначены тому же хосту, что и первичный запрос, это может дать полезный вектор для ряда атак через заголовок Host, включая SSRF, основанную на маршрутизации, отравление сброса пароля и отравление кэша.

SSRF через некорректную стартовую строку запроса

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

Например, реверс-прокси может взять путь из стартовой строки запроса, добавить префикс http://backend-server и направить запрос на этот URL. Это работает, если путь начинается с символа /, но что если он начинается с символа @?

Получившийся URL будет http://backend-server@private-intranet/example, который большинство HTTP-библиотек интерпретирует как запрос доступа к private-intranet с именем пользователя backend-server.

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

Эти техники также популяризировал Джеймс Кеттл. Более детальное описание техники, инструментов и того, как ему удалось эксплуатировать эти уязвимости в реальных условиях, см. в полном whitepaper и видеодокладе на странице Research.

Last updated