Home  ›  All Blogs  ›  manmeet  › 

Graphql Exploitation - Part 1- Understanding Graphql & Enumeration of Graphql Schema

    manmeet
    1-March-2021

graphql_blog.png

Graphql Exploitation - Part 1- Understanding Graphql & Enumeration of Graphql Schema

This blog will give you a good look at Graphql and necessary information that will help you in understanding how graphql can be so vulnerable if not deployed properly.

Introduction

We know that REST APIs are worldwide used as the best way to implement backends. However, REST APIs have some disadvantages that Facebook understood and finally developed “GRAPHQL”.

A few of the disadvantages of REST APIs are:

  • Not able to dictate what is needed in response. Which leads to unnecessarily fetching of data and utilizing high bandwidth.
  • To fetch different types of data, developers have to develop a lot of different endpoints, which will also increase the complexity of the application.

Graphql is a solution to the above problems. In Graphql the client/ frontend dictates what specific data is needed for that particular request. Moreover, there is only one API endpoint in use to receive all types of requests, so no need of creating different APIs.

Source: https://dev.to/javinpaul/5-best-courses-to-learn-graphql-in-2020-2fo5

If we talk about a proper definition of Graphql we can refer to GraphQl.org, which is the official site of Graphql documentation. It is recommended to go through this site to understand things more briefly. According to the site,

Graphql is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. Graphql isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.

There is a lot of things associated with Graphql implementation and usage. But through this blog, we will try to understand the important parts of Graphql. For understanding the proper implementations kindly refer to the official tutorial for Graphql at GraphQl.org.

Graphql Components

The GraphQl contains 2 main components :

  1. Graphql Server-Side Component - As the name suggests, it refers to the use of Graphql at the back-end of the application where Graphql resolves the queries/mutations/subscriptions and provides the requested data/operation. To receive requests Graphql can have a single API endpoint (eg. /graphql). The backend server could be in any language/framework as Graphql has supporting libraries and modules for most of the highly used languages (refer to Code libraries for Graphql). The Server-side component contains 3 main things:

    • Query - It defines the different operations that can be done. Every query has an operation type.
    • Resolver - It is a part of code that helps to direct conversion of the operation into data.
    • Schema - It defines the available fields, field types, attributes and attribute types for different operations(query, mutation, and subscription). It also provides the documentation of various objects and types getting used in the application. While the exploitation of GraphQl we also try fetching schema.
  2. Graphql Client-Side Component - Graphql client is the part of the frontend or any other application that wants to interact with the backend to do some operations. It will interact with Graphql API to send and receive data according to query/mutations/subscriptions passed in the request. Like the graphql server component, the client also uses dedicated Graphql libraries (Code libraries for Graphql).

Graphql Operation Types

Kindly note, whatever data is in the “query” parameter of the request of Graphql, is generally said to be a query but depending upon the unit of operation requested we can distinguish the operation types.

Graphql contains 3 types of operation types and called with their respective keywords :

  1. Query - for fetching data using specifically defined query operations.

  2. Mutations - for modifying any data (create/update/delete) in database or data source (eg. xml) using operations

  3. Subscriptions - for receiving real-time messages from the backend. Normally worked like web-socket and continuously ping backend.

Before going further it is recommended to go through this awesome explanation of operations and operation types.

Graphql Request Structure

This is very important to see things clearly before we jump into the next sections. Graphql request structure contains below things:

  • Operation Type - we have discussed various operation types above. The operation type is always mentioned at the start of the query. If no operation type is mentioned the default operation type is “query”.

This means ,

both queries above will give the same output and are of the “query” type. Same way, we can write queries of mutation and subscription type by adding the “mutation” and “subscription” keywords at the start of queries.

  • Operation Name - Suppose in a web application frontend, there are 1000 functions in JavaScript which fetch the same data using the same query, but one function is not able to request data and there could be some possible error on the client-side. Developers have to go through logs to find out which query is not called. But because all 1000 functions is using calling the same query, it is very difficult to identify which javascript function is not working just by looking at logs.

There is another case, let suppose a developer wants to use dynamic values in the query using variables so that a single query can be used dynamically.

He/she can resolve both things by adding “Operation Name”. Just by giving a name to the operation, we can distinguish queries and even pass variables to the fields inside the query. Graphql doesn’t care what operation name the frontend is giving. It is good practice for Developers to use operation names in queries.

The operation name is added after the operation type. The below image is representing how the operation name is written in Graphql query and how the request looks if intercepted.

We can use Operation Name even there is no variable declared just to identify queries.

  • Variables - Variables are needed to use query dynamically.

  • Selection Set - As Graphql gives us the ability to choose what fields we want from it, we can pass those field names which we want in response, in curly brackets ({}) as JSON objects.

Selection set literarily tells Graphql resolver what all fields are needed in response. If in the above query “name” is removed from the selection set of the “veterinary” field then we will get a response without the name of “veterinary”.

Identifying Graphql

There are various ways we can know if Graphql is in use:

Observing Requests and Responses

We can very easily identify the use of graphql just by analyzing the requests going to the server. The typical request should look like this.

The request contains the “query” parameter either in GET or POST method. The “query” parameter contains the actual operation type, selection sets, and sometimes operation name. Sometimes, arguments are also passed in the query and we can find other parameters in the JSON body as shown below.

All this is enough to ensure ourselves that Graphql is in use.

By Generating Error

Try to add anything random in the query or try to use the wrong operations in the query field. use

{
"query": "query {\n__schema}\n"
}

It will throw some error like this.

observe the error, it gives us a clear indication that Graphql is getting used for this API.

Presence of Graphiql

Graphiql is a web IDE created for developers to run Graphql queries as well as observe the responses from the backend. Graphiql looks like this.

It comes as a package with libraries of Graphql. Kindly note that this interface is normally displayed when the developer enables it on some API endpoint, generally it is found in the below locations:

/graphql
/graphiql
/graphql/console
/graphql.php
/graphiql.php
/explorer
/altair
/playground
/graphql-explorer
/graphiql/

It is not necessary that Graphiql will always available on one of the above endpoints. A developer can set custom endpoints for Graphiql. In that case, to find Graphiql we can try brute-forcing endpoints. Some web frameworks like Django, when running in Debug mode can display us all the endpoints currently running while showing a default error message and then we can look for endpoint/s which are running Graphiql.

Enumerating Graphql Schema

Enumerating Graphql schema is important as it will tell us what all operations are available and what output we can expect if those operations are executed. This will help us to try many types of logical unauthorized attacks on listed operations. This step is not needed when we are targeting database directly (injection attacks) or other server attacks (DOS). It also tells us the fields and attributes which are expected for different queries, mutations, and subscriptions. So there are some cases and techniques which we can use to get the Graphql schema,

Using Graphiql

Graphiql interface provides us a nice representation of the schema.

Using introspection query

Many a time we don’t get graphiql to get schema, in that case, we can use a normal graphql request and pass an introspection query in it that will fetch the whole schema in response. Below is the introspection query:

{__schema{queryType{name},mutationType{name},types{kind,name,description,fields(includeDeprecated:true){name,description,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},isDeprecated,deprecationReason},inputFields{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},interfaces{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},enumValues(includeDeprecated:true){name,description,isDeprecated,deprecationReason,},possibleTypes{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}}},directives{name,description,locations,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue}}}}

This query will give us the whole schema in one shot.

there is a second type of introspection query with fragments

\n  query IntrospectionQuery {\n    __schema {\n      queryType { name }\n      mutationType { name }\n      subscriptionType { name }\n      types {\n        ...FullType\n      }\n      directives {\n        name\n        description\n        locations\n        args {\n          ...InputValue\n        }\n      }\n    }\n  }\n\n  fragment FullType on __Type {\n    kind\n    name\n    description\n    fields(includeDeprecated: true) {\n      name\n      description\n      args {\n        ...InputValue\n      }\n      type {\n        ...TypeRef\n      }\n      isDeprecated\n      deprecationReason\n    }\n    inputFields {\n      ...InputValue\n    }\n    interfaces {\n      ...TypeRef\n    }\n    enumValues(includeDeprecated: true) {\n      name\n      description\n      isDeprecated\n      deprecationReason\n    }\n    possibleTypes {\n      ...TypeRef\n    }\n  }\n\n  fragment InputValue on __InputValue {\n    name\n    description\n    type { ...TypeRef }\n    defaultValue\n  }\n\n  fragment TypeRef on __Type {\n    kind\n    name\n    ofType {\n      kind\n      name\n      ofType {\n        kind\n        name\n        ofType {\n          kind\n          name\n          ofType {\n            kind\n            name\n            ofType {\n              kind\n              name\n              ofType {\n                kind\n                name\n                ofType {\n                  kind\n                  name\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n

and that too will give the same result.

What If Fetching Schema Fails?

We have encountered this scenario few times when the introspection query fails to fetch schema or the introspection query is disabled. Then we are left with 2 things:

  1. Use the known queries which are part of normal client requests and try to abuse them.
  2. Try guessing the field names, arguments, and argument types for different operations.

In the next part, we will use this gathered data to find possible vulnerabilities in Graphql

References

About Payatu

Payatu is a Research Focused, CERT-In impaneled Cybersecurity Consulting company specializing in security assessments of IoT product ecosystem, Web application & Network with a proven track record of securing applications and infrastructure for customers across 20+ countries.

Get in touch with us. Click on the get started button below.

Get to know more about our process, methodology & team!

Close the overlay

I am looking for
Please click one!