Lab 13: Authentication Bypass Techniques

Objective

Attack a live authentication system from Kali Linux and bypass it using four different techniques:

  1. SQL Injection login bypass — use admin'-- and OR 1=1 to log in without a password

  2. Type juggling — exploit loose PHP-style comparison to bypass a password == 0 check with null

  3. Predictable reset token — brute-force a timestamp-based MD5 reset token

  4. MFA bypass — skip multi-factor authentication by omitting the field entirely

Every attack runs from Kali against a live Flask API — real SQL execution, real JWT tokens returned.


Background

Authentication bypass is one of the oldest and most impactful vulnerability classes. An attacker who bypasses authentication skips every downstream authorization check — they have full access to whatever that account could do.

Real-world examples:

  • 2019 Capital One — IAM misconfiguration; attacker bypassed intended auth flow via SSRF

  • 2023 Cisco IOS XE (CVE-2023-20198) — unauthenticated remote access via auth bypass; 50,000+ devices compromised in 48 hours

  • 2021 GitLab (CVE-2021-22205) — ExifTool XXE bypass led to unauthenticated RCE; 50,000+ servers exposed

  • 2020 SolarWinds Orion — hardcoded solarwinds123 password; no MFA = total bypass

OWASP coverage: A07:2021 (Auth Failures), A03:2021 (Injection)


Architecture

Time

45 minutes

Tools

Tool
Container
Purpose

curl

Kali

Send crafted HTTP requests

python3

Kali

Brute-force reset tokens, automate attacks

nmap

Kali

Service fingerprinting

gobuster

Kali

Enumerate auth endpoints


Lab Instructions

Step 1: Environment Setup — Launch the Victim Auth Server

📸 Verified Output:


Step 2: Launch the Kali Attacker Container

📸 Verified Output:


Step 3: SQL Injection Login Bypass — admin'--

📸 Verified Output:

💡 admin'-- works because -- is SQL's line comment. The query becomes SELECT * FROM users WHERE username='admin' — the AND password=... clause is erased. The database finds user admin and returns the row regardless of the password. Fix: always use parameterised queries — db.execute("... WHERE username=? AND password=?", (u, p)).


Step 4: Type Juggling — Bypass with null

📸 Verified Output:

💡 PHP's == operator is the root cause. In PHP, "0" == false, 0 == null, "" == false all return true. This happens because PHP converts both sides to the same type before comparing. If a stored password hash starts with 0e (e.g., MD5 of 240610708 is 0e462097431906509019562988736854), it's treated as scientific notation 0 × 10^... = 0, making any password that also hashes to 0e... match. Fix: always use === (strict equality) in PHP, and bcrypt/argon2 which never produce 0e output.


Step 5: Predict the Password Reset Token

📸 Verified Output:


Step 6: MFA Bypass — Omit the Field

📸 Verified Output:

💡 data.get('mfa_code') returns None when the field is absent — and the server treats None as "MFA not started" rather than "MFA missing". Fix: explicitly require the field — if 'mfa_code' not in data: return 401. Never use absence of a field to mean "skip this check". MFA must be verified positively, not conditionally.


Step 7: Chained Attack — SQLi + MFA Bypass

📸 Verified Output:


Step 8: Cleanup


Remediation

Attack
Root Cause
Fix

SQLi bypass

f-string query: f"...WHERE username='{u}'"

Parameterised: db.execute("...WHERE username=?", (u,))

Type juggling

Loose == comparison

Strict equality === (PHP) / bcrypt.checkpw() (Python)

Predictable token

MD5(username + timestamp)[:8]

secrets.token_urlsafe(32) — 256-bit CSPRNG, 15-min TTL

MFA bypass

if mfa is None: skip

if 'mfa_code' not in data: return 401 — require field explicitly

Further Reading

Last updated