воскресенье, 15 июня 2025 г.

Критическая уязвимость на 90% сайтов: захват аккаунтов работает через подмену Unicode в email

⚠️ Что это за уязвимость?

Если у вас есть веб-сервер с регистрацией через email, вы можете быть уязвимы к атаке типа "Punny Code Account Takeover".

Суть угрозы: Хакеры могут захватить любой аккаунт на вашем сайте, используя визуально одинаковые, но технически разные символы Unicode в email-адресах. Атака возможна даже без взаимодействия пользователя (0-click), если система автоматически отправляет письма для сброса пароля.

📚 Подробные материалы об уязвимости:


🔍 Как работает атака?

Шаг 1: Хакер находит жертву

Злоумышленник выбирает целевой аккаунт: admin@company.com

Шаг 2: Создание визуального двойника

Хакер создает похожий email с гомографами (визуально одинаковыми символами из разных алфавитов и разными UNICODE):

  • Оригинал: admin@company.com (латинские буквы)
  • Подделка: аdmin@company.com (первая буква "а" — кириллическая) 
Эти email выглядят абсолютно одинаково: admin@company.com

Шаг 3: Эксплуатация уязвимости системы

Проблема в том, что разные компоненты по-разному обрабатывают Unicode:

  1. База данных (MySQL) приводит кириллическую "а" к латинской "a"
  2. SMTP-сервер различает эти символы как разные
Можно подделывать как имена пользователей в общедоступной почте, так и сам домен.

Шаг 4: Захват аккаунта

  1. Хакер запрашивает "восстановление пароля" для аккаунта похожего на аdmin@company.com (специально создает такой поддельный email)
  2. Система проверяет в БД: находит в базе сайте аккаунт для admin@company.com (считает символы одинаковыми)
  3. Почтовый сервер отправляет письмо: на поддельный аккаунт аdmin@company.com (где кириллическая "а")
  4. Хакер получает письмо на специально созданный email с ссылкой для сброса пароля от чужого аккаунта!


Атака работает не только для email, но и для OAuth/OIDC-провайдеров (GitLab, Google и др.), если email-идентификаторы не валидируются и не нормализуются одинаково.

Гомографы часто  встречаются, можно привести еще несколько примеров:
  • Греческие буквы (например, υ вместо u).

  • Другие Unicode-символы, которые выглядят похоже на латинские (например, 𝗍 — математический символ вместо t


🧪 Как проверить свой сервер на уязвимость?

Простой тест (5 минут):

Шаг 1: Создайте тестовый аккаунт

Зарегистрируйтесь с обычным email: test@yourdomain.com. Для проверки не требуется покупать домены или настраивать почтовые серверы — используйте Burp Collaborator или аналогичные сервисы для перехвата писем.

Шаг 2: Попробуйте гомографы

Через Burp Suite перехватите запрос регистрации и подмените email на вариант с гомографом (например, кириллическая "а"). Скопируйте и вставьте эти символы для создания второго email:

Кириллические буквы (выглядят как латинские):
а (вместо a) - U+0430
е (вместо e) - U+0435  
о (вместо o) - U+043E
р (вместо p) - U+0440
с (вместо c) - U+0441
у (вместо y) - U+0443
х (вместо x) - U+0445

Попробуйте: tеst@yourdomain.com (кириллическая "е")

Шаг 3: Анализ результата

  • Если система говорит "Email уже занят"  🚨 УЯЗВИМОСТЬ НАЙДЕНА!
  • Если позволяет зарегистрироваться — возможно, система защищена

Шаг 4: Проверка восстановления пароля

  • Запросите "забыл пароль" для email с гомографом (тут потребуется трюк из видео с подменой символов в Burp).
  • Если получили письмо — критическая уязвимость подтверждена.

Шаг 5:

  • Войдите с оригинальным email и новым паролем — если вход успешен, произошёл захват аккаунта.

Важно: Браузеры часто автоматически кодируют специальные символы, поэтому используйте только Burp Suite для подмены email в HTTP-запросах.


Скриншоты из видео:

Автоматизированная проверка

# Пример скрипта для тестирования
test_emails = [
    "test@example.com",    # оригинал
    "tеst@example.com",    # кириллическая е
    "tеѕt@example.com",    # кириллические е и s
]

for email in test_emails:
    response = register_attempt(email)
    print(f"{email}: {response}")

🛡️ Что делать для защиты?

Объяснить программистам необходимость единой обработки Unicode на всех этапах (БД, SMTP, веб-приложение), чтобы избежать рассогласования.

Немедленные действия:

1. Проверьте текущих пользователей

-- Найдите подозрительные email с Unicode
SELECT email, LENGTH(email), CHAR_LENGTH(email) 
FROM users 
WHERE LENGTH(email) != CHAR_LENGTH(email);

2. Временная защита

Добавьте проверку при регистрации:

import unicodedata

def is_safe_email(email):
    # Проверяем, содержит ли email только ASCII
    try:
        email.encode('ascii')
        return True
    except UnicodeEncodeError:
        return False

Долгосрочные решения:

1. Исправление логики сравнения

def secure_email_compare(email1, email2):
    # Сравниваем точные Unicode-коды
    return email1.encode('utf-8') == email2.encode('utf-8')

2. Детекция гомографов

def detect_homographs(email):
    suspicious_chars = {
        'а': 'a', 'е': 'e', 'о': 'o', 'р': 'p', 
        'с': 'c', 'у': 'y', 'х': 'x'
    }
    
    for cyrillic, latin in suspicious_chars.items():
        if cyrillic in email:
            return f"Подозрительный символ: {cyrillic} (возможно, имелся в виду {latin})"
    return None

3. Единая обработка Unicode

Убедитесь, что все компоненты (БД, SMTP, веб-форма) обрабатывают Unicode одинаково:

  • Используйте UTF-8 везде
  • Не применяйте автоматическую нормализацию
  • Проверяйте входные данные на этапе валидации

4. Проверьте настройки collation в базе данных ⚠️ КРИТИЧЕСКИ ВАЖНО

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

Collation определяет правила сравнения символов в базе данных, и неправильная настройка может приводить к тому, что разные Unicode-символы считаются одинаковыми.

🔍 Проверка текущих настроек

-- Проверьте текущие настройки таблицы users
SHOW TABLE STATUS LIKE 'users';

-- Проверьте настройки конкретного поля email
SHOW COLUMNS FROM users LIKE 'email';

-- Проверьте, какая collation используется по умолчанию
SELECT @@collation_database, @@character_set_database;

📌 Основные типы collation и их влияние на безопасность:

  • utf8mb4_general_ci — небезопасно: проверяет только один байт за раз, может считать разные символы одинаковыми
  • utf8mb4_unicode_ci — небезопасно: может приводить похожие символы к одному виду
  • utf8mb4_bin — безопасно: выполняет строгое побайтовое сравнение на основе Unicode scalar values  
Пример 1:
-- Используйте строгое сравнение
ALTER TABLE users MODIFY email VARCHAR(255) 
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

Пример 2: 

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



🧪 Пример сравнения (ОПАСНО — только для тестирования!)

SELECT 'admin@site.com' = 'аdmin@site.com' COLLATE utf8mb4_general_ci;
-- может вернуть 1 (TRUE)

SELECT 'admin@site.com' = 'аdmin@site.com' COLLATE utf8mb4_bin;
-- всегда вернет 0 (FALSE)

Мониторинг и аудит:

1. Логирование подозрительной активности

def log_suspicious_registration(email, ip):
    if not is_safe_email(email):
        logger.warning(f"Suspicious registration attempt: {email} from {ip}")

2. Регулярные проверки

  • Еженедельно сканируйте базу на наличие похожих email
  • Отслеживайте множественные запросы сброса пароля
  • Мониторьте регистрации с международными доменами
  • Отклоняйте email, если он содержит символы из разных скриптов (кириллица + латиница).
  • Логируйте все попытки регистрации или сброса пароля с Unicode-символами.

🎯 Приоритет действий

Критический уровень (сделать сегодня):

  1. ✅ Проверить систему тестом выше
  2. ✅ Добавить временную ASCII-проверку email
  3. ✅ Просканировать существующих пользователей

Высокий уровень (сделать на этой неделе):

  1. ✅ Исправить логику сравнения email
  2. ✅ Обновить конфигурацию базы данных
  3. ✅ Добавить детекцию гомографов

Средний уровень (сделать в течение месяца):

  1. ✅ Внедрить полный мониторинг
  2. ✅ Обучить команду безопасности
  3. ✅ Провести пентест на Unicode-атаки

🔍 Дополнительные ресурсы

📞 Нужна помощь?

Если вы нашли уязвимость или нужна помощь с исправлением:

  1. Не паникуйте — большинство сайтов уязвимы
  2. Исправление обычно занимает 1-2 дня
  3. Обратитесь к специалистам по безопасности

Помните: эта уязвимость критична, но легко исправляется при правильном подходе!