⚠️ Что это за уязвимость?
Если у вас есть веб-сервер с регистрацией через email, вы можете быть уязвимы к атаке типа "Punny Code Account Takeover".
Суть угрозы: Хакеры могут захватить любой аккаунт на вашем сайте, используя визуально одинаковые, но технически разные символы Unicode в email-адресах. Атака возможна даже без взаимодействия пользователя (0-click), если система автоматически отправляет письма для сброса пароля.
📚 Подробные материалы об уязвимости:
- Техническое описание: blog.voorivex.team/puny-code-0-click-account-takeover
- Видео-объяснение: youtube.com/watch?v=Cj1sOFHDClM
🔍 Как работает атака?
Шаг 1: Хакер находит жертву
Злоумышленник выбирает целевой аккаунт: admin@company.com
Шаг 2: Создание визуального двойника
Хакер создает похожий email с гомографами (визуально одинаковыми символами из разных алфавитов и разными UNICODE):
- Оригинал:
admin@company.com
(латинские буквы) - Подделка:
аdmin@company.com
(первая буква "а" — кириллическая)
Шаг 3: Эксплуатация уязвимости системы
Проблема в том, что разные компоненты по-разному обрабатывают Unicode:
- База данных (MySQL) приводит кириллическую "а" к латинской "a"
- SMTP-сервер различает эти символы как разные
Шаг 4: Захват аккаунта
- Хакер запрашивает "восстановление пароля" для аккаунта похожего на
аdmin@company.com (специально создает такой поддельный email)
- Система проверяет в БД: находит в базе сайте аккаунт для
admin@company.com
(считает символы одинаковыми) - Почтовый сервер отправляет письмо: на поддельный аккаунт
аdmin@company.com
(где кириллическая "а") - Хакер получает письмо на специально созданный 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-символами.
🎯 Приоритет действий
Критический уровень (сделать сегодня):
- ✅ Проверить систему тестом выше
- ✅ Добавить временную ASCII-проверку email
- ✅ Просканировать существующих пользователей
Высокий уровень (сделать на этой неделе):
- ✅ Исправить логику сравнения email
- ✅ Обновить конфигурацию базы данных
- ✅ Добавить детекцию гомографов
Средний уровень (сделать в течение месяца):
- ✅ Внедрить полный мониторинг
- ✅ Обучить команду безопасности
- ✅ Провести пентест на Unicode-атаки
🔍 Дополнительные ресурсы
- Unicode Security Guide
- RFC 5891 (Internationalized Domain Names)
- Unicode Confusables Detection
- Unicode Security Mechanism
📞 Нужна помощь?
Если вы нашли уязвимость или нужна помощь с исправлением:
- Не паникуйте — большинство сайтов уязвимы
- Исправление обычно занимает 1-2 дня
- Обратитесь к специалистам по безопасности
Помните: эта уязвимость критична, но легко исправляется при правильном подходе!