Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel IntermedioCon cuenta

2FA bypass — TOTP brute force, response manipulation, fallback abuse, race conditions

Técnicas reales de bypass de 2FA: brute force de TOTP, manipulación de response (status 200 sin token válido), fallback a OTP por email, race conditions en setup.

Gorka El Bochi11 de mayo de 202614 min

Respuesta rápida

2FA reduce el riesgo de credential stuffing pero no es bala de plata — cada implementación introduce su propia clase de bug. Los cinco bypasses más rentables: brute force (rate limit ausente o débil → 6 dígitos son 1M combos, vencibles en horas), response manipulation (cambiar el status del verify endpoint), fallback abuse (saltar TOTP usando recovery codes / email OTP), race conditions en setup (linkear tu authenticator a la cuenta de la víctima entre register y enroll) y session fixation (la session post-2FA hereda permisos pre-2FA). Bounties: €1.500-€15.000 — el bug class más rentable del 2026 detrás de IDOR.


TOTP brute force — el bug que no debería existir pero existe

TOTP genera 6 dígitos cada 30s. Espacio total: 1.000.000 combos. Si el server no rate-limita el endpoint de verify → vencible.

Test rápido

http
POST /api/auth/2fa/verify
{"code": "000000"}        → 401 Invalid code
{"code": "000001"}        → 401 Invalid code
{"code": "000002"}        → 401 Invalid code
...

¿La respuesta cambia tras N requests? Si tras 1000 sigues recibiendo 401 (no 429 Too Many Requests), brute force es viable.

Cuenta atrás

Con TOTP de 30s y rate de 100 req/s contra 1M combos → media de 5000s ≈ 1.5h. Si el rate es 500/s (paralelo) → 17min. Si el rate es 10/s → casi 14h pero sigue vencible.

Asumiendo que el código cambia cada 30s, necesitas resincronizar tras cada ventana — pero como el código sigue siendo válido durante esos 30s, en cualquier batch tienes la oportunidad de hit.

Tools

bash
# turbo-intruder (Burp extension) — single-packet HTTP/2 attack
# Permite ~30 requests/segundo con un solo paquete TCP
python
# turbo-intruder script
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=5, requestsPerConnection=100, engine=Engine.HTTP2)
    for i in range(1000000):
        code = str(i).zfill(6)
        engine.queue(target.req, code)

def handleResponse(req, interesting):
    if req.status != 401:           # 200 = bypass
        table.add(req)

[!warning] No quemes la cuenta de tu test user Brute force genera muchísimos logs. Avisa al program antes. Algunos consideran "denial of service against own account" out of scope.

<!-- PAYWALL -->

Response manipulation — el €5000 fácil

El client trustea la respuesta del server. Si la app es SPA y verify retorna {"success": true, "redirect": "/dashboard"} para válido y {"success": false} para inválido — manipular la respuesta en Burp engaña al frontend.

Patrón

http
POST /api/auth/2fa/verify
{"code": "000000"}

← Response (interceptada en Burp):
   HTTP/1.1 401 Unauthorized
   {"success": false}
                                ← cambia a
   HTTP/1.1 200 OK
   {"success": true, "redirect": "/dashboard"}

Si el frontend lee success para decidir si redirigir + guardar el token → entras al dashboard. Funciona si:

  • El server emite la cookie de sesión antes del 2FA (anti-pattern frecuente).
  • La autenticación final está en el frontend (SPA mal implementada).

Status code only

Algunos clients miran solo status === 200:

css
HTTP/1.1 401 Unauthorized          → cambia a HTTP/1.1 200 OK

Frontend redirige.

Patrón "code accepted" en endpoint distinto

Algunas apps validan 2FA en /verify y luego llaman a /finalize-login con el token de la sesión pre-2FA. Si /finalize-login no verifica que /verify haya pasado (asume que el frontend lo hizo) → call directo a /finalize-login salta 2FA:

http
POST /api/auth/finalize-login
Cookie: pre_2fa_session=XXX
                                  ← 200 OK + cookie de sesión post-2FA

Fallback abuse — el 2FA del 2FA

Casi todas las apps tienen fallbacks por si el user pierde el authenticator: backup codes, OTP por email/SMS, security questions. Cada fallback es una superficie nueva.

OTP por email — débil

Si TOTP requiere brute force de 1M combos, OTP por email suele ser 4-6 dígitos pero sin rate limit estricto porque "el atacante necesita el email":

http
POST /api/auth/2fa/send-email-otp
{"userId": VICTIMA}
                                  ← email enviado
POST /api/auth/2fa/verify-email-otp
{"code": "0000"}                  ← brute force 4 dígitos = 10K combos
{"code": "0001"}
...

Especialmente sangriento si el OTP no expira o expira tras horas — tienes ventana grande.

Recovery codes — leak en setup

Cuando enrolla 2FA, el server muestra 10 backup codes. Si el endpoint que los genera tiene IDOR:

http
GET /api/auth/2fa/recovery-codes/USERID
                                  ← idealmente solo USERID==me, pero IDOR a otros

→ Lista de 10 codes que bypassean TOTP para ese user.

Security questions

Endpoint de "olvidé mi 2FA" pide questions:

  • "What's your mother's maiden name?" → OSINT / LinkedIn
  • "What's your first pet's name?" → frecuentemente en social media
  • Algunas apps tienen el question predefinido ("First school?") → respuestas comunes en wordlist

Race condition en 2FA setup

Cuando un user enrolla 2FA, hay una ventana entre "muestra QR code" y "verifica primer código". Si el server permite múltiples enrollments paralelos:

Patrón

bash
Atacante (con sesión robada por XSS/credential stuff, sin 2FA aún):
  POST /api/auth/2fa/setup     → QR code 1 (secret A)
  POST /api/auth/2fa/setup     → QR code 2 (secret B)   ← sobrescribe el secret?
  POST /api/auth/2fa/setup     → QR code 3 (secret C)

Si el último request sobrescribe el secret en DB sin invalidar los anteriores:

  • Víctima escanea QR 1, enrolla TOTP normalmente.
  • Pero el secret final en DB es C (controlado por atacante).
  • Atacante genera código con secret C → entra como víctima.

Bounty real documentado: €3.500 (fintech).

Setup + verify split

Algunas apps separan setup (genera secret + persistencia inmediata) de verify (confirma que el user lo escaneó). Si setup persiste el secret antes de verify → atacante con sesión válida puede ejecutar setup en cuenta ajena vía IDOR en userId body:

http
POST /api/auth/2fa/setup
{"userId": VICTIMA, "secret": "ATACANTE_SECRET"}
                                  ← secret guardado para víctima

Próximo login de víctima → pide 2FA → atacante tiene el secret → entra.


Session fixation post-2FA

Anti-pattern frecuente: la sesión emitida pre-2FA (tras password) sigue siendo válida tras 2FA. Si el server no rota el session token tras verify:

Patrón

  1. Atacante captura sesión pre-2FA de víctima (XSS, sniffing en HTTP, etc.).
  2. Víctima completa 2FA normalmente.
  3. Atacante usa la misma sesión pre-2FA → ahora es post-2FA con todos los permisos.

Fix correcto: rotar session token tras verify (igual que tras password reset).

Algunas apps emiten dos cookies: session (post-password) y session_2fa (post-2FA). Si el backend solo chequea session para endpoints "públicos" pero asume que el 2FA está validado para todo → bypass parcial.


Apps con magic link como alternative auth method frecuentemente saltan 2FA porque "el email es factor". Pero si el email no requiere 2FA → atacante con acceso al email gana incluso si la app principal tiene 2FA.

Chain

bash
1. Atacante envía magic link a evil-controlled-email (vía IDOR de profile update)
2. Magic link → login completo, salta 2FA
3. Cambia 2FA settings, password, etc.

Default credentials en backup codes

Algunas apps generan backup codes con patrones predecibles:

  • 8 dígitos derivados del userId con seed estático.
  • Hash del username truncado.
  • "BACKUP-00001" secuencial por user.

Test: enrolla 2FA en dos cuentas test, compara backup codes. ¿Hay patrón o son random reales?


Hunting checklist

  • Rate limit en verify endpoint — ¿1000 requests sin 429?
  • Response manipulation: prueba modificar status + body para forzar success.
  • Endpoint /finalize-login o equivalente — ¿se puede llamar sin pasar /verify?
  • Fallbacks: OTP email/SMS (rate limit, expiración), recovery codes (IDOR de listado), security questions (predecibles/OSINT).
  • Race condition en /setup: múltiples requests paralelos → ¿sobrescribe secret?
  • IDOR en /setup: userId body — ¿puedo enrollar 2FA en cuenta ajena?
  • Session rotation tras verify: el token cambia o sigue igual?
  • Magic link / passwordless que saltan 2FA.
  • Backup codes con patrones predecibles (compara entre cuentas).
  • Cookie post-2FA validada en TODOS los endpoints sensibles (no solo el primer).
  • Documenta el bypass con request mínimo + impact: ATO vs persistence vs role escalation.

Labs relacionados

Practica TOTP brute force, response manipulation, fallback abuse y race conditions de setup en labs de 2FA y Auth.

Practica esto en un lab

0 Click Ato Otp Brute Force

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta
Premium · 1 técnica más

Hay un payload extra al final

El bypass de 2FA via session fixation + IDOR del setup endpoint que da control completo sin nunca conocer el código original. Reportado a 3 fintech con bounties combinados de €8000.

Desbloquear

5 €/mes · cancela cuando quieras

Artículos relacionados