Поддомен угнали через забытую запись DNS: разбор
На promo.example.com вдруг открывается не заброшенная лендинг-страница, а чужой контент — иногда безобидная заглушка, иногда фишинговая форма с логотипом компании. DNS никто не менял, сертификат для основного домена в порядке, а поддомен тем не менее принадлежит уже не вам. Разбираемся, как работает subdomain takeover — атака, которая не требует ни взлома сервера, ни кражи паролей, а использует ровно одну вашу ошибку: DNS-запись, оставленную указывать на сервис, от которого вы давно отказались.
Содержание
- Механика атаки: почему забытая CNAME-запись — это открытая дверь
- Какие внешние сервисы чаще всего оставляют такой след
- Как обнаружить «висячие» CNAME в своих DNS-записях
- Что видит и что может сделать атакующий, захватив поддомен
- Правило «удалять DNS-запись сразу при отказе от сервиса»
- Регулярный аудит всех DNS-записей: как выстроить процесс
Механика атаки: почему забытая CNAME-запись — это открытая дверь
Когда вы подключаете внешний сервис к поддомену — облачное хранилище для статики, конструктор лендингов, платформу для деплоя приложений, хелпдеск-портал, — типичная схема выглядит так: в DNS-зоне вашего домена создаётся CNAME-запись, указывающая на адрес, который выдал сам сервис, например promo.example.com CNAME random-id.cloudapp-provider.net. Дальше сервис на своей стороне видит входящий запрос с этим доменным именем и понимает, что должен отдавать контент именно вашего проекта — связка держится на том, что провайдер знает: random-id.cloudapp-provider.net привязан к вашему аккаунту.
Проблема начинается, когда вы отказываетесь от сервиса — переезжаете на другую платформу, удаляете проект, не продлеваете подписку. Ресурс на стороне провайдера освобождается: random-id.cloudapp-provider.net перестаёт быть привязан к кому бы то ни было и в некоторых архитектурах становится снова доступен для регистрации — теперь уже кем угодно. А вот CNAME-запись в вашей DNS-зоне остаётся: удалять её отдельным действием никто не считает нужным, ведь «сервис же отключили, чего ещё делать».
Дальше сценарий простой и не требует от атакующего никакой изощрённости:
- Атакующий сканирует поддомены интересующих доменов (это делается массово и автоматически — brute-force по словарю типичных имён поддоменов плюс данные из сертификатной прозрачности, Certificate Transparency logs, где видны все выданные когда-либо сертификаты для
*.example.com). - Для каждого найденного поддомена резолвится CNAME и проверяется, куда он указывает.
- Если целевой адрес отвечает признаками «ресурс не существует» (специфическая страница ошибки провайдера, статус 404 определённого вида, таймаут там, где обычно есть ответ) — это кандидат на захват.
- Атакующий регистрирует на своей стороне ресурс с тем же идентификатором, что стоит в вашей CNAME-записи, — через обычный, легальный процесс регистрации у того же провайдера.
- С этого момента провайдер начинает отвечать на запросы к
promo.example.comконтентом, который выложил атакующий, — потому что провайдер ориентируется на то, что написано в его собственной базе привязок, а не на то, кто владеет доменомexample.com.
Ключевой момент: сам домен example.com при этом никто не компрометирует — ни ваш DNS-провайдер, ни регистратор. Слабое звено — забытая ссылка на внешний ресурс, которым больше никто не управляет. Формально запись в зоне «правильная», она указывает туда же, куда и всегда, — но то, что на другом конце, поменяло владельца без вашего ведома.
Какие внешние сервисы чаще всего оставляют такой след
Уязвимой к сценарию делает не конкретный бренд, а архитектурный паттерн: сервис привязывает клиентские ресурсы к произвольным доменным именам через идентификатор, который после освобождения можно занять заново. Паттерн встречается в нескольких широких категориях:
- Хостинг статических сайтов и лендингов — конструкторы, где сайт публикуется по короткому проектному имени, а сверху вешается ваш CNAME.
- Платформы деплоя приложений (PaaS) — выдают поддомен вида
myapp.platform-host.net; после удаления приложения имя снова становится доступным для регистрации. - Объектные хранилища с публичным доступом — бакет с уникальным именем, к которому привязан CNAME для «красивого» URL; при удалении бакета имя не защищено от повторного создания кем-то ещё.
- Хелпдеск- и support-порталы, базы знаний — подключаются через поддомен вида
help.example.com, а после смены поставщика поддержки запись остаётся висеть. - CDN и edge-сервисы, особенно тестовые зоны, от которых отказались после пилота.
- Лендинги под рекламные кампании — поддомен создали под конкретную кампанию, кампанию свернули, поддомен никто не помнит.
Общий признак один: провайдер позволяет самостоятельно, без подтверждения владения доменом, «занять» присланное в запросе имя на своей стороне — это удобно для скорости подключения, и та же лёгкость работает в обратную сторону при отключении.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверКак обнаружить «висячие» CNAME в своих DNS-записях
Прежде чем что-то чинить, нужен полный список того, что вообще есть в зоне. Начните с выгрузки всех записей — если DNS управляется через панель хостинг-провайдера или регистратора, экспортируйте зону целиком; если это собственный сервер имён на PowerDNS или BIND, проще всего пройтись прямо по файлу зоны или через API:
# PowerDNS: выгрузить все записи зоны через API
curl -s -H "X-API-Key: $API_KEY" \
http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.com. \
| jq -r '.rrsets[] | select(.type=="CNAME") | .name'
Для BIND без API — просто просмотрите файл зоны и выпишите все строки с типом CNAME:
grep -i "CNAME" /etc/bind/zones/db.example.com
Дальше для каждого найденного поддомена нужно проверить, куда именно ведёт CNAME, и жив ли этот адрес:
# посмотреть, на что указывает CNAME
dig +short CNAME promo.example.com
# проверить, резолвится ли конечный адрес вообще
dig +short A random-id.cloudapp-provider.net
Здесь есть три характерных сценария:
- CNAME есть, но целевой адрес вообще не резолвится (
digвозвращает пусто) — самый явный признак «висячей» записи, убирать или переносить в первую очередь. - CNAME резолвится, но HTTP(S)-запрос отдаёт страницу с явным «сайт не найден», «проект не существует», «этот адрес свободен» — IP-адрес инфраструктуры провайдера жив (общий балансировщик на множество клиентов), но конкретно ваш идентификатор больше ничему не принадлежит:
curl -s https://promo.example.com/ | grep -i "not found\|no such\|doesn't exist\|available"
- CNAME резолвится и отдаёт нормальный контент — вероятно, всё в порядке, но стоит сверять его с ожиданием: если должен быть ваш лендинг, а отдаётся заглушка неизвестного проекта — это тоже сигнал, даже при ответе «200 OK».
Для проверки большого числа поддоменов вручную неудобно — практичнее собрать список CNAME-записей в текстовый файл и прогнать через простой скрипт:
#!/usr/bin/env bash
# check-dangling-cname.sh — грубая проверка списка CNAME-записей
while read -r sub target; do
ip=$(dig +short A "$target" | tail -1)
if [ -z "$ip" ]; then
echo "ПОДОЗРИТЕЛЬНО (не резолвится): $sub -> $target"
else
status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://$sub/")
echo "$sub -> $target ($ip), HTTP $status"
fi
done < cname-list.txt
Файл cname-list.txt — пары «поддомен / цель CNAME» построчно, полученные на предыдущем шаге. Скрипт не заменяет ручную проверку подозрительных случаев, но быстро отсекает явно живые записи от тех, куда стоит присмотреться внимательнее. Дополнительно стоит свериться с логами Certificate Transparency — они покажут все поддомены, для которых когда-либо выпускался TLS-сертификат, включая те, что не значатся ни в одном внутреннем документе, потому что их создавали разово под кампанию и забыли.
Что видит и что может сделать атакующий, захватив поддомен
Захват «висячего» поддомена — это не абстрактный риск, а рабочая точка входа для нескольких вполне конкретных сценариев вреда, и часть из них не требует от атакующего вообще ничего технически сложного дальше:
Фишинг с доверием к домену. Захваченный login.example.com выглядит для пользователя как легитимная часть сайта — совпадает домен верхнего уровня, часто есть валидный TLS-сертификат (провайдер сам выпускает сертификат для подключённого поддомена, значит будет и замок в адресной строке). Форма входа на такой странице соберёт реальные пароли пользователей, которые доверяют домену.
Кража сессионных cookie. Если у основного домена cookie настроены с областью .example.com, а не строго www.example.com, скрипт на захваченном поддомене может их прочитать — в зависимости от флагов Secure, HttpOnly и SameSite это может дать доступ к активным сессиям на основном сайте.
Обход политик безопасности контента. CSP-настройки и списки разрешённых источников в почтовых фильтрах и корпоративных прокси нередко доверяют всему *.example.com — захваченный поддомен автоматически наследует это доверие и может использоваться как площадка для загрузки вредоносных скриптов, формально «своих».
Репутационный и SEO-ущерб. Поисковые системы и антивирусные списки помечают заражённый поддомен как источник фишинга — это бьёт по репутации всего домена и требует отдельной работы по снятию блокировки после устранения проблемы.
Рассылка от имени домена. Если захваченный ресурс поддерживает отправку почты, а SPF-запись описана широко (include: на всю инфраструктуру провайдера без уточнения конкретного отправителя), это иногда открывает возможность рассылки писем, проходящих проверку SPF как «отправленные легитимно».
Не каждый захват даёт весь набор возможностей сразу — многое зависит от типа сервиса, настроек TLS и cookie, видимости поддомена пользователям. Но сама вероятность, что случайно найденная «висячая» запись окажется полезной атакующему, — не гипотетическая, а регулярно подтверждаемая практика.
Правило «удалять DNS-запись сразу при отказе от сервиса»
Единственная надёжная профилактика этой атаки — не техническая хитрость, а дисциплина: DNS-запись убирается в тот же момент, когда вы отказываетесь от внешнего сервиса, а не «когда-нибудь потом, если вспомним».
Практически это означает несколько привычек:
- Отключение сервиса и удаление DNS-записи — один тикет, а не два. Если в команде есть чек-лист на отключение внешней интеграции, пункт «удалить связанную DNS-запись» должен быть в нём же, а не отдельной задачей, которую легко потерять.
- Порядок действий: сначала удалить запись, потом отменять сервис. Между отменой подписки и фактическим освобождением ресурса у провайдера иногда есть зазор — если убрать CNAME до того, как ресурс освободится, окно для захвата вообще не появится.
- Не оставлять «на всякий случай». Соблазн оставить запись — вдруг вернёмся к сервису через месяц — стоит взвешивать против цены забытой уязвимой записи. Создать CNAME заново — секундное дело; вспомнить про забытую запись — куда менее вероятное событие.
- Документировать, зачем создана каждая запись. Комментарий в системе управления зоной или таблица «поддомен → сервис → ответственный → дата подключения» превращает поиск «а зачем это здесь» из археологии в справочную операцию.
- Учитывать поддомены, созданные не основной командой. Маркетинг подключает лендинг для кампании, продажи — демо-стенд у вендора, разработка — тестовое окружение у подрядчика. Такие поддомены создаются вне обычного процесса деплоя и потому легче всего забываются. Похожая логика забытого доступа, оставленного подрядчиком, разобрана в статье «Ключ подрядчика остался в authorized_keys» — механизм другой, причина та же: право или ресурс выдали разово, а отозвать забыли.
Регулярный аудит всех DNS-записей: как выстроить процесс
Дисциплина в моменте отключения сервиса снижает риск, но не устраняет его полностью — записи всё равно накапливаются годами, ответственные меняются, документация теряется. Поэтому вторая обязательная часть профилактики — периодическая ревизия всей зоны целиком, независимо от того, помните вы о конкретной записи или нет.
Периодичность. Для небольшого домена с редкими изменениями достаточно раз в квартал; для домена, где регулярно подключают и отключают маркетинговые кампании и тестовые окружения, — раз в месяц. Смысл не в частоте самой по себе, а в предсказуемо коротком окне между появлением «висячей» записи и её обнаружением.
Что входит в ревизию:
- Полная выгрузка зоны и список всех CNAME-записей.
- Проверка каждой на «висячесть» — резолвится ли цель, отвечает ли ожидаемым контентом.
- Сверка с внутренним реестром «поддомен → назначение»: если запись не находит объяснения ни у кого в команде, это повод для расследования, а не просто технической проверки.
- Проверка по логам Certificate Transparency на поддомены, не попавшие в основной DNS-экспорт (бывает при делегировании части зоны другому провайдеру).
- Фиксация результата — кто проверял, когда, что нашли, — чтобы следующая ревизия отталкивалась от известного состояния.
Такую проверку удобно встраивать в общий процесс аудита безопасности инфраструктуры — если в компании уже есть регулярное ревью доступов и конфигураций, ревизия DNS-зоны логично встаёт туда же отдельным пунктом; подход к подготовке такого аудита разобран в статье «Как подготовить сервер к аудиту безопасности». Скрипт вроде приведённого выше стоит повесить на cron с оповещением при обнаружении новой «висячей» записи — тогда ревизия не зависит от того, вспомнил ли кто-то её запустить. Похожий принцип — не полагаться на память, а держать автоматическую проверку состояния домена и сертификатов — описан в статье про мониторинг сертификатов и доменов.
Параллель с другими типами «забытого» в инфраструктуре прямая: открытый порт от неиспользуемого тестового сервиса — та же логика риска, только на уровне сети, а не DNS; разбор похожего инцидента — в статье «Сервер взломали через забытый порт». В обоих случаях проблема не в разовой ошибке, а в отсутствии процесса, который бы поймал её раньше, чем ею воспользовались.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обнаружить захват поддомена сразу после того, как он произошёл?
Напрямую нет — специального уведомления от DNS не бывает, ведь сама запись не меняется. Обнаружить можно регулярной проверкой (см. выше) либо косвенно — по жалобам пользователей, аномалиям в логах или мониторингу, который сравнивает ожидаемый и фактический контент страницы.
Достаточно ли просто удалить CNAME-запись, если нашли «висячую»?
Да, если сервис больше не нужен — удаление полностью закрывает вектор. Если сервис нужен, но проект на его стороне пересоздали, обновите CNAME на актуальный идентификатор.
Что делать, если поддомен уже захвачен и на нём чужой контент?
Сначала удалите или переадресуйте DNS-запись — это немедленно останавливает показ чужого контента. Затем проверьте логи веб-сервера или CDN на предмет объёма трафика и утечки данных пользователей, а также отзовите TLS-сертификат для поддомена, если он выпускался независимо.
Защищает ли от этой атаки DNSSEC?
Нет — DNSSEC подтверждает подлинность самой записи, но не проверяет, актуален ли объект, на который она указывает. Подписанная запись может «честно» вести на ресурс, который уже никому не принадлежит.
Опасны ли только CNAME-записи, или другие типы тоже?
Наиболее типичный вектор — CNAME на внешний сервис, но похожая логика применима к A-записям на эластичные IP облачных провайдеров и к делегированию NS на поддомен, если серверы имён тоже освободились.
Как быстро проверить один поддомен, если нет времени на полный аудит?
dig +short CNAME поддомен.example.com, затем dig +short A результат — если второй запрос ничего не вернул, присмотритесь внимательнее прямо сейчас.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →