web-hacking

2FA Bypass: Tecniche, Payload e Attacchi OTP per Pentest

2FA Bypass: Tecniche, Payload e Attacchi OTP per Pentest

2FA bypass :response manipulation,OTP brute force,link diretto post-login,SIM swapping, phishing MFA,backup code abuse.Payload per pentester ed hacker ethical

  • Pubblicato il 2026-07-10
  • Tempo di lettura: 19 min

2FA Bypass: Tutte le Tecniche per Aggirare l’Autenticazione a Due Fattori #

Il 2FA bypass è l’insieme di tecniche che permettono a un attaccante di accedere a un account protetto dall’autenticazione a due fattori senza possedere il secondo fattore. Molte implementazioni 2FA sembrano sicure ma hanno falle logiche, di configurazione o di implementazione che le rendono aggirabili.

Trovare un bypass del 2FA in un programma di bug bounty vale quasi sempre Critical o High — stai dimostrando che una protezione di sicurezza pensata per impedire l’account takeover non funziona.

Il 2FA non è un meccanismo unico: ci sono OTP via SMS, TOTP (Google Authenticator), email OTP, backup code, push notification (MFA), chiavi hardware (FIDO2). Ogni implementazione ha i propri punti deboli.

Satellite della guida pillar Auth & Access Control.

Tutte le tecniche di questa guida vanno testate esclusivamente su applicazioni per cui si dispone di autorizzazione scritta esplicita — HTB, lab, CTF o penetration test autorizzati.


Come Funziona il 2FA (e Dove Si Rompe) #

Prima di capire i bypass, capisci il flusso normale del 2FA:

text
1. Utente inserisce username + password → autenticazione primo fattore
2. Server verifica le credenziali → crea uno stato "half-authenticated"
3. Server chiede il secondo fattore (OTP, TOTP, ecc.)
4. Utente inserisce il codice → autenticazione completata
5. Server crea la sessione completa → utente dentro

I bypass sfruttano errori in uno qualsiasi di questi passi. I più comuni:

  • Il server non verifica correttamente che il secondo fattore sia stato completato
  • Il codice OTP non ha limite di tentativi
  • Il flusso post-2FA può essere raggiunto direttamente saltando il passo 3
  • La risposta del server al passo 3 può essere manipolata lato client
  • Il “secondo fattore” può essere ottenuto in altro modo (SIM swap, phishing)

Flusso di autenticazione 2FA e punto di bypass


Come Identificare il Tipo di 2FA #

Prima di scegliere quale tecnica provare, capisci con cosa hai a che fare. Ogni tipo ha un tell riconoscibile:

  • Google/Microsoft Authenticator, Authy → TOTP (RFC 6238), codice a 6 cifre generato client-side, rigenerato ogni 30s. Nessuna chiamata di rete per generarlo, solo per verificarlo.
  • Codice via email → OTP generato e inviato dal server. Cerca l’endpoint /send-otp o /resend-code.
  • Codice via SMS → OTP carrier-based. Non intercettabile senza SIM swap o accesso al device.
  • Push notification (Duo, Okta, Microsoft Authenticator push) → challenge/response, l’utente approva da app. Vettore principale: MFA fatigue.
  • Passkey/chiave hardware (YubiKey, Windows Hello) → WebAuthn, vincolato all’origine (dominio). Il più resistente a tutte le tecniche di questa guida.
  • Backup code → stringa alfanumerica monouso, generata all’attivazione del 2FA.

Questo ti dice subito dove concentrarti: contro TOTP/SMS/email ha senso brute force, replay, response manipulation. Contro push ha senso MFA fatigue. Contro passkey, quasi nessuna tecnica logica di questa guida funziona — il test si sposta su altri vettori (device compromise, social engineering, downgrade forzato a un metodo più debole).


Tecnica 1 — Response Manipulation #

È la più semplice e sorprendente: l’applicazione decide lato server se il codice è corretto, ma poi comunica l’esito al frontend con una risposta JSON che puoi intercettare e modificare.

Come funziona:

text
1. Mandi il codice OTP sbagliato
2. Il server risponde: {"success": false, "message": "Invalid OTP"}
3. Burp intercetta questa risposta PRIMA che arrivi al browser
4. Modifichi: {"success": true, "message": "OTP verified"}
5. Il browser pensa che il 2FA sia passato → ti reindirizza alla dashboard

Passo per passo con Burp:

text
1. Intercetta la request del 2FA (Burp Proxy → Intercept ON)
2. Inserisci un OTP sbagliato (es. 000000) e manda
3. In Burp: vai su "Response" e aspetta la risposta del server
4. Modifica il corpo della risposta:
   - false → true
   - "success":0 → "success":1
   - "verified":false → "verified":true
   - "status":"failed" → "status":"success"
5. Forward → il browser riceve la risposta modificata → accesso ottenuto

Funziona? No sempre. Dipende da come è implementato il flusso:
- Se il server crea la sessione solo dopo aver verificato il 2FA lato server → non funziona
- Se il server crea la sessione già al passo 1 e il 2FA è solo un "gate" frontend → funziona

Sequence diagram: response manipulation con Burp Suite

Variante: response manipulation al contrario. Invece di intercettare il codice sbagliato, manda quello giusto e cattura la risposta di successo (200 OK con il payload esatto di conferma). Poi, in un secondo momento, prova a rigiocare quella stessa risposta su un tentativo con OTP sbagliato — utile quando il frontend valida solo la struttura della risposta e non un token univoco al suo interno.

Come testare velocemente:

bash
# Intercetta la request del 2FA con Burp
# Nota il formato della risposta di successo (fai prima un login valido)
# Poi prova con OTP sbagliato e modifica la risposta

# Oppure con curl: manda OTP sbagliato e guarda la risposta raw
curl -X POST "https://target.com/api/verify-otp" \
  -H "Content-Type: application/json" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"otp": "000000"}'
# Response: {"success":false,"error":"Invalid code"}
# → Prova a mandare questa stessa request ma intercetta e modifica la response

Tecnica 2 — Salta il Passo del 2FA (Direct Navigation) #

Questa è la falla logica più comune. Il server autentica l’utente con username + password, poi dice “ora inserisci il 2FA” — ma non verifica che il 2FA sia stato completato prima di permettere l’accesso alle pagine protette.

Come funziona:

text
1. Fai login con credenziali valide → sei "half-authenticated"
2. Il server ti manda alla pagina /verify-2fa
3. Invece di inserire il codice, vai direttamente a /dashboard o /account
4. Il server controlla solo se hai una sessione (creata al passo 1) e non se hai completato il 2FA
5. Sei dentro senza aver mai inserito il codice

Come testare:

bash
# Passo 1: fai login con credenziali valide (senza completare il 2FA)
curl -X POST "https://target.com/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"victim@mail.com","password":"password123"}' \
  -c cookies.txt  # salva i cookie

# Passo 2: senza inserire il 2FA, prova ad accedere alle pagine protette
curl "https://target.com/dashboard" \
  -b cookies.txt  # usa i cookie del login

curl "https://target.com/account/settings" \
  -b cookies.txt

curl "https://target.com/api/user/profile" \
  -b cookies.txt

# Se risponde 200 invece di reindirizzarti a /verify-2fa → bypass confermato
text
In Burp:
1. Fai login, aspetta la pagina /verify-2fa
2. Apri una nuova tab nel browser (stesso browser, stessa sessione)
3. Vai manualmente a /dashboard, /account, /admin
4. Sei dentro? → bypass confermato

Tecnica 3 — OTP Brute Force #

I codici OTP sono di solito 4-8 cifre. Se non c’è rate limiting né blocco account, puoi provarli tutti.

Spazio di ricerca:

text
4 cifre → 10.000 combinazioni
6 cifre → 1.000.000 combinazioni
8 cifre → 100.000.000 combinazioni

Un OTP a 6 cifre con validità di 30 secondi (TOTP) è impraticabile da bruteforzare in tempo. Ma molte implementazioni:

  • Non limitano i tentativi
  • Non fanno scadere il codice dopo N tentativi
  • Usano OTP a 4 cifre (10.000 combinazioni)
  • Non invalidano il codice dopo un uso riuscito

Come testare il rate limiting:

bash
# Manda 10 richieste rapide con codici sbagliati
for i in $(seq 1 10); do
  curl -s -X POST "https://target.com/api/verify-otp" \
    -H "Cookie: session=SESSION_HALF_AUTH" \
    -H "Content-Type: application/json" \
    -d "{\"otp\": \"00000$i\"}" \
    -o /dev/null -w "Tentativo $i: %{http_code}\n"
done
# Se tutti i tentativi danno 200 (o 401 senza blocco) → no rate limiting → bruteforzabile

# Brute force con ffuf (6 cifre = 1M, ma se la sessione non scade e non c'è blocco...)
ffuf -u "https://target.com/api/verify-otp" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"otp":"FUZZ"}' \
  -w <(seq -w 0 999999 | head -10000) \
  -mc 200 \
  -fr "invalid|error|incorrect"

Bypass del rate limiting per IP:

bash
# Alcune implementazioni bloccano per IP ma non per sessione
# Prova a ruotare l'IP con header:
curl -X POST "https://target.com/api/verify-otp" \
  -H "X-Forwarded-For: 1.2.3.4" \
  -H "X-Real-IP: 1.2.3.5" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"otp":"123456"}'
# Ogni request con un IP diverso in X-Forwarded-For resetta il rate limit?
# → Rate limit bypassato

Rate limit “silenzioso”: in alcuni casi il server blocca ufficialmente dopo N tentativi (risposta 401/429), ma se per puro tentativo mandi comunque il codice corretto oltre quel limite, risponde 200. Vale sempre la pena testare il codice giusto anche dopo un presunto blocco — la logica di blocco e la logica di verifica a volte sono due path di codice separati e non sincronizzati.

Per tecniche di bypass del rate limit più generali (header rotation, endpoint switching, method tampering) vedi API Rate Limit Bypass; per brute force su login e credential stuffing vedi Brute Force.


Tecnica 4 — OTP Riusabile (Manca l’Invalidazione) #

Un OTP usato con successo dovrebbe essere immediatamente invalidato. Se il server non lo fa, lo stesso codice funziona più volte.

Come testare:

bash
# Usa un OTP valido per autenticarti
curl -X POST "https://target.com/api/verify-otp" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"otp":"482916"}'  # OTP valido

# Logout, fai di nuovo login (ottieni una nuova sessione half-auth)
# Riusa lo stesso OTP
curl -X POST "https://target.com/api/verify-otp" \
  -H "Cookie: session=NUOVA_SESSION_HALF_AUTH" \
  -d '{"otp":"482916"}'  # stesso OTP di prima
# Se risponde 200 → OTP non invalidato dopo l'uso → bypass possibile

Tecnica 5 — OTP Scaduto Ancora Accettato #

I TOTP (Google Authenticator) sono validi 30 secondi. Alcune implementazioni accettano codici vecchi di diversi minuti per “tolleranza di clock”.

Come testare:

bash
# Ottieni un codice TOTP valido
# Aspetta 2-5 minuti (il codice dovrebbe essere scaduto)
# Prova a usarlo
curl -X POST "https://target.com/api/verify-otp" \
  -H "Cookie: session=SESSION" \
  -d '{"otp":"CODICE_VECCHIO"}'
# Se risponde 200 dopo 2+ minuti → finestra di validità troppo larga

Tecnica 6 — Manipolazione del Parametro User (Account Takeover) #

Durante il flusso 2FA, alcune applicazioni includono l’identificatore dell’utente nella request di verifica. Se puoi modificarlo, verifichi il tuo OTP ma per un altro account.

Come funziona:

text
1. Fai login col tuo account (hai il tuo OTP valido)
2. La request di verifica include: {"user_id": TUO_ID, "otp": "482916"}
3. Cambia user_id con quello della vittima: {"user_id": VITTIMA_ID, "otp": "482916"}
4. Il server verifica il tuo OTP ma crea la sessione per la vittima
5. Sei loggato come vittima

Come testare:

bash
# Intercetta la request di verifica OTP con Burp
# Cerca user_id, email, username, account_id nel body
# Sostituisci col target

curl -X POST "https://target.com/api/2fa/verify" \
  -H "Content-Type: application/json" \
  -d '{"user_id": 1, "otp": "482916"}'
# user_id: 1 = account admin
# otp: 482916 = OTP del TUO account → stai verificando il tuo codice per l'account admin

Tecnica 7 — Backup Code Abuse #

Quando l’utente attiva il 2FA, l’applicazione genera codici di backup (di solito 8-10 codici monouso). Se questi codici sono prevedibili o hanno problemi di implementazione:

Come testare:

bash
# Codici backup prevedibili: sequenziali o derivati dall'user_id
# Se il codice backup è nel formato XXXXX-XXXXX con spazio limitato → brute force

# Prova codici comuni che le persone salvano male
curl -X POST "https://target.com/api/2fa/backup" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"backup_code":"12345678"}'

# Backup code accettato anche se il 2FA non è abilitato?
# Prova su account senza 2FA
curl -X POST "https://target.com/api/2fa/backup" \
  -H "Cookie: session=SESSION_UTENTE_SENZA_2FA" \
  -d '{"backup_code":"00000000"}'
# Se risponde 200 → i backup code non richiedono che il 2FA sia attivo

Nota anche un vettore indiretto: se all’attivazione del 2FA i backup code vengono generati e mostrati subito in una risposta API separata, un problema di CORS mal configurato o una XSS altrove nell’app possono permettere a un attaccante di leggere quella risposta ed esfiltrare i codici prima ancora che l’utente li salvi.


Tecnica 8 — MFA Fatigue (Push Notification Bombing) #

Specifico per implementazioni 2FA con push notification (Microsoft Authenticator, Duo, Okta). L’attaccante conosce le credenziali e bombarda l’utente di notifiche push finché per stanchezza o confusione approva.

text
Flusso:
1. Attaccante ha username + password della vittima
2. Fa login in loop → ogni tentativo manda una push notification alla vittima
3. La vittima riceve 50 notifiche di approvazione in 30 minuti
4. La vittima, per errore o stanchezza, approva una → attaccante dentro

Reale: Uber breach 2022 — un contractor ha approvato una notifica MFA
dopo essere stato bombardato per ore, ricevendo anche un WhatsApp
"Sono del supporto IT, approva la notifica"

Non è qualcosa che testi in un pentest standard senza autorizzazione esplicita — ma documentalo come vettore di social engineering se il target usa push MFA.


Tecnica 9 — SIM Swapping e SS7 #

Per il 2FA via SMS: l’attaccante convince l’operatore telefonico a trasferire il numero della vittima su una sua SIM. Poi riceve tutti gli SMS della vittima inclusi gli OTP.

Fuori scope per un pentest web tradizionale, ma rilevante in:

  • Assessment di sicurezza completi
  • Social engineering assessment
  • Contesti in cui il cliente usa SMS-OTP per sistemi critici (banche, crypto)

Tecnica 10 — Phishing MFA con Proxy Trasparente (AiTM) #

L’attaccante crea un sito di phishing che fa da proxy trasparente tra la vittima e il sito reale (Adversary-in-the-Middle). La vittima inserisce le credenziali e completa il 2FA regolarmente sul sito falso, ma l’attaccante — che sta proxando in tempo reale il sito vero — intercetta il session cookie emesso subito dopo. Il secondo fattore non viene “rotto”: semplicemente non serve più, perché quello che conta ormai è il cookie di sessione post-autenticazione.

text
Vittima → [proxy phishing / Evilginx] → sito reale
            ↑                             ↑
         cattura                    la vittima autentica
         il cookie                  normalmente, 2FA incluso

Flusso AiTM: Evilginx tra vittima e sito reale

Tool di riferimento: Evilginx, framework open source per dimostrare AiTM phishing in engagement autorizzati. Setup, phishlet e workflow completo: Evilginx2: Bypass 2FA con Phishing Proxy. Versione aggiornata con focus su detection (in inglese): Evilginx 3: AiTM Phishing e MFA Bypass. Panoramica più generale sul phishing come vettore di initial access: Phishing: Tecniche, Tipologie e Difese.

Il cookie rubato in questo modo è a tutti gli effetti un session hijacking post-autenticazione — il 2FA non viene “rotto”, diventa semplicemente irrilevante.


Tecnica 11 — Referer Header Bypass #

Alcune applicazioni “verificano” di essere arrivate dal passo 2FA controllando solo l’header Referer della richiesta, invece di un flag di sessione server-side.

bash
curl "https://target.com/dashboard" \
  -H "Referer: https://target.com/verify-2fa" \
  -b cookies.txt
# Se risponde 200 invece di redirect a /verify-2fa → basta falsificare
# da dove sembri arrivare

Tecnica 12 — Token/OTP Leak nella Response #

A volte il codice OTP (o un token equivalente) finisce, per errore di sviluppo o debug lasciato in produzione, dentro la risposta della request che lo genera — non solo in quella di verifica.

bash
curl -X POST "https://target.com/api/2fa/send-otp" \
  -H "Cookie: session=SESSION_HALF_AUTH"
# Guarda l'intero body della risposta, non solo lo status code
# Cerca campi tipo: debug_otp, test_code, dev_otp, otp_hint

Se alla creazione dell’account arriva un’email con un link “verifica il tuo indirizzo” che logga direttamente l’utente senza richiedere il secondo fattore, chi ha accesso a quella casella (o intercetta il link) entra senza mai passare dal 2FA.

Come testare: crea un account, attiva il 2FA, poi controlla se il link di verifica email (o un link “conferma nuovo dispositivo”) autentica direttamente senza chiedere l’OTP.


Tecnica 14 — CSRF per Disabilitare il 2FA #

Se l’endpoint che disattiva il 2FA (es. POST /api/2fa/disable) non ha protezione CSRF (token anti-CSRF valido, cookie SameSite=Strict/Lax), una vittima autenticata che visita una pagina malevola può ritrovarsi il 2FA disattivato a sua insaputa, senza che l’attaccante debba conoscere password o OTP.

Come testare: verifica se /2fa/disable accetta la request senza token CSRF e senza richiedere la password/OTP corrente come conferma.


Tecnica 15 — Sessioni Non Invalidate Dopo l’Attivazione del 2FA #

Quando un utente attiva il 2FA (magari perché sospetta un accesso non autorizzato), tutte le sessioni già attive create PRIMA dell’attivazione dovrebbero essere terminate. Se non lo sono, un attaccante che ha già una sessione valida (rubata prima) resta dentro anche dopo che la vittima ha “messo in sicurezza” l’account.

Come testare: login su due dispositivi, attiva il 2FA da uno, verifica se l’altro dispositivo resta ancora loggato.


Tecnica 16 — Endpoint/API Version Legacy #

Se l’applicazione ha subito un refactor e oggi il flusso 2FA passa da /api/v2/verify-otp con tutte le protezioni, controlla se /api/v1/verify-otp (o un endpoint usato dalla vecchia app mobile) esiste ancora — spesso mantenuto per retrocompatibilità e senza le stesse protezioni di rate limiting o validazione.

bash
curl -X POST "https://target.com/api/v1/verify-otp" \
  -H "Cookie: session=SESSION_HALF_AUTH" \
  -d '{"otp":"000000"}'

Tecnica 17 — Decoy Requests contro il Rate Limiting #

Alcune implementazioni azzerano il contatore dei tentativi falliti ogni volta che l’utente chiede un nuovo invio del codice (“Rinvia codice”). Puoi sfruttarlo per bruteforzare indefinitamente: mandi un batch di tentativi fino quasi al limite, poi triggeri un resend, e il contatore riparte da zero.

text
1. Manda 15 OTP sbagliati (limite presunto: 20)
2. Chiama /api/2fa/resend-otp
3. Il contatore si azzera?
4. Manda altri 15 OTP sbagliati
5. Ripeti → brute force senza mai triggerare il blocco reale

Tecnica 18 — Remember Me / Trusted Device Abuse #

Molte app offrono “Ricorda questo dispositivo per 30 giorni” dopo il primo 2FA riuscito, salvando un cookie tipo trusted_device_id o remember_device=true. Se quel cookie è prevedibile, non firmato o non legato in modo forte al dispositivo (solo un valore booleano o un ID incrementale), copiarlo o indovinarlo basta per saltare il 2FA su ogni login successivo.

Come testare:

bash
# Attiva 2FA, completa il flusso, spunta "ricorda questo dispositivo"
curl -v "https://target.com/login" -c cookies.txt 2>&1 | grep -i "set-cookie"
# Cerca: trusted_device, remember_device, device_token

# Prova a riusare quel valore da un'altra sessione senza mai passare dal 2FA
curl "https://target.com/dashboard" \
  -H "Cookie: trusted_device_id=VALORE_COPIATO; session=NUOVA_SESSIONE_HALF_AUTH"

Controlla anche se il valore è un booleano decodificabile (remember_device=true dentro un JWT o un cookie non firmato) — se lo è, impostarlo manualmente bypassa il 2FA per qualunque account.


Tecnica 19 — Claim MFA Manipolabile nel JWT #

Se l’app usa JWT per lo stato di autenticazione, il completamento del 2FA è spesso tracciato come claim nel token stesso: "mfa":false, "mfa_completed":false, oppure "amr":["pwd"] (senza "otp"/"mfa" nell’array). Se il JWT non è firmato correttamente (algorithm none, secret debole, JWK confusion) puoi modificare quel claim direttamente.

bash
# Decodifica il JWT dalla request post-login
jwt_tool <TOKEN> -T
# Cerca claim tipo: mfa, mfa_completed, amr, 2fa_verified, auth_level

# Se l'algoritmo è manipolabile o il secret è debole:
jwt_tool <TOKEN> -X a                                          # test alg none
jwt_tool <TOKEN> -C -d /usr/share/wordlists/rockyou.txt        # crack secret debole
# Poi modifica mfa_completed:false → true e ri-firma

Approfondimento completo sulle vulnerabilità JWT: 10 Attacchi JWT per Ethical Hacker.


Tecnica 20 — Bypass del 2FA via OAuth/SSO #

Se l’app supporta sia login locale (con 2FA obbligatorio) sia “Accedi con Google/Microsoft/GitHub”, e l’account OAuth della vittima è già collegato, il flusso SSO spesso salta completamente il 2FA nativo — anche se il pannello mostra “2FA attivo e obbligatorio”.

text
Login locale                          → 2FA richiesto
Login con Google (account collegato)  → 2FA MAI richiesto

Come testare: collega un account OAuth di test, attiva il 2FA nativo, poi prova il login via SSO invece che via password — verifica se ti porta dentro senza mai chiedere il secondo fattore. Compromettere l’account OAuth della vittima (o il flusso di autorizzazione) diventa così una via alternativa completa al 2FA dell’app target.


Tecnica 21 — Race Condition sulla Verifica OTP #

Molti backend eseguono “verifica codice → crea sessione → invalida OTP” come tre operazioni separate, non atomiche. Mandando decine di richieste di verifica in parallelo con lo stesso OTP valido, alcune possono superare il controllo prima che il codice venga marcato come già usato.

bash
# Con un OTP valido, manda 50 richieste in parallelo
for i in $(seq 1 50); do
  curl -s -X POST "https://target.com/api/verify-otp" \
    -H "Cookie: session=SESSION_HALF_AUTH" \
    -d '{"otp":"482916"}' &
done
wait
# Verifica se vengono generate più sessioni/token per lo stesso, singolo OTP

La stessa logica si applica ai contatori di rate limit non atomici (Tecnica 3). Approfondimento su race condition e altre vulnerabilità sottovalutate: Misc & Infrastructure Attacks.


Tecnica 22 — Session Fixation sulla Sessione Half-Authenticated #

Se il session ID assegnato in stato “half-auth” (prima del 2FA) resta identico dopo il completamento del secondo fattore — invece di essere rigenerato — un attaccante che è riuscito a fissare quel session ID nel browser della vittima eredita una sessione completamente autenticata senza mai inserire l’OTP.

bash
curl -v "https://target.com/login" 2>&1 | grep -i "set-cookie"
# Nota il session ID PRIMA del 2FA

curl -v "https://target.com/verify-otp" -b "session=STESSO_ID" 2>&1 | grep -i "set-cookie"
# Se il session ID non cambia dopo la creazione della sessione completa → session fixation

Tecnica 23 — API Mobile e WebSocket Senza Enforcement MFA #

Le app mobile spesso parlano con endpoint dedicati (/mobile/, /api/m/, header X-App-Version) sviluppati separatamente dal flusso web — e a volte il 2FA non è stato portato su quel path. Lo stesso vale per dashboard sbloccate via WebSocket dopo il login: se il messaggio di autorizzazione (es. {"authenticated":true}) è deciso lato client e non ri-verificato a ogni messaggio, puoi bypassare il 2FA aprendo direttamente la connessione WS con una sessione half-auth.

Come testare: ripeti i test delle Tecniche 1 e 2 contro ogni endpoint /mobile/ o /api/v*/ trovato analizzando il traffico dell’app mobile o il bundle JS, e verifica se un handshake WebSocket accetta una sessione non ancora 2FA-completata.


Tecnica 24 — Il Reset Password Bypassa il 2FA #

Pattern comune in produzione: il flusso di reset password non richiede il secondo fattore al login successivo, anche su account con 2FA “obbligatorio”. Se riesci a triggerare un reset password (vedi Password Reset Attack per host header poisoning e tecniche correlate), il login post-reset ti fa entrare senza mai chiedere l’OTP.

text
1. Chain: Host header poisoning → cattura link di reset
2. Reset password della vittima
3. Login con la nuova password
4. Il 2FA "obbligatorio" non viene richiesto → account takeover completo

Questo è un account takeover a tutti gli effetti, anche se sulla carta il 2FA risultava attivo.


Difesa: Come Blindare un’Implementazione 2FA #

Ogni tecnica sopra corrisponde quasi sempre a un controllo mancante lato server. Lato blue team/sviluppo, questi sono i punti che chiudono la maggior parte dei bypass.

VulnerabilitàMitigazione
OTP riusabile (Tecnica 4)Invalida il codice subito dopo l’uso
Brute force OTP (Tecnica 3)Rate limit per account + lockout progressivo
Direct navigation (Tecnica 2)Flag di sessione mfa_completed verificato server-side
Response manipulation (Tecnica 1)Decisione di accesso mai basata su un campo client-side
Backup code deboli (Tecnica 7)RNG sicuro, monouso, notifica all’uso
Remember me abuse (Tecnica 18)Token firmato, legato a device fingerprint, scadenza reale
JWT claim MFA manipolabile (Tecnica 19)Algoritmo forte (RS256/ES256), claim verificati server-side
OAuth/SSO salta il 2FA (Tecnica 20)Step-up MFA anche sul flusso SSO, non solo su quello locale
Race condition su verify-otp (Tecnica 21)Lock/transazione atomica su verifica + invalidazione
Session fixation half-auth (Tecnica 22)Rigenera il session ID dopo ogni step di autenticazione
CSRF su disable-2FA (Tecnica 14)Token anti-CSRF + riconferma password/OTP
Reset password salta il 2FA (Tecnica 24)Il 2FA resta obbligatorio anche dopo un reset password

Stato di sessione esplicito, non implicito. Non basta creare una sessione al login: serve un flag verificato ad OGNI request verso endpoint protetti (es. session.mfa_completed = true), impostato SOLO dopo la verifica server-side del secondo fattore. Se manca questo flag, ogni endpoint deve rifiutare la request — la protezione non può essere un semplice redirect lato frontend (Tecniche 1, 2, 11).

Rate limiting per account/sessione, non solo per IP. Il contatore va legato al target (account o sessione), altrimenti rotazione di IP o header X-Forwarded-For lo aggirano. Usa backoff esponenziale e NON azzerare il contatore quando l’utente chiede un resend del codice (Tecniche 3, 17).

OTP monouso e a scadenza reale. Invalida il codice appena usato con successo, anche se la request arriva dopo un tentativo già scaduto. Sui TOTP, mantieni una finestra di tolleranza minima (±1 step, non minuti) per il clock skew (Tecniche 4, 5).

Backup code robusti e monouso. Generati con RNG sicuro, abbastanza lunghi da non essere bruteforzabili, invalidati dopo l’uso, e con notifica all’utente (email/push) ogni volta che uno viene consumato (Tecnica 7).

Re-autenticazione per azioni sensibili. Disabilitare il 2FA, cambiare email/telefono di recupero, o rigenerare i backup code devono richiedere SEMPRE la password corrente + un OTP valido — mai solo una sessione attiva — e l’endpoint deve avere un token anti-CSRF valido (Tecnica 14).

Invalidazione sessioni al cambio 2FA. Attivare, disattivare o modificare il metodo 2FA deve terminare tutte le altre sessioni attive sull’account, tranne quella corrente (Tecnica 15).

Nessuna decisione di sicurezza lato client. La verifica del secondo fattore, la creazione della sessione completa e il controllo di accesso alle risorse protette devono avvenire ed essere ri-verificate server-side ad ogni richiesta — mai fidarsi di un campo success: true/false nella risposta per decidere se mostrare la dashboard (Tecnica 1).

Remember me legato al device, non a un booleano. Il token “dispositivo fidato” va firmato, associato a un fingerprint del device (non solo a un ID) e con scadenza reale — mai un semplice flag booleano decodificabile (Tecnica 18).

Claim di autenticazione firmati, non solo presenti. Se lo stato MFA vive in un JWT, l’algoritmo deve essere forte (RS256/ES256 con chiave privata protetta) e ogni claim critico (mfa, amr) va ri-validato server-side, non solo letto dal token (Tecnica 19).

Step-up MFA anche sul flusso OAuth/SSO. Se il 2FA è obbligatorio per il login locale, deve esserlo anche per chi entra via provider esterno collegato — altrimenti l’SSO diventa la via più semplice per bypassarlo (Tecnica 20).

Operazioni atomiche sulla verifica OTP. Verifica, creazione sessione e invalidazione del codice vanno eseguite in una singola transazione con lock, non come tre step separati attaccabili in parallelo (Tecnica 21).

Rigenera il session ID a ogni step di autenticazione. Il session ID pre-2FA non deve mai sopravvivere identico dopo il login completo — questo chiude sia la session fixation sia buona parte dei problemi di sessione ibrida (Tecnica 22).

Contro il phishing AiTM (Evilginx e simili). Il 2FA “classico” (OTP, TOTP, push) non ferma un attacco Adversary-in-the-Middle: la vittima lo completa regolarmente, l’attaccante ruba il cookie di sessione subito dopo. Le difese che funzionano davvero:

  • FIDO2/Passkey — il secondo fattore è vincolato all’origine (dominio): un dominio di phishing non riesce a completarlo, a differenza di OTP e push che l’utente può “consegnare” senza accorgersene.
  • Token binding / Conditional Access basato su device (es. Entra ID, Google Advanced Protection) — un cookie rubato non è riutilizzabile da un dispositivo non riconosciuto.
  • Monitoraggio degli identity log — un IP che completa il login diverso dall’IP che usa la sessione subito dopo è un indicatore forte di sessione rubata.

Approfondimento tecnico completo su attacco e detection: Evilginx 3: AiTM Phishing e MFA Bypass.

Logging e monitoraggio. Logga ogni tentativo di verifica 2FA (esito, IP, user agent, timestamp). Alert su pattern anomali: molti fallimenti seguiti da un successo da un IP diverso, resend eccessivi in poco tempo, backup code usato subito dopo un fallimento OTP.


Workflow Completo da Pentester #

Quando trovi un’applicazione con 2FA, segui questo ordine:

Workflow pentest 2FA bypass, step 0-10

text
Step 0 — Fingerprint del tipo di 2FA
  → SMS, email, TOTP, push, backup code o passkey?
  → Determina quali tecniche hanno senso provare (vedi sezione dedicata sopra)

Step 1 — Direct navigation
  → Fai login (half-auth), salta il 2FA, prova /dashboard /account /admin direttamente
  → È la tecnica più veloce e spesso funziona

Step 2 — OAuth/SSO check
  → Se l'app supporta login via Google/Microsoft/GitHub, prova quel flusso invece della password
  → Test rapido, alto impatto: spesso salta il 2FA nativo anche se "obbligatorio" (Tecnica 20)

Step 3 — Response manipulation
  → Burp Repeater: manda OTP sbagliato, modifica la response da false a true
  → Forward e vedi se il browser ti porta dentro

Step 4 — User parameter tampering
  → Guarda la request del 2FA: c'è user_id, email, o account nel body?
  → Sostituisci con l'ID della vittima usando il tuo OTP valido

Step 5 — Rate limit check
  → Manda 20 richieste rapide con OTP sbagliati, vieni bloccato?
  → No blocco → brute force fattibile (specie se OTP a 4 cifre)
  → Blocco per IP → prova X-Forwarded-For rotation
  → Prova anche il resend: azzera il contatore?

Step 6 — OTP reuse
  → Usa un OTP valido, fai logout, rifai login, riusa lo stesso OTP

Step 7 — OTP scaduto
  → Ottieni un OTP, aspetta 2-3 minuti, prova a usarlo

Step 8 — Backup code
  → Prova codici backup prevedibili o brute force se spazio limitato

Step 9 — Logica avanzata
  → Referer header, endpoint API legacy (v1 vs v2), CSRF su disable-2fa,
    sessioni non invalidate dopo attivazione, token leak nella response
    di invio codice, link di verifica email, remember-me/trusted device,
    claim MFA nel JWT, race condition su verify-otp, session fixation
    su half-auth, endpoint mobile/WebSocket, reset password che salta il 2FA

Step 10 — Documenta come vettore SE non bypassabile
  → MFA fatigue possibile? SMS-OTP = SIM swap possibile? AiTM/phishing proxy possibile?
  → Raccomanda FIDO2/hardware key se disponibile

Checklist #

text
FLUSSO E LOGICA
☐ Direct navigation: login → salta 2FA → /dashboard accessibile?
☐ Response manipulation: OTP sbagliato → modifica response → accesso?
☐ User parameter: user_id/email nel body della verifica? → sostituisci
☐ Logout + rilogin con stesso OTP → OTP non invalidato?
☐ OTP vecchio di 2+ minuti ancora accettato?
☐ Referer header falsificato → bypass del redirect?
☐ Endpoint API v1/legacy ancora attivo e meno protetto?
☐ Token/OTP leak nella response di invio codice?
☐ Link di verifica email logga senza richiedere 2FA?
☐ CSRF su /2fa/disable senza richiesta di password/OTP?
☐ Sessioni multi-device non invalidate dopo attivazione 2FA?
☐ Cookie "remember device" prevedibile/non firmato?
☐ JWT con claim mfa/mfa_completed manipolabile (alg none, secret debole)?
☐ Login via OAuth/SSO salta il 2FA nativo?
☐ Richieste parallele su verify-otp → race condition?
☐ Session ID pre-2FA identico dopo il login completo (fixation)?
☐ Endpoint /mobile/ o WebSocket senza enforcement MFA?
☐ Reset password → login successivo salta il 2FA?

RATE LIMITING
☐ 20 tentativi falliti → nessun blocco?
☐ X-Forwarded-For variabile bypassa il blocco per IP?
☐ Blocco per sessione o per IP? (test con IP diverso)
☐ Resend del codice azzera il contatore dei tentativi?
☐ OTP a 4 cifre? → 10.000 combinazioni → brute force rapido

BACKUP CODE
☐ Backup code con spazio limitato (brute forceable)?
☐ Backup code funziona anche senza 2FA abilitato?
☐ Backup code sequenziale o prevedibile?
☐ Backup code esfiltrabile via CORS/XSS al momento della generazione?

ACCOUNT TAKEOVER
☐ Chain: user_id tamper → verifica tuo OTP per account admin → ATO?
☐ Chain: bypass direct nav → accesso senza 2FA → ATO se hai credenziali?
☐ AiTM/phishing proxy testabile in awareness assessment autorizzato?

DOCUMENTAZIONE
☐ Screenshot del bypass step by step
☐ Dimostrazione accesso all'account target
☐ Impact statement: tipo di dati accessibili, privilegio account

DIFESA (lato sviluppo/blue team)
☐ Flag di sessione mfa_completed verificato ad ogni request protetta?
☐ Rate limit legato ad account/sessione, non solo IP?
☐ Disable-2FA richiede password+OTP corrente e token CSRF?
☐ Sessioni invalidate al cambio 2FA?
☐ Logging su tentativi 2FA con alert su pattern anomali?

FAQ #

Il 2FA via SMS è sicuro? È meglio di niente, ma è il più debole. Vulnerabile a SIM swapping, SS7 interception, phishing proxy. Per sistemi critici raccomanda sempre TOTP (Google Authenticator) o meglio FIDO2/hardware key (YubiKey).

Il 2FA blocca il phishing? Blocca il phishing “classico” (furto di sola password). Non blocca un attacco Adversary-in-the-Middle come Evilginx: lì la vittima completa il 2FA regolarmente sul sito falso, e l’attaccante ruba il cookie di sessione dopo. Solo FIDO2/Passkey e il token binding legato al dispositivo fermano davvero questo scenario.

Il direct navigation bypass funziona sempre? No. Dipende dall’implementazione. Se il server usa un flag nella sessione che viene verificato ad ogni request protetta (session.2fa_completed = true) e non crea questo flag finché il 2FA non è completato — il bypass non funziona. Ma molte applicazioni creano la sessione completa già dopo il login e usano il 2FA solo come “gate” che il frontend gestisce.

Come faccio a sapere se c’è user_id nella request del 2FA? Burp Suite Proxy History. Filtra le request verso /verify, /2fa, /otp. Guarda il corpo di ogni POST. Cerca qualsiasi campo che identifichi l’utente: user_id, email, username, account, uid.

Response manipulation: come intercetto la response in Burp? Proxy → Options → attiva “Intercept responses based on the following rules”. Poi nel Proxy tab, quando arriva la response, puoi modificarla prima che il browser la riceva. Oppure usa il Repeater: manda la request con OTP sbagliato, nota la response, pensa a come modificarla, poi usa “Match and Replace” in Proxy per farlo in automatico su tutte le request.

Cosa devo controllare per primo lato sviluppo se voglio blindare il mio 2FA? Il flag di sessione server-side (mfa_completed) verificato su ogni endpoint protetto, e la re-autenticazione obbligatoria per disabilitare il 2FA. Sono i due controlli che, da soli, chiudono la maggior parte dei bypass logici di questa guida.

Che differenza c’è tra MFA e 2FA? Il 2FA (Two-Factor Authentication) è un caso specifico di MFA (Multi-Factor Authentication): richiede esattamente due fattori. MFA è il termine generico e può richiederne anche di più (es. password + TOTP + verifica biometrica). Nella pratica, negli articoli e nei prodotti, i due termini vengono usati quasi come sinonimi.

Perché FIDO2/Passkey resiste al phishing dove OTP e push falliscono? Perché la chiave crittografica generata da FIDO2 è legata all’origine (il dominio) a livello di protocollo (WebAuthn). Un sito di phishing su un dominio diverso non riesce a completare la challenge, anche se la vittima interagisce attivamente con la pagina falsa — a differenza di OTP e push, che l’utente può “consegnare” senza che il protocollo se ne accorga.

È possibile bruteforzare Google Authenticator? Il codice TOTP generato da Google Authenticator è a 6 cifre e cambia ogni 30 secondi: bruteforzarlo nella finestra di validità (1.000.000 di combinazioni in 30s) è impraticabile in condizioni normali. L’attacco realistico non è sul codice in sé, ma sull’implementazione lato server: assenza di rate limiting, finestre di clock skew troppo ampie, o furto del seed segreto durante l’enrollment.

Come funziona il TOTP? TOTP (RFC 6238) genera il codice combinando un segreto condiviso (scambiato una sola volta, di solito via QR code) con il timestamp corrente diviso in step da 30 secondi, tramite HMAC. Server e app calcolano lo stesso codice in modo indipendente, senza bisogno di comunicazione di rete: è per questo che TOTP funziona anche offline.

Qual è la severità in un report? Bypass completo del 2FA che porta ad accesso non autorizzato → Critical. Brute force OTP senza rate limiting → High. OTP riusabile o con finestra di validità troppo larga → Medium/High. CSRF su disable-2fa → High/Critical a seconda dell’impatto.


Risorse #

#MFA bypass #OTP bypass #TOTP bypass #SIM swapping # MFA fatigue #2FA bypass

lascia un messaggio

Non sono un robot