Как выявлять и эксплуатировать уязвимости HTTP заголовка Host
В этом разделе мы подробнее рассмотрим, как определить, уязвим ли веб-сайт к атакам через заголовок HTTP Host. Затем мы приведём примеры того, как можно эксплуатировать такие уязвимости, а также несколько интерактивных лабораторных заданий для практики на заведомо уязвимом сайте.
Как тестировать уязвимости с помощью заголовка HTTP Host
Чтобы проверить, уязвим ли сайт к атаке через заголовок HTTP Host, вам понадобится перехватывающий прокси, такой как Burp Proxy, и инструменты ручного тестирования вроде Burp Repeater и Burp Intruder.
Коротко: вам нужно понять, можете ли вы изменить заголовок Host и при этом всё ещё достичь целевого приложения своим запросом. Если да, вы можете использовать этот заголовок для зондирования приложения и наблюдать, как это влияет на ответ.
Передайте произвольный заголовок Host
При зондировании уязвимостей внедрения через заголовок Host (Host header injection) первым шагом проверьте, что произойдёт, если вы укажете произвольное, нераспознанное доменное имя в заголовке Host.
Некоторые перехватывающие прокси получают целевой IP-адрес напрямую из заголовка Host, что практически делает подобное тестирование невозможным: любые изменения этого заголовка приведут к отправке запроса на совершенно другой IP-адрес. Однако Burp Suite корректно разделяет заголовок Host и целевой IP-адрес. Это разделение позволяет передавать любой произвольный или некорректно сформированный заголовок Host, при этом гарантируя, что запрос отправится на нужную цель.
Иногда вы всё равно сможете получить доступ к целевому сайту, даже если передадите неожиданный заголовок Host. Причин может быть несколько. Например, серверы иногда настроены с вариантом по умолчанию (fallback) на случай получения запросов к незнакомым доменным именам. Если вашим целевым сайтом оказывается значение по умолчанию — вам повезло. В этом случае можно начать изучать, что приложение делает с заголовком Host и подлежит ли такое поведение эксплуатации.
С другой стороны, поскольку заголовок Host — фундаментальная часть работы веб-сайтов, его подмена часто приводит к невозможности достичь целевого приложения. Фронтенд-сервер или балансировщик нагрузки, получив ваш запрос, может просто не знать, куда его переслать, что приведёт к ошибке вида Invalid Host header. Это особенно вероятно, если доступ к вашей цели осуществляется через CDN. В этом случае переходите к техникам, описанным ниже.
Проверьте некорректную валидацию
Вместо ответа Invalid Host header ваш запрос может быть заблокирован какой-то защитной мерой. Например, некоторые сайты валидируют соответствие заголовка Host значению SNI (индикация имени сервера, Server Name Indication, SNI) из рукопожатия TLS (протокол транспортного уровня безопасности). Это не обязательно означает, что они невосприимчивы к атакам через заголовок Host.
Постарайтесь понять, как сайт парсит заголовок Host. Иногда это раскрывает лазейки, позволяющие обойти валидацию. Например, некоторые алгоритмы парсинга опускают порт из заголовка Host, значит валидируется только доменное имя. Если вы также можете указать нечисловой порт, вы оставляете домен нетронутым (чтобы достичь целевого приложения), одновременно потенциально внедряя полезную нагрузку через порт.
GET /example HTTP/1.1
Host: vulnerable-website.com:bad-stuff-hereДругие сайты пытаются применять логику сопоставления для поддержки произвольных поддоменов. В этом случае вы можете полностью обойти валидацию, зарегистрировав произвольный домен, оканчивающийся той же последовательностью символов, что и домен из белого списка:
Либо можно воспользоваться менее защищённым поддоменом, который вам уже удалось скомпрометировать:
Для дополнительных примеров распространённых ошибок валидации доменов ознакомьтесь с материалами по (SSRF) Подделка запросов на стороне сервера и Уязвимости CORS
Отправляйте неоднозначные запросы
Код, валидирующий хост, и код, делающий с ним что-то уязвимое, часто находятся в разных компонентах приложения или даже на отдельных серверах. Идентифицируя и эксплуатируя расхождения в способах получения заголовка Host, вы можете сформировать неоднозначный запрос, который будет «выглядеть» как запрос к разным хостам в зависимости от того, какая система его рассматривает.
Ниже — лишь несколько примеров того, как можно сформировать неоднозначные запросы.
Внедряйте дубликаты заголовка Host
Один из подходов — попробовать добавить дублирующиеся заголовки Host. Часто это просто приведёт к блокировке запроса. Однако, поскольку браузер вряд ли когда-либо отправит такой запрос, разработчики могут не предусмотреть этот сценарий. В этом случае вы иногда обнаружите любопытные поведенческие особенности.
Разные системы и технологии обрабатывают этот случай по-разному, но часто приоритет отдаётся одному из двух заголовков, фактически переопределяя значение другого. Когда системы не согласны в том, какой заголовок «правильный», могут возникать расхождения, которые вы сможете эксплуатировать. Рассмотрим запрос:
Допустим, фронтенд отдаёт приоритет первому экземпляру заголовка, а бэкенд — последнему. В этом случае вы можете использовать первый заголовок для маршрутизации запроса к нужной цели, а второй — для передачи полезной нагрузки в серверный код.
Передавайте абсолютный URL
Хотя стартовая строка запроса обычно содержит относительный путь на запрошенном домене, многие серверы также понимают запросы с абсолютными URL.
Неоднозначность, вызванная одновременной передачей абсолютного URL и заголовка Host, тоже может приводить к расхождениям между системами. Формально при маршрутизации приоритет должна иметь стартовая строка, но на практике это соблюдается не всегда. Такие расхождения можно использовать схожим образом с кейсом дублирующихся заголовков Host.
Учтите, что иногда нужно поэкспериментировать с разными протоколами. Серверы могут вести себя по-разному в зависимости от того, содержит ли стартовая строка HTTP- или HTTPS-URL.
Добавляйте переносы строк
Необычное поведение можно обнаружить, делая отступ пробелом перед HTTP-заголовками. Некоторые серверы интерпретируют такой «сдвинутый» заголовок как перенос строки и, следовательно, рассматривают его как часть значения предыдущего заголовка. Другие серверы полностью игнорируют заголовок с отступом.
Из-за крайне непоследовательной обработки этого случая часто возникают расхождения между системами, которые обрабатывают ваш запрос. Например:
Сайт может блокировать запросы с несколькими заголовками Host, но вы можете обойти эту проверку, сделав отступ у одного из них. Если фронтенд проигнорирует заголовок с отступом, запрос будет обработан как обычный запрос к vulnerable-website.com. Теперь предположим, что бэкенд игнорирует ведущий пробел и в случае дубликатов отдаёт приоритет первому заголовку. Такое расхождение может позволить передавать произвольные значения через «перенесённый» заголовок Host.
Другие техники
Это лишь малая часть способов сформировать вредоносные, неоднозначные запросы. Например, многие техники контрабанды HTTP-запросов можно адаптировать для построения атак через заголовок Host. Мы подробнее рассмотрим это в отдельной теме о контрабанде запросов.
Внедряйте заголовки переопределения Host
Даже если вы не можете переопределить заголовок Host с помощью неоднозначного запроса, есть другие возможности изменить его значение, оставив сам заголовок нетронутым. В частности, можно внедрить полезную нагрузку через один из нескольких других HTTP-заголовков, которые предназначены именно для этой цели (хотя и для более безобидных сценариев).
Как уже обсуждалось, доступ к сайтам часто осуществляется через какой-то промежуточный компонент — балансировщик нагрузки или реверс-прокси. В такой архитектуре заголовок Host, который получает бэкенд-сервер, может содержать доменное имя одного из этих промежуточных узлов. Обычно это не имеет отношения к запрашиваемой функциональности.
Чтобы решить проблему, фронтенд может добавлять заголовок X-Forwarded-Host, содержащий исходное значение заголовка Host из первоначального клиентского запроса. По этой причине, когда присутствует заголовок X-Forwarded-Host, многие фреймворки обращаются именно к нему. Вы можете наблюдать такое поведение даже при отсутствии фронтенда, который бы добавлял этот заголовок.
Иногда X-Forwarded-Host можно использовать для внедрения вредоносного ввода с обходом любой валидации, применяемой к самому заголовку Host.
Хотя X-Forwarded-Host де-факто является стандартом для такого поведения, вы можете встретить и другие заголовки со схожим назначением, включая:
X-HostX-Forwarded-ServerX-HTTP-Host-OverrideForwarded
С точки зрения безопасности важно, что некоторые сайты (возможно, даже ваш) поддерживают такое поведение непреднамеренно. Обычно это происходит потому, что один или несколько из этих заголовков включены по умолчанию в сторонней технологии, которую они используют.
Как эксплуатировать заголовок HTTP Host
Определив, что вы можете передавать произвольные имена хостов целевому приложению, можно искать способы эксплуатации.
В этом разделе мы приведём примеры распространённых атак через заголовок HTTP Host, которые вы можете построить. Мы также создали несколько заведомо уязвимых сайтов, чтобы вы увидели, как работают эти эксплойты, и смогли закрепить материал на практике. Мы рассмотрим следующие примеры:
Отравление сброса пароля
Иногда злоумышленники могут использовать заголовок Host для атак отравления сброса пароля.
Отравление веб-кэша через заголовок Host
При зондировании потенциальных атак через заголовок Host вы часто наткнётесь на поведение, которое выглядит уязвимым, но напрямую не эксплуатируется. Например, вы можете обнаружить, что заголовок Host отражается в разметке ответа без HTML-кодирования или даже используется прямо в импортируемых скриптах. Отражённые уязвимости на стороне клиента, такие как XSS (межсайтовый скриптинг), обычно неэксплуатируемы, когда вызваны заголовком 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 (внедрение внешних сущностей XML) или уязвимой бизнес-логике, которая отправляет 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.
Last updated