🎉 Lab Complete!

You forged a CSRF attack and bypassed token validation!

Next: File Upload Bypass →
← Back
WAPT / Lab 03 — CSRF Exploitation
INTERMEDIATE
Tasks

Cross-Site Request Forgery (CSRF) tricks an authenticated user's browser into sending an unwanted request to a site where they're already logged in — without their knowledge. The server receives what looks like a perfectly legitimate, authenticated request, so it acts on it.

💡
The key insight: Browsers automatically attach cookies to every request — including requests triggered by another site. If you're logged into your bank and you visit an attacker's page, that page can silently make your browser send a request to the bank — with your real session cookie attached.
CSRF Attack Flow
👤 Victim logged in
→
😈 Visits evil page
→
📤 Hidden request fires
→
🏦 Bank processes it
→
💸 Action taken!

When you log into a website, the server sets a session cookie in your browser. Every request your browser makes to that domain — regardless of which page triggered it — automatically includes that cookie. This is normal browser behaviour. CSRF abuses it.

🧩
Three conditions for CSRF to work:
1Victim is authenticated. They must be logged in and have a valid session cookie for the target site.
2Action relies on cookies. The server must use session cookies to authenticate the request — not something the attacker can't know, like a CSRF token.
3No unpredictable parameters. The request must be something the attacker can fully predict and forge — like a fixed transfer URL with known parameters.
<!-- Attacker's evil page --> <img src="https://bank.com/transfer?to=attacker&amount=5000"> <!-- Or with a hidden form that auto-submits --> <form action="https://bank.com/transfer" method="POST" id="f"> <input name="to" value="attacker"> <input name="amount" value="5000"> </form> <script>document.getElementById('f').submit()</script>
🚨
The victim sees nothing. The form submits invisibly in milliseconds. The image tag triggers silently. The bank gets a legitimate-looking POST request with a valid session cookie. Without CSRF protection, it approves it.

Students often confuse these two. The key difference: XSS injects code that runs in the victim's browser on the target site — the attacker controls what the victim's browser does on the legitimate site. CSRF makes the victim's browser send a request from a different site — the attacker doesn't need any code injection on the target, just a way to make the victim's browser send a forged request.

XSS
Attacker injects JS
into the TARGET site.
Victim's browser runs
the attacker's code
on the legit site.
CSRF
Attacker hosts a page
ELSEWHERE that tricks
the browser into sending
a request to the target
with real cookies.

CSRF can be used to transfer funds, change account email/password, make purchases, delete accounts, or perform any state-changing action a logged-in user can do. The attacker just needs to trick the victim into visiting a page — via a phishing link, a malicious ad, or even a forum post with a hidden image tag.

🏴
Real attacks: In 2008, a CSRF vulnerability in a major router brand allowed attackers to change DNS settings just by getting users to visit a page — silently redirecting all their traffic. Netflix had a CSRF bug that let attackers change account details. CSRF consistently appears in the OWASP Top 10.
❌ No Protection
POST /transfer
Cookie: session=abc
to=attacker&amt=5000

// Any site can forge this
✅ CSRF Token
POST /transfer
Cookie: session=abc
csrf_token=x9kP2mQz

// Token unknown to attacker

The standard fix is a CSRF token — a secret, random, per-session value embedded in every form. The server validates it on submission. Since the attacker's page is on a different origin, it cannot read the token from the legitimate site (Same-Origin Policy), so it cannot forge a valid request.

✅
Other defences: The SameSite cookie attribute (SameSite=Strict or Lax) tells browsers not to send cookies on cross-site requests. Origin/Referer header validation checks where the request came from. Modern frameworks include CSRF protection by default — always keep it enabled.
🎯
Mission: Work through three stages — understand how CSRF bypasses authentication, forge a hidden request from the "attacker's site", then bypass a broken token implementation. Collect two flags to complete the lab!
1
Observe the vulnerable bank — no CSRF protection
In Stage 1, log into the VulnerableBank as alice. Make a legitimate transfer. Watch the Request Log — what does the request look like? Notice there is no secret token — just a session cookie. Ask yourself: could another site send this exact same request?
2
Launch the CSRF attack from the "attacker's page"
Go to Stage 2. You are now on the attacker's page. Alice is still "logged in" — her session cookie is active. Click the button to simulate Alice visiting the malicious page. Watch what happens to her account — did the forged request succeed?
3
Collect Flag 1 — successful CSRF attack
Once the CSRF attack succeeds and Alice's balance changes, the first flag is revealed. Copy it and submit it in the flag box.
4
Bypass the "broken" CSRF token in Stage 3
Go to Stage 3. This version has a CSRF token — but the implementation is flawed. Inspect the token behaviour carefully. The server only checks whether a token field exists, not whether it's valid. What happens if you submit an empty or wrong token?
5
Collect Flag 2 — token bypass
Successfully bypass the broken token validation to unlock the second flag. Submit it to complete the lab!
💡
Hints guide your thinking — not your clipboard. Try each stage, read the request log carefully, then come back if you're stuck. The answer is in the details!
Think about what the browser automatically includes in every request to a domain.

When Alice logs in, the server gives her a session cookie. Her browser stores it and sends it with every subsequent request to that domain — even requests triggered by a completely different website.

The server sees: valid session cookie = trusted user. It doesn't ask "where did this request actually come from?"
Look closely at the Request Log after you do a legitimate transfer in Stage 1.

The request body contains to= and amount= — both values the attacker already knows. The only "authentication" is the session cookie, which the browser sends automatically.

This means an attacker can write a page that sends this exact same POST request. The browser will helpfully attach Alice's cookie without asking.
The attacker's page contains a hidden form that is pre-filled with the transfer details and set to auto-submit the moment the page loads.

Alice doesn't click anything, doesn't see anything — the page loads, the form submits, and VulnerableBank processes the transfer because the session cookie came along for the ride.

In Stage 2, click "Simulate Alice visiting the evil page" — this is what happens when Alice clicks a phishing link.
The server in Stage 3 checks:

if (isset($_POST['csrf_token'])) { // proceed }

Notice anything? It only checks whether the field exists — not whether the value is correct. A token that checks the presence of a field, not its secret value, is completely useless.

Think: what if you send any value as the token? Would the server accept it?
A real CSRF token must be:

1) Secret — generated server-side, not guessable
2) Tied to the session — different for every user
3) Validated properly — server checks the value, not just presence
4) Single use (ideally) — rotated after each form submission

The token in Stage 3 fails condition 3. In real-world code, always validate the token value against the session-stored value — never just check if the field exists.
🎬
Video Walkthrough
Watch our full step-by-step solution on YouTube — only after you've given it a proper try!
Watch on YouTube Subscribe — @WhiteFortressSecurity
http://vulnerable-bank.local/dashboard
Stage:

🏦 VulnerableBank

// logged in as: alice // no csrf protection

Balance: $10,000.00
Active Session
user: alice
cookie: sess_a8f2c...
balance: $10,000
csrf_tok:NONE ❌
📡 Request Log
Make a transfer to see the request...

😈 free-prizes.evil.com

// attacker-controlled page

<!-- Hidden in page source -->
<form action="http://bank.local/transfer"
     method="POST" id="x">
  <input name="to" value="attacker99">
  <input name="amount" value="5000">
</form>
<script>x.submit()</script>

🎁 You won a free iPhone! Click below to claim your prize!

Alice's Session (Still Active)
user: alice
cookie: sess_a8f2c...
balance: $10,000
origin: free-prizes.evil.com
📡 Forged Request Log
Click the button above to launch the attack...

🏦 VulnerableBank v2

// "csrf protected" — or is it?

Balance: $10,000.00
Server Token Check
user: alice
real_token: x9kP2mQzR7
submitted: —
check: waiting...
📡 Server Logic
if (isset($_POST['csrf_token'])) {
  // BUG: only checks if field exists!
  process_transfer();
} else {
  die("CSRF check failed");
}
🚩 Flag
wfa@lab ~ csrf-exploitation
White Fortress Academy — Lab Terminal ──────────────────────────── Type 'help' for commands
wfa@lab:~$
🚩 Flag