Обход MFA: как атакующие обходят двухфакторную аутентификацию и как защититься
Как обходят многофакторную аутентификацию: 15 техник из публичных bug bounty-отчётов, что проверять на пентесте и как закрыть ошибки в логике MFA.
Заполни форму, и видео запустится здесь же.
Готово. Видео появится здесь, как только загрузим его.
Нажимая кнопку, соглашаешься с обработкой персональных данных

О чём эфир
Поймёшь, почему второй фактор обходят даже у HackerOne, Meta и Shopify: чаще ломается не сам TOTP или WebAuthn, а логика вокруг него.
Разберёшь 15 техник из публичных bug bounty-отчётов: проверку на клиенте, перебор кода без лимитов, race condition при отключении 2FA, вход через SSO без второго фактора, IDOR в настройках MFA, разные правила для веба, мобильного приложения и API, фишинг через reverse-proxy, push bombing и перехват SMS.
Заберёшь чек-лист проверки MFA для пентеста и принципы защиты для отчёта: решение только на сервере, лимиты на OTP, одноразовые коды, единая политика для всех точек входа и атомарные операции.
В конце практика на стенде: обход второго фактора через cookie, которая хранит состояние проверки.
Разбор эфира по темам
Второй фактор ломают не в криптографии, а в логике вокруг него
MFA ставят как дополнительный слой поверх пароля: логины и пароли утекают постоянно, и второй фактор должен закрыть вход, даже если пароль уже у атакующего. Поэтому обход второго фактора критичен для бизнеса, а bug bounty-программы платят за такие отчёты хорошие деньги.
При этом многофакторная аутентификация остаётся обычным куском кода внутри приложения. У неё есть своя логика работы, а значит, и свои ошибки разработчиков. Отсюда главный вывод практикума: сам механизм TOTP или WebAuthn обычно надёжен, ломается то, что вокруг него. Именно поэтому ошибки в реализации MFA находили даже у HackerOne, Meta и Shopify.
Многофакторная аутентификация это ещё один компонент системы. Как у него есть своя логика работы, так есть и свои ошибки, которые делают разработчики.
Кирилл Николаев
Уязвимости второго фактора укладываются в несколько классов. Почти любой найденный обход попадает в один из них:
- Решение принимает клиент: сервер отдаёт результат проверки, а пропускать дальше или нет, решает браузер.
- Нет rate limit: код можно перебирать без ограничений.
- Race condition: многошаговый процесс входа и отключения 2FA ломается параллельными запросами.
- Пустой или дефолтный код: бэкенд принимает пустую строку или 0000.
- Обходные пути входа: OAuth, SSO, восстановление пароля, legacy API.
- Слабая защита самого MFA-конфига: IDOR или CSRF при отключении второго фактора.
- Несогласованность поверхностей: веб требует второй фактор, а мобильное приложение или API нет.

Сервер должен решать сам: подмена ответа и перебор кода
Самый простой обход начинается с ответа сервера после ввода кода. Внутри лежит что-то вроде `success: false` или `mfa_verified: false`, и фронтенд по этому флагу решает, пускать ли пользователя дальше. Достаточно в Burp заменить false на true, и интерфейс откроет доступ.
Уязвимость не в самом OTP, не в том, как он хранится и насколько сложно генерируется, а в том, что на клиенте есть код на JavaScript, который решает, валидный код или нет.
Кирилл НиколаевНа практике это не всегда так прямолинейно. Бывает, что часть API доступна ещё до ввода второго фактора. Бывает, что приложение передаёт флаг в одном запросе, а форму рисует по ответу на следующий, и менять приходится несколько мест. Но корень один: решение о входе принимается не на сервере.

Второй простой путь: перебрать сам код. Обычно это 4 или 6 цифр, то есть от 10 000 до 1 000 000 комбинаций. Без ограничения на число попыток такой код подбирается за разумное время. Был отчёт про Facebook или Instagram, где лимит и блокировка узлов были, но исследователь взял несколько тысяч облачных серверов и с каждого проверил по паре кодов. Выплата оказалась примерно равна тому, что он потратил на серверы.
Отсюда простое правило для защиты: код должен становиться недействительным после небольшого числа неудачных попыток, например после десяти.

Код живёт дольше, чем нужно: race condition, пустые и повторные OTP
На самом HackerOne нашли race condition при отключении двухфакторной аутентификации. Если отправить несколько запросов на отключение, приходило несколько писем со ссылками. После подтверждения одной ссылки остальные оставались рабочими, хотя действительной должна была остаться только последняя. В итоге атакующий с такой ссылкой мог снова и снова отключать 2FA без уведомления пользователя, даже после того как тот включал её обратно.

Иногда срабатывает совсем банальное: пустая строка или код вроде 0000 и 1111. Бэкенд должен считать пустое значение отсутствием кода и обрывать вход, а вместо этого пропускает дальше. Чаще всего это кусок тестового конфига или тестового кода, который доехал до продакшена.

Ещё одна ошибка: код не инвалидируется после использования. Если атакующий видит трафик пользователя, он успевает войти с тем же кодом со своего компьютера. Есть и более редкий вариант: код проверяется без привязки к пользователю, и твой собственный OTP подходит для входа в чужую учётную запись.

Второй фактор обходят сбоку: SSO, настройки MFA и разные поверхности
Вход через Google, Apple, VK и других провайдеров обычно реализован отдельным куском кода. Он может вообще не знать про проверку второго фактора. Тогда у пользователя MFA включена, а вход через SSO пускает без неё. Такой отчёт был у Shopify: обход двухфакторной аутентификации через вход Google.

У MFA есть и собственные настройки: включение, отключение, смена номера. Если в функции отключения есть IDOR, можно выключить второй фактор другому пользователю, подставив его идентификатор.

Самое частое попадание на крупных проектах: несогласованность между поверхностями. Веб пишет одна команда, приложение под iOS другая, под Android третья. Политика у компании одна, а реализация разная, и где-то второй фактор просто не проверяют: в API, в GraphQL, в старой версии REST API или в мобильном приложении.
Вход через обычное веб-приложение обычно максимально защищён: его легко тестировать, простые баги там уже собрали. С мобильными приложениями сложнее: их надо отдельно установить, посмотреть, может быть, отреверсить.
Кирилл Николаев
Когда атакуют человека, а не код: фишинг, push bombing и SMS
Фишинг через reverse-proxy вроде Evilginx крадёт не только логин и пароль. Пользователь сам проходит второй фактор, а атакующий забирает итоговую сессионную cookie и дальше работает от его имени. Пароль и код ему уже не нужны. Против ключей WebAuthn и FIDO это не работает: они проверяют, на какой сервис идёт вход. А вот код из SMS или приложения перехватывается спокойно.

Push bombing строго говоря не уязвимость, а социальная инженерия, но работает. Атакующий знает пароль и шлёт push-запросы на подтверждение входа, пока человек не согласится. Так в 2022 году взломали учётную запись в Uber.
Рано или поздно человек или выключит телефон, или начнёт разбираться, что случилось, или просто нажмёт «Разрешить», лишь бы от него отстали.
Кирилл Николаев
Перехват SMS для пентестера редкая история, но APT-группировки им пользуются. Есть два пути: перенести номер жертвы на свою SIM-карту или перехватить сообщение через протокол SS7, который передаёт данные в открытом виде. Поэтому SMS считается слабым вторым фактором. Если есть выбор, используй приложение-аутентификатор.

Редкие, но живые ошибки: type juggling, app-пароли, обход лимитов и сессии
Type juggling встречается редко, но о нём стоит знать. Старые версии PHP до восьмой сравнивают типы так, что 0 и строка с цифрами могут оказаться равны. Если отправить вместо строки число или массив, проверка кода может пройти.

Некоторые протоколы вообще не умеют работать с OTP: IMAP, SMTP, CalDAV, старые API. Для них приложение выдаёт отдельный пароль без второго фактора. Ошибка появляется, если такой пароль можно сгенерировать без подтверждения текущего второго фактора или если он даёт доступ шире, чем обычный вход.

Лимит на ввод кода иногда считается неправильно. Бэкенд смотрит на заголовки вроде X-Forwarded-For, чтобы понять, откуда пришёл запрос, и тогда каждый перебор можно отправлять как будто с нового адреса. Обычно прокси вроде nginx эти заголовки переписывает, так что сработает не везде.

И последнее: смена пароля или второго фактора не завершает старые сессии. Пользователь понял, что его взломали, всё поменял, а украденная cookie продолжает работать. За такой отчёт на HackerOne вряд ли заплатят, но проблему стоит закрыть.

Чек-лист проверки MFA на пентесте
Простые баги вроде перебора срабатывают всё реже. Чаще находится ошибка в логике: как устроен вход через API или мобильное приложение и какие запросы доступны ещё до ввода кода.
Сейчас не так часто срабатывает брутфорс или какая-то простая бага. Работает именно логика двухфакторной аутентификации: как через API устроен вход, через мобильное приложение, какие API-запросы доступны до ввода кода.
Кирилл НиколаевПорядок проверки по методологии практикума:
- 1
Response tampering: подменить false на true, 4xx на 200, mfa_required и otp_verified.
- 2
Rate limit и brute-force: лимит на шаге ввода, а не только на пароле.
- 3
Race conditions: параллельные проверка, отключение и повторное включение.
- 4
Reuse и invalidation: старый код, другая сессия, код после выхода.
- 5
Alt-flows: восстановление пароля, OAuth и SSO, «запомнить меня», доверенное устройство, API и мобильное приложение.
- 6
Config-endpoints: CSRF, IDOR, повторная аутентификация при отключении MFA, смена номера и почты.
- 7
Session binding: факт прохождения MFA связан с конкретной сессией и токеном.


На практике на учебном стенде хватило одного наблюдения. После логина приложение ставит cookie с названием вроде mfa, которая хранит состояние проверки. Если взять cookie после ввода пароля, выставить нужное значение mfa и сразу запросить дашборд, сервер пускает без кода. Это та же ошибка: факт прохождения второго фактора не привязан к сессии на сервере.
Как закрыть эти ошибки
Каждый класс уязвимостей закрывается своим принципом. Их удобно вставлять в отчёт как рекомендации:
- Серверное состояние: решение о прохождении MFA принимает только сервер и хранит его в сессии, а не в ответе или cookie.
- Лимиты на OTP: ограничение попыток и отправки кода по аккаунту, сессии и IP.
- Защита изменений: отключение и сброс MFA только с CSRF-защитой и подтверждением паролем или текущим OTP.
- Одноразовость OTP: код сразу помечается использованным и удаляется, единое состояние для веба, мобильного приложения и API.
- Единая политика входа: OAuth, SSO, восстановление пароля и API проверяют, включён ли у пользователя второй фактор.
- Атомарность операций: многошаговые действия идут транзакциями в базе, чтобы их нельзя было выполнить параллельно.


Для себя вывод тот же, что и для приложения: SMS слабее приложения-аутентификатора, а смена пароля без завершения всех сессий не спасает от уже украденной cookie. В серьёзных сервисах для этого есть кнопка «выйти на всех устройствах».
Частые вопросы
Можно ли обойти двухфакторную аутентификацию?
Да. Чаще уязвим не сам механизм TOTP или WebAuthn, а логика вокруг него: проверка результата на клиенте, отсутствие лимитов на ввод кода, альтернативные способы входа и настройки MFA. Такие ошибки находили даже у HackerOne, Meta и Shopify.
Почему SMS считается слабым вторым фактором?
Номер можно перенести на чужую SIM-карту, а протокол SS7, через который идут SMS, передаёт данные в открытом виде. Поэтому код из SMS перехватить проще, чем код из приложения-аутентификатора.
Защищает ли MFA от фишинга?
Не всегда. Фишинг через reverse-proxy вроде Evilginx забирает сессионную cookie уже после ввода пароля и кода, и дальше атакующий работает как пользователь. Против ключей WebAuthn и FIDO такой приём не срабатывает: они проверяют сервис, на который идёт вход.
Что такое push bombing?
Атакующий знает логин и пароль и шлёт пользователю push-запросы на подтверждение входа, пока тот не нажмёт «Разрешить», чтобы от него отстали. Так в 2022 году взломали учётную запись в Uber.
Как проверить MFA на пентесте?
Проверить, что решение о входе принимает сервер, а не клиент. Есть ли лимиты на отправку и ввод OTP по аккаунту, сессии и IP, нет ли race condition при отключении 2FA, одноразовый ли код, одинаково ли второй фактор требуют веб, мобильное приложение, API и SSO и завершаются ли сессии после смены MFA.
Ещё эфиры по теме
Тема:ПентестКарьера639 участниковХод мысли на собеседовании важнее готового ответа. Два технических интервью целиком: junior по вебу, middle по инфраструктуре. Где проходит граница между уровнями?
Тема:Пентест1079 участниковНи одной учётной записи, а домен уже выдаёт о себе много. Карта кратчайшего пути к администратору домена и кейс, где изоляцию двух доменов обошли через пароли из сетевой папки.
Тема:Пентест79 участниковОдна кавычка ломает запрос к базе. А условие OR 1=1 может изменить данные всех пользователей банка. Практика: перехват запросов в Burp Suite, поиск инъекции в API, выгрузка пользователей из базы.