EXERCISE 1 — Building Level-1 (GET) and Level-2 (POST) payloads =============================================================== USE A LEGAL TARGET: OWASP Juice Shop, DVWA, or a PortSwigger Web Security Academy CSRF lab. Never a site you don't own. --- LEVEL 1: GET FORGERY (image tag) --- Suppose the app exposes a state-changing GET, e.g. DVWA-style: GET /vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change Payload (host on your own attacker page, then open it while logged into the app): WHAT MADE IT POSSIBLE: The endpoint CHANGES STATE on a GET request. An issues a credentialed GET, so the browser attaches the victim's session cookie and the password changes. The enabling property = "state change exposed over a safe method (GET)". --- LEVEL 2: POST FORGERY (auto-submitting form) --- Suppose the app changes email via POST /profile with body email=...:
Open this page while logged into the app; it auto-submits. WHAT MADE IT POSSIBLE: The POST endpoint authorizes the action using ONLY the session cookie -- it has NO anti-CSRF token (or doesn't validate one). Since a
sends a credentialed cross-site POST with a simple content type (no preflight), the browser attaches the cookie and the server accepts it. The enabling property = "cookie-only authorization, no unpredictable token required". OBSERVING IT: Watch DevTools -> Network when your payload page loads: you'll see the request go to TARGET with the Cookie header attached, and a 200/redirect showing the action succeeded. That is the forgery firing. KEY CONTRAST: Level 1 exploited a BUG (state change on GET). Level 2 exploited the DEFAULT (cookie-only auth with no token) -- which is why even correct POST endpoints need explicit CSRF defences (Chapter 5 onward).