Pentesting GraphQL

GraphQL is an API to interact with other APIs. Instead of one request triggering multiple requests to different REST API’s, for example a database, a file server etc. GraphQL allows you to make one request to the GraphQL DPI which then interacts with the underlying architecture. An advantage of GraphQL is that you can ask for exactly what you want, being very specific without needing to make a more general query which may return a lot of data and then parsing through that data to display what you want.

To illustrate: with a regular API developers need to write many different endpoints such as

/users
/administrators
/v2/users/details/contact
/signup

With GraphQL all queries are sent to one endpoint /graphql which then interacts with other APIs to return data.

1.jpg

Interacting with GraphQL is done with POST queries to the GraphQL endpoint at /graphql. You ask for an object and its fields and the response is the value of those fields. Responses can be one of several scalar types which could be string, integer, array, or custom scalar types. A node is a object and an edge is the actions relating one node to another node. To illustrate with a social media example: a user is a node and a post is a node. Like is an edge because one node (User) interacts with another node (Post) with this edge (The User Liking the Post.)

2.jpg

We can see in the schema the various different types of objects.

3.jpg

Queries can also take arguments. Here the id: 1000 is the argument passed to the value “human.”

4.jpg

In GraphQL changing data is called a mutation. Here is an example of a mutation. The biggest problem with GraphQL is usually that everything is passed as untrusted data. However the schema is complicated and it takes a lot of manual work to find the holes which may be there.

5.jpg

To understand the schema of the GraphQL we can make a Introspection Query, this returns us the API docs - its like the Swagger file of the GraphQL. These files can be massive, for example the introspection query file of Github is 84,000 lines of schema.

Introspection Queries are enabled by default however they should be turned off if you are using a private API that requires authentication. If you are using a public API that you want other developers to build onto then it should be enabled. The possible endpoints for a GraphQL instance could be located at any off the following endpoints.

6.jpg

💡 GraphQL does not contain any built in authentication or authentication. It is up to the developer to implement this security layer themselves or implement libraries. Many times this can be misconfigured resulting in serious vulnerabilities!

Tools

GraphQL Voyager takes the response of the introspection query and builds in out visually to see what data is connected to what.

7.jpg

8.jpg

Shapeshifter - This tool will scan a GraphQL endpoint and attempt to create a list of valid queries based off of different scalar types. The outputted list of “response 200” queries can then be passed into repeater or sqlmap for further testing. https://github.com/szski/shapeshifter

Inql - An amazing tool that actually comes with a Burp extension! It enabled you to make an Introspection Query, display all the parameters, helps create the proper query syntax, and integrates with responder for further testing. There is also a command line version which contains a tool to generate cycles in the GraphQL code which could lead to Denial of Service.

Attacking

The three most common vulnerabilities present in GraphQL are the same as any other API:

  • IDOR
  • Authentication Bypass
  • Information Disclosure

The following are some examples of these attacks:

Bypassing authentication by requesting only the nested object as the root object itself.

9.jpg

Trying to send mutations may allow you to add or delete other users or write other data to the database.

10.jpg

SQL injection is also possible with in GraphQL. Add a ' or a * to the end of a query to check.

This is an example of Information Disclosure.

11.jpg

Explanation of the Query: We are requesting Class with arguments name and grades. Nested within grades we are requesting grade and comments and also user. User is nested within grades and within user is nested name.

The response we get is a clear example of Information Disclosure by returning too much information then should be allowed.

In conclusion, if you are using GraphQL at your company, make sure you are doing it correct or get your self a nice pentest to find out :)

--Credits for the images goes to Doyensec, InsiderPhd and Matt Szymanski