CIOlogia Безопасность бизнеса · не на словах, а с доказательствами
← Все разборы Информационная безопасность

Забытый поддомен банка: как «мёртвая» DNS-запись чуть не увела пароли клиентов

Разбираем на пальцах и на командах, почему заброшенная страница промо-акции оказалась опаснее незакрытой уязвимости в интернет-банке — и как за пару дней закрыть подобную дыру у себя.

Разбор CIOlogia

Заказчик — небольшая региональная финансовая организация — попросил обычный аудит доступов: кто и куда ходит, отключены ли уволенные, стоит ли MFA на критичных системах. Штатная гигиена. Но, как обычно в таких проектах, первым шагом было не «смотреть на людей», а посмотреть на инфраструктуру снаружи — глазами атакующего. И там нашлась история совсем другого масштаба: класс атак, который в отрасли давно называют subdomain takeover, а конкретную волну инцидентов последних лет — Danglegeddon.

Суть проблемы: доменное имя без хозяина

Несколько лет назад под рекламную акцию сделали лендинг вида promo.bank-example.ru. Разместили его не на своей инфраструктуре, а на внешнем конструкторе сайтов — по CNAME. Акция закончилась, страницу отключили, а вот запись в DNS осталась висеть:

promo.bank-example.ru.  3600  IN  CNAME  clientname.builderservice.com.

Аренда имени clientname.builderservice.com на стороне конструктора истекла — и это имя стало свободным. Любой человек в интернете мог зарегистрировать его заново на том же сервисе. DNS-запись банка при этом продолжает честно указывать «сюда» — просто «сюда» теперь принадлежит не банку.

Как это эксплуатируется

Атака на dangling DNS почти никогда не требует эксплойтов в классическом смысле — это чистая разведка и терпение. Вот типичный путь атакующего.

1. Массовый сбор поддоменов

subfinder -d bank-example.ru -all -silent -o subs.txt
amass enum -passive -d bank-example.ru -o amass.txt
cat subs.txt amass.txt | sort -u > all_subs.txt
wc -l all_subs.txt
# 187 all_subs.txt

Источники — Certificate Transparency логи, пассивный DNS, поисковые движки. Полезно смотреть и историю выпуска сертификатов:

curl -s "https://crt.sh/?q=%25.bank-example.ru&output=json" | jq -r '.[].name_value' | sort -u

2. Разрешение записей и поиск «висячих» CNAME

dnsx -l all_subs.txt -cname -resp -o resolved.txt

promo.bank-example.ru [CNAME] [clientname.builderservice.com]
old-partners.bank-example.ru [CNAME] [bankexample.herokuapp.com]
test-crm.bank-example.ru [CNAME] [bankexample.blob.core.windows.net]

Дальше — фильтрация по сигнатурам известных «сиротских» сервисов (существуют публичные базы вроде can-i-take-over-xyz, содержащие паттерны ответов для GitHub Pages, Heroku, Azure, AWS S3, Shopify, Zendesk, Fastly и десятков других провайдеров):

httpx -l resolved.txt -status-code -title -mc 404 -silent

https://promo.bank-example.ru [404] [NXDOMAIN — No such app]

Ответ вроде No such app, There isn't a GitHub Pages site here или NoSuchBucket — классический индикатор: имя на другом конце свободно и его можно занять.

3. Захват имени на стороне провайдера

Атакующий просто регистрируется на том же конструкторе/хостинге и создаёт проект с ровно тем же алиасом, что был прописан в CNAME банка:

После регистрации на builderservice.com
создать сайт с адресом: clientname.builderservice.com
загрузить index.html — клон формы входа в интернет-банк

DNS-запись promo.bank-example.ru → clientname.builderservice.com банк не менял — она была не нужна и забыта. Через минуту-две после распространения DNS страница promo.bank-example.ru начинает открывать чужой контент — визуально неотличимый от официального сайта, потому что домен настоящий.

4. Автоматизация массового сканирования

В реальных атаках такие поиски не делаются вручную по одному банку — сканируют целые реестры доменов пачками, используя nuclei с шаблонами takeover:

nuclei -l all_subs.txt -t subdomain-takeover/ -severity high,critical

[subdomain-takeover:heroku] [http] [high] promo.bank-example.ru
[subdomain-takeover:github-pages] [http] [medium] old-blog.bank-example.ru

Это ровно тот же инструментарий, которым я пользовался при аудите — разница только в намерениях.

Что и почему сработало бы дальше

Захват поддомена сам по себе — не финал, а плацдарм. Дальше атака развивается предсказуемо:

  • TLS-сертификат без подозрений. Домен принадлежит банку по DNS, поэтому Let's Encrypt или любой другой CA выпустит валидный сертификат по HTTP-01/DNS-01 challenge — браузер покажет зелёный замок, а не предупреждение.
  • Фишинг с нулевым недоверием. Ссылку https://promo.bank-example.ru/login легко продвигать через рассылки, SMS, контекстную рекламу — антифрод-фильтры почтовых провайдеров реже блокируют легитимный домен второго уровня.
  • SEO- и репутационный захват. Старые ссылки на акцию из соцсетей, партнёрских сайтов, поисковой выдачи продолжают вести на этот адрес годами — трафик приходит бесплатно и без усилий атакующего.
  • Кража сессионных cookie. Если у банка выставлен широкий scope cookie (Domain=.bank-example.ru) для SSO между сервисами, скомпрометированный поддомен теоретически может читать/устанавливать cookie в общем домене — путь к перехвату сессии в основном интернет-банке.
  • Складирование учёток для credential stuffing. Даже если форма — просто копия логина без реального банкинга за ней, собранные пары логин/пароль масштабно проверяются на других сервисах и в самом интернет-банке через автоматизированные скрипты (или тот же hydra, если бы фронт банка допускал брутфорс без rate-limit).

Во сколько это могло обойтись

Даже осторожная оценка: 50 скомпрометированных счетов со средним остатком 300 тыс. рублей — это потенциальный отток вкладов на 15 млн рублей. Плюс расследование инцидента, уведомление регулятора, возможные штрафы за утечку персональных данных и, главное, репутационный урон — «банк, у которого воруют пароли», расходится за день, а доверие возвращается годами.

Как закрыть

Работа заняла пару дней и стоила несопоставимо меньше, чем компенсация одному пострадавшему клиенту.

  1. Полная инвентаризация DNS. Выгрузить зону целиком и сверить с реестром регистратора/DNS-провайдера:
    dig axfr bank-example.ru @ns1.registrar.ru
    # либо через API DNS-провайдера, если AXFR закрыт (правильно, что закрыт)
  2. Проверка живости каждого CNAME/A-адреса.
    for h in $(cat all_subs.txt); do
      echo -n "$h -> "; dig +short cname "$h"
    done | tee cname_map.txt
    
    httpx -l cname_map.txt -status-code -title -fc 200
  3. Удаление записей на мёртвые и истёкшие сервисы — просто снести из зоны всё, что указывает на закрытые проекты, а не оставлять «на всякий случай».
  4. Регламент жизненного цикла поддомена. Закрытие акции = обязательное удаление DNS-записи как часть чек-листа, а не «выключили сайт и забыли».
  5. Ограничение scope cookie и явная политика Same-Site/Domain, чтобы даже гипотетический захваченный поддомен не мог участвовать в SSO-схемах основного банкинга.
  6. CAA-запись, ограничивающая, какие удостоверяющие центры вправе выпускать сертификаты для домена — снижает риск «тихого» валидного TLS на захваченном поддомене:
    bank-example.ru. IN CAA 0 issue "letsencrypt.org"
    bank-example.ru. IN CAA 0 issuewild ";"
  7. Постоянный мониторинг вместо разового аудита. Еженедельный прогон subfinder/dnsx/nuclei с шаблонами takeover и алертом в мессенджер ответственному, плюс отслеживание новых сертификатов через Certificate Transparency (crt.sh, Cert Spotter API) — новый неожиданный поддомен виден в течение часов, а не лет.
Самые опасные дыры в защите — это не сложные взломы, а то, что компания сама забыла удалить за собой.

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