← Volver al buscador
Seguridad web Intermedio

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.

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

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

# turbo-intruder (Burp extension) — single-packet HTTP/2 attack
# Permite ~30 requests/segundo con un solo paquete TCP
# 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

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:

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:

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":

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:

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

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:

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

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

7,99 €/mes · cancela cuando quieras

Artículos relacionados

Gratis

CSRF (Cross-Site Request Forgery) — explicado completo con bypasses

CSRF: cómo se explota, defensas comunes (tokens, SameSite, Origin), bypasses (method change, JSON, double-submit, content-type) y dónde buscarlo en cualquier app.

12 mincsrfauthsession
Leer artículo
Gratis€560

0-click Account Takeover — OTP brute force + Email Normalization

Dos fallos por separado parecen menores. Juntos, te dan ATO completo conociendo solo el email. Bounty real: €560 y 12 minutos de explotación.

14 minaccount-takeoverotprate-limiting
Leer artículo
Gratis

JWT — vulnerabilidades, bypasses y manipulación de claims

alg=none, RS256→HS256 confusion, kid SQLi/path traversal, jku spoofing, secret cracking con hashcat. Cómo cazar JWTs mal verificados.

13 minjwtauthsession
Leer artículo
Nivel intermedioToda la Academy

Contenido educativo de Kerb3r0ps. Úsalo solo sobre sistemas para los que tengas permiso. Volver al buscador.