Сегодня мы не будем говорить о zero‑day, RCE или продвинутых APT. Мы поговорим о гораздо более опасной проблеме — о ложном чувстве безопасности.
В 2026 году многие организации считают, что «у нас включена двухфакторная аутентификация — значит, мы защищены». Но что, если 2FA — это просто фасад? Что, если за этой «бронированной дверью» стоит замок с четырёхзначным кодом и надпись: «угадывай сколько хочешь»? Именно такая уязвимость была обнаружена в одном из российских банков — и она позволяла полностью обойти 2FA, зная лишь номер телефона клиента.
Здравствуйте! Я аналитик SOC и параллельно занимаюсь пентестом. Недавно мне довелось участвовать в авторизованном black‑box пентесте российского банка — как внешнего, так и внутреннего периметра по стандартам ЦБ.
Инфраструктура была большая, около 4000 компов и 4500 тысячи пользователей. В ходе внешнего тестирования (15 сабдоменнов) были выявлены разные уязвимости: от классических Stored XSS и IDOR до неочевидных API‑мисконфигураций. Во внутренней инфраструктуре также обнаружились интересные векторы — от неправильно настроенных сервисов до нестандартных методов эскалации привилегий. Однако самым критичным находкой во внешнем пентесте стал обход механизма двухфакторной аутентификации (2FA) по SMS в личном кабинете клиента, предназначенном для подачи финансовых заявок.
Немного об импакте, который может получить злой хакер/мошенник
Это полноправный инструмент для оформления финансовых заявок, и доступ к нему открывает перед злоумышленником широкий спектр возможностей. Оформление проектного финансирования и кредитной линии. Все эти действия могут быть выполнены без дополнительного подтверждения — ведь 2FA уже пройдено. Таким образом, атакующий не просто «подсматривает» чужие данные — он активно использует доверие банка к легитимному пользователю для проведения мошеннических операций. В личном кабинете есть раздел с документами пользователя, его истории заявок, отчетность, реквизиты. И что самое страшное — это то, что на сайте есть номер телефона технической поддержки и он привязан к ЛК, мы можем с этого профиля подтверждать или отклонять выдачу денежных средств.


Что пошло не так? Секрет в четырёх цифрах
Когда я впервые зашёл на страницу входа в личный кабинет, все выглядело стандартно. Была возможность авторизоваться по номеру телефона. На первый взгляд удобно. Но с точки зрения безопасности — тревожный сигнал. Почему тревожный? Дело в том, что код подтверждения состоял из 4-х цифр, и тут вступает в игру простая арифметика:

Код состоит из 4 десятичных цифр: от 0000 до 9999.
Всего 10 000 возможных комбинаций.
При отсутствии ограничений на количество попыток — это полный брут за считанные секунды.
Таким образом, энтропия 2FA настолько низкая, что защищает он разве что от ручного угадывания.
От первого входа — к первой догадке
Первым делом я зарегистрировал тестовый аккаунт (ЕСТЕСТВЕННО с согласия банка, в рамках пентеста) и попытался войти в личный кабинет. Ввёл номер телефона — и буквально через пару секунд на него пришло SMS-сообщение вида:
Ваш код подтверждения: 5621 Банк «Рога и Копыта»

4 цифры, и в голову закрались три мысли:
Есть ли лимиты на ввод?
Как проверяется код на стороне сервера?
Можно ли автоматизировать?
Для ответа на вопросы я полез в Burp, начал шерстить логику работы. Там я обнаружил, что вся логика аутентификации оказалась сосредоточена всего на двух API-вызовах:
1. Пользователь нажимает «Получить код»:

Сервер отвечает:
{"repeat":180}
Что означает: «SMS отправлена. Повторно запросить можно только через 180 секунд».
2. Проверка кода — точка входа для атаки
После получения SMS пользователь вводит код, и браузер отправляет:
POST /api/*****/login HTTP/1.1 Host: **** Content-Type: application/json {"code":"0548","phone":"+7(111) 222-22-22"}
И тут у нас вся суть уязвимости:
При неверном коде → HTTP 400
{"message":"Номер телефона или код некорректный"}
При верном коде → HTTP 200 и установка сессионных кук (JSESSIONID, PHPSESSID и др.).
Не было никаких других ограничений, ни счётчика попыток, ни блокировки сессии, ни капчи, НИЧЕГО. Для сервера каждый запрос был как первый. А значит, можно отправить 10 000 таких запросов подряд – и он честно ответит на каждый.
Создание эксплоита
Если сервер не против общения, то почему бы не позадавать ему разные запросы 10 000 раз подряд?
Хотя основной PoC был реализован на JavaScript, чтобы работать внутри браузерной сессии, сама атака — чисто HTTP-базированная, а значит, её можно воспроизвести любым инструментом, умеющим отправлять POST-запросы.
Почему именно JavaScript в браузере?
Использует те же куки, что и пользователь (
JSESSIONID,PHPSESSID),Обходит CORS и SameSite-политики,
Демонстрирует уязвимость вживую на сайте банка — без прокси, без Burp, без сторонних тулзов.
Полный скрипт по понятным причинам публиковать не буду, но и замудренного там ничего нет.
1. Отправка запроса на проверку кода
await fetch('https://roga_and_copyta/*****/api/*****/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({code: codeStr, phone: phone}) });
Сервер честно отвечает 200 при успехе — и этого достаточно.
2. Многопоточность через асинхронные функции
for (let i = 0; i < 20; i++) { turboThread(i, start, end); // 20 "потоков" }
Каждый перебирает свой диапазон кодов параллельно.
3. Определение успеха
if (response.status === 200) { foundCode = codeStr; // Визуальное оповещение + ввод кода в поле }
А можно ли на Python?
Конечно! Изначально скрипт и был на Python, для демонстрации заказчику был переписан на JS. Неважно, на каком языке вы его напишете — главное, что сервер отвечает на каждый запрос. А когда он делает это 10 000 раз подряд без единого «стоп слова» — то 2FA превращается в иллюзию.
Корень проблемы: CWE-307 и ошибка проектирования
Уязвимость классифицируется как:
CWE-307: Improper Restriction of Excessive Authentication Attempts
CVSS 3.1: 9.1 (Critical)
Вектор: Network
Сложность: Low
Требуемые привилегии: None
Взаимодействие с пользователем: None
Обход 2FA → полный доступ к ЛК
Почему так вышло? Три фатальные ошибки:
Удобство > Безопасность:
Полагаю, что разработчики боялись «раздражать» клиента блокировками при опечатке — и убрали все механизмы защиты. (теория)Непонимание угрозы автоматизации:
Считали, что «4 цифры — это и так сложно угадать», забыв, что человек не угадывает — скрипт перебирает.Отсутствие тестирования на перебор:
Ни один из сценариев «многократный ввод кода» не был покрыт тестами безопасности.
Как это исправить? Рекомендации
Безопасность — это не «галочка про 2FA», а многослойная защита. Что нужно сделать:
Жесткие лимиты попыток. Максимум 3–5 попыток на один код, после чего уничтожение кода и необходимость нового.
CAPTCHA после нескольких ошибок. Простая капча уже остановит 90% скриптов.
Переход на 6-значные коды. Такое количество комбинаций уже займет часы, а не 35 секунд.
И понятное дело мониторинг.
Заключение
Это история больше не про взлом банка, а история про иллюзию безопасности. Радует то, что банки уделяют внимание пентестам для поиска таких простых дыр. Все уязвимости закрыты, это был очень интересный опыт.
Комментарии (10)

gg1ZmO Автор
26.03.2026 08:44Понимаю вашу реакцию, довольно часто встречаю такое.
Но с точки зрения классификации - это не баг, а уязвимость. Баг - это когда что-то работает не так, как задумывал разработчик. Здесь же всё работает ровно по задумке, просто задумка такая себе.Так что это полноценная уязвимость, о которой я, конечно же, информирую заказчика и выдаю рекомендации по устранению.
rtkprg3
26.03.2026 08:44Но при этой "задумке" банк все равно называет свою аутентификацию 2FA? Если да, то это именно баг.

Zhuravlev-A-E
26.03.2026 08:44Баг - это когда что-то работает не так, как задумывал разработчик.
Обычно считается, что баг (или программная ошибка) это когда либо запрограммированно (код работает) не так как задумано либо ошибка в дизайне
Или словами классика: "В программном обеспечении имеется ошибка, если оно не выполняет того, что пользователю разумно от него ожидать"

verticalacid
26.03.2026 08:44Пост после удаления слопа:
При пентесте российского банка нашли, что SMS-код для входа в личный кабинет — 4 цифры (10 000 вариантов), а сервер не ограничивает количество попыток ввода. Ни блокировки, ни капчи, ни счётчика ошибок. Написал скрипт, перебрал все коды за секунды, получил полный доступ к ЛК с финансовыми заявками, паспортными данными и возможностью оформлять кредиты. Банку сообщили, дыру закрыли.

Shaman_RSHU
26.03.2026 08:44У вас первые две картинки огромны, но контент там размазан, поэтому можно было не замазывать. Но суть понятна

Reedus0
26.03.2026 08:44Господа, ну мы все взрослые люди, ну давайте не будем рофлить над начинающим специалистом

Vaha2838
26.03.2026 08:44Мужик даже в самом простом приложении от «синего» банка стоит защита от брута. После трех попыток все просто блокируется. И брутер идет дальше кодить. Так что дальше развивать мвсль не имеет смысла. Ну а с новыми законами о заморозке переводов кража денег даже при полном доступе к банку человека становится тоже миссией не выполнимо. У меня кстати был такой клиент напереводил тысяч 150 пока Сбкр ему не вставил тычину и не заблокировал кабинет. У чела включились мозги и он вышел уже на меня. Дальше дело техники. А счас этот порог блокировки начинается по моему тысяч с 20 . Переводишь на незнакомую карту 20 к и улетаешь в блок.
rtkprg3
Меня триггерит, когда 2FA называют такую систему, где пароль можно сбросить при помощи СМС и открытых данных (пусть и открытых в даркнете). Например, сброс пароля при помощи СМС и номера карты или номера паспорта. Это все уже ОДНОфакторка, т.к. не требуется второй секрет. Номер паспорта и карты секретом не является.
Для вас, как пентестера, такие сценарии являются багом, о котором вы информируете заказчика?