June 14

Анализ SSL/TLS сертификатов: Certificate Transparency logs, выявление скрытых хостов

Анализ SSL/TLS сертификатов: Certificate Transparency logs, выявление скрытых хостов

Введение

SSL/TLS сертификаты — это цифровые удостоверения, которые обеспечивают шифрование соединений и подтверждают подлинность веб-сайтов. В контексте технического OSINT сертификаты становятся золотоносной жилой: они часто содержат имена доменов и поддоменов, которые не видны в DNS, а также могут раскрывать внутренние и тестовые хосты организации. Благодаря механизму Certificate Transparency (CT), каждый выданный сертификат публикуется в публичных логах, доступных для поиска. Данная статья посвящена методам анализа сертификатов, использованию CT-логов и выявлению скрытых активов.

Что такое Certificate Transparency (CT)?

CT — это открытая система аудита сертификатов, созданная для обнаружения ошибочных или злонамеренно выданных сертификатов. Когда центр сертификации (CA) выпускает сертификат, он обязан отправить его в несколько публичных CT-логов. Логи неизменяемы и доступны для всех. Благодаря этому любой исследователь может найти все сертификаты, выданные для домена (или любого шаблона), включая сертификаты для внутренних поддоменов, которые никогда не публиковались в DNS.

Почему сертификаты ценны для OSINT?

Основные источники CT-логов

Этап 1: Базовый поиск сертификатов через crt.sh

crt.sh (https://crt.sh) — это общедоступный интерфейс к CT-логам. Проще всего начать с запроса:

https://crt.sh/?q=%.example.com

где % заменяет любой префикс. Этот запрос найдёт все сертификаты, содержащие строку example.com в любом поле (name_value).

Параметры crt.sh:

  • q — поисковый запрос (можно использовать SQL-подобные операторы).
  • excluded — исключить мёртвые сертификаты (expired, revoked).
  • output — формат вывода (json, csv, html).
  • limit — количество результатов (по умолчанию 2000).

Примеры запросов:

  • ?q=example.com — ищет точное совпадение в любом поле.
  • ?q=%.example.com — ищет все поддомены.
  • ?q=*.example.com — ищет wildcard-сертификаты.
  • ?q=example.com&excluded=expired — исключить истекшие.

Использование API crt.sh (JSON):

https://crt.sh/?q=%.example.com&output=json

Python-функция для получения сертификатов:

import requests
import json

def get_certificates(domain, exclude_expired=True):
    url = f"https://crt.sh/?q=%25.{domain}&output=json"
    if exclude_expired:
        url += "&excluded=expired"
    resp = requests.get(url)
    if resp.status_code == 200:
        try:
            data = resp.json()
            # crt.sh возвращает список списков, каждый подсписок — запись
            # Поля: idx, name, issuer, validity_start, validity_end, ca, cert
            certs = []
            for row in data:
                cert = {
                    'name': row[1],
                    'issuer': row[2],
                    'valid_from': row[3],
                    'valid_to': row[4],
                    'ca': row[5],
                    'certificate': row[6]
                }
                certs.append(cert)
            return certs
        except:
            return []
    return []

certs = get_certificates("example.com")
for c in certs:
    print(c['name'], c['valid_to'])

Этап 2: Извлечение доменов из Subject Alternative Names (SAN)

Большинство современных сертификатов используют расширение SAN (Subject Alternative Names), которое содержит список всех имён, для которых действителен сертификат. Это наиболее ценный источник поддоменов.

Пример записи SAN из crt.sh:

name_value: example.com
           www.example.com
           mail.example.com
           admin.example.com
           *.example.com

Обратите внимание, что *.example.com — wildcard-сертификат, который покрывает все поддомены первого уровня. Однако с 2023 года некоторые CA начали ограничивать выдачу wildcard-сертификатов.

Как извлечь все уникальные имена из набора сертификатов:

def extract_domains(certificates):
    domains = set()
    for cert in certificates:
        names = cert['name'].split('\n')  # часто имена разделены \n
        for name in names:
            name = name.strip().lower()
            if name and not name.startswith('*.'):
                domains.add(name)
            elif name.startswith('*.'):  # wildcard
                domains.add(name[2:])    # добавляем зону, но с пометкой
    return sorted(domains)

Этап 3: Поиск по части имени (через SQL-запросы crt.sh)

crt.sh поддерживает прямые SQL-запросы (язык PostgreSQL). Это позволяет делать сложные поиски, например:

https://crt.sh/?q=SELECT name_value FROM certificate_identity WHERE name_value LIKE '%.example.com%' AND name_value NOT LIKE '%.%.%'

Этот запрос найдёт только поддомены первого уровня (без точек в средней части).

Полезные SQL-шаблоны:

  • Все сертификаты, выданные определённым CA: q=SELECT * FROM certificate WHERE issuer LIKE '%Let%27s Encrypt%'
  • Сертификаты, истекающие в ближайшие 30 дней: q=SELECT name_value, not_after FROM certificate WHERE not_after < NOW() + interval '30 days' AND name_value LIKE '%.example.com'

Этап 4: Выявление скрытых хостов через сертификаты

Скрытые хосты — это внутренние или тестовые поддомены, которые не разрешаются в DNS публично, но для них был выпущен сертификат (например, dev-db.internal.example.com). Такой сертификат будет в CT-логах, даже если DNS-запрос к dev-db.internal.example.com не вернёт IP.

Почему это возможно?

  • Сертификат мог быть выпущен до того, как поддомен был удалён из DNS.
  • Внутренние серверы могут иметь сертификаты для своих внутренних имён, но по ошибке они стали публичными.
  • Некоторые организации используют общие сертификаты для многих внутренних серверов, и эти сертификаты попадают в CT.

Как найти такие хосты:

  1. Выполните поиск %.example.com в crt.sh.
  2. Извлеките все имена.
  3. Для каждого имени выполните DNS-запрос A/AAAA. Если запрос не возвращает IP, но имя выглядит правдоподобно — это скрытый хост.
  4. Проверьте IP через Shodan/Censys — возможно, сертификат был выдан для IP-адреса, который сейчас неактивен.

Python-скрипт для обнаружения скрытых хостов:

import dns.resolver
import requests

def check_dns(domain):
    try:
        answers = dns.resolver.resolve(domain, 'A')
        return [str(r) for r in answers]
    except:
        return []

# Получить все имена из сертификатов
certs = get_certificates("example.com")
domains = extract_domains(certs)

hidden = []
for domain in domains:
    ips = check_dns(domain)
    if not ips:
        print(f"Скрытый хост (не резолвится): {domain}")
        hidden.append(domain)
    else:
        print(f"{domain} -> {ips}")

print(f"Найдено скрытых хостов: {len(hidden)}")

Этап 5: Анализ времени действия сертификата

Дата истечения сертификата может указывать на то, насколько активно используется хост. Сертификаты, которые истекают, обычно обновляются, если хост жив. Если сертификат истёк давно, а новых нет — хост, вероятно, выведен из эксплуатации.

Применение:

  • Найти старые сертификаты для old-site.example.com, чтобы восстановить историю.
  • Определить закономерности обновления сертификатов (например, каждые 90 дней — Let's Encrypt).
  • Обнаружить сертификаты с очень длинным сроком действия (могут быть самоподписными или тестовыми).

Этап 6: Поиск сертификатов по серийному номеру

Если у вас есть серийный номер сертификата (например, из утечки файла), можно найти его в CT-логах и получить связанные домены.

Поиск в crt.sh по серийному номеру:

https://crt.sh/?q=serial_number_string

Серийные номера обычно шестнадцатеричные. Этот метод полезен, если вы нашли сертификат на сервере (через OpenSSL) и хотите узнать, какие ещё домены есть в том же сертификате.

Этап 7: Интеграция с Shodan/Censys для поиска по хэшу сертификата

Shodan и Censys позволяют искать устройства по хэшу сертификата (SHA1 или SHA256). Это позволяет найти все серверы в интернете, использующие тот же сертификат (или тот же ключ).

Shodan фильтр ssl.cert.sha256:

ssl.cert.sha256:5f5a5f5a5f5a5f5a5f5a5f5a5f5a5f5a5f5a5f5a

Так можно обнаружить все серверы организации, использующие единый сертификат.

Censys аналогично:

services.tls.certificate.leaf_fingerprint_sha256: <hash>

Этап 8: Мониторинг новых сертификатов (CertSpotter)

CertSpotter (https://sslmate.com/certspotter/) — это сервис, который отслеживает CT-логи и уведомляет вас о появлении новых сертификатов для указанных доменов. Он особенно полезен для мониторинга инфраструктуры конкурентов или собственной.

Как использовать:

  • Бесплатный аккаунт позволяет добавить до 10 доменов.
  • При обнаружении нового сертификата приходит email.
  • Можно также использовать API для автоматической обработки.

Этап 9: Обнаружение сертификатов, связанных с организацией

Если вы знаете юридическое название организации (Organization field в сертификате), можно найти все сертификаты, выпущенные на это имя (даже если домены не связаны явно).

Поиск в crt.sh по организации:

https://crt.sh/?q=O%3DExample%20Inc

Пример: O=Google Trust Services найдёт сертификаты Google.

Осторожно: поле O не всегда заполняется, особенно для сертификатов Let's Encrypt (там только O=Let's Encrypt).

Практический пример: полное исследование компании через сертификаты

Задача: найти все домены, связанные с компанией acme.com, включая тестовые поддомены и внутренние хосты.

  1. crt.sh для %.acme.com → 120 сертификатов, 350 уникальных имён.
  2. Очистка: убрать дубликаты, домены, не заканчивающиеся на acme.com (убрать сторонние).
  3. DNS-проверка: 80 имён резолвятся в IP, 270 — нет (скрытые).
  4. Среди скрытых находим test.acme.com, staging.api.acme.com, jenkins.acme.com.
  5. Проверка Shodan для jenkins.acme.com (хотя IP не резолвится, возможно, сертификат есть на каком-то IP). Shodan: ssl.cert.subject.CN:jenkins.acme.com → находим IP 198.51.100.45 с открытым 8080.
  6. Анализ: Jenkins сервер доступен по IP, но не имеет DNS-записи. Уязвимость.
  7. Исторические сертификаты: старый сертификат old.acme.com истёк в 2022, но в логах есть. Его IP 203.0.113.88 уже не доступен.
  8. Вывод: обнаружены забытые, но активные серверы, требующие внимания.

Автоматизация мониторинга через crt.sh API

import requests
import time
import hashlib

def monitor_new_certs(domain, last_check_file):
    # загружаем последний известный хэш
    try:
        with open(last_check_file, 'r') as f:
            last_hash = f.read().strip()
    except:
        last_hash = ''
    
    url = f"https://crt.sh/?q=%25.{domain}&output=json"
    resp = requests.get(url)
    if resp.status_code == 200:
        data = resp.json()
        # вычисляем хэш от всего содержимого (как дешёвый способ детектировать изменения)
        content_str = json.dumps(data)
        new_hash = hashlib.sha256(content_str.encode()).hexdigest()
        if new_hash != last_hash:
            print(f"Обнаружены новые сертификаты для {domain}")
            # здесь можно отправить уведомление
            with open(last_check_file, 'w') as f:
                f.write(new_hash)
        else:
            print("Нет изменений")

  • Данные CT-логов публичны. Их сбор полностью легален.
  • Не пытайтесь получить информацию о сертификатах, используя уязвимости (это не требуется — всё открыто).
  • Даже если вы нашли внутренний поддомен, не пытайтесь взломать его без разрешения владельца. Используйте информацию только для защиты или информирования организации.

Анализ SSL/TLS сертификатов через CT-логи — один из самых мощных методов пассивного технического OSINT. Позволяет обнаруживать поддомены, которые не видны в DNS, включая тестовые, внутренние и исторические хосты. Основные инструменты — crt.sh, CertSpotter, Censys. Комбинация извлечения доменов из сертификатов, проверки DNS-резолвинга и дальнейшего сканирования (Shodan) позволяет выявить скрытую инфраструктуру организации.