PRIMARY CATEGORY → WEB TECHNOLOGIES

Theory

GraphQL is a query language and runtime for APIs that allows clients to request exactly the data they need from a server.

Unlike traditional REST APIs, where multiple endpoints typically expose different resources, GraphQL commonly uses a single endpoint and lets the client define the structure of the requested data

<TARGET>/graphql
<TARGET>/api/graphql

GraphQL APIs are defined through a schema containing types, fields, queries and mutations, which the server resolves when processing client requests

Misconfigurations or insecure implementations can expose sensitive information, authorization flaws, excesive data access or other attack vectors


Enumeration

Identifying the GraphQL Engine

First, we can proceed as follows to identify which GraphQL engine is being used

Setup

git clone https://github.com/dolevf/graphw00f graphw00f
cd !$

Usage

python3 main.py --fingerprint --detect --target '<TARGET>'

Then, simply check the resource below, which provides more in-depth information about the identified GraphQL engine

GraphQL-Threat-Matrix

IMPORTANT

We should always check whether the backend is using a graphiql interface under its /graphql endpoint

Introspection

Introspection is a GraphQL feature that enables users to query GraphQL API about the structure of the backend system

Therefore, a user could use an introspection query to obtain all queries supported by the API schema

Introspection comes enabled by default on certain GraphQL engines, such as graphene

Zoom in

Types

All GraphQL Types supported by the backend server

All fields for a specific Type
  • Standard Type → OBJECT
  • Input Type → INPUT_OBJECT
Queries

All GraphQL Queries supported by the backend server

After enumerating them, we can call one of them as follows

allEmployees Query

Mutations

All GraphQL Mutations supported by the backend server

After enumerating them, we can carry out a mutation as follows

  • Standard Mutation

registerUser Mutation

All information

Types, fields and queries supported by the backend

Since the result of this query is quite large and complex, we can use GraphQL-Voyager to visualize the schema as an interactive graph

e.g.

Zoom in

To do so, simply access here, select CHANGE SCHEMA, go to INTROSPECTION section and paste the output of previous query

Zoom in

Auditing a GraphQL Endpoint

Automated

Setup

git clone https://github.com/dolevf/graphql-cop GraphQL-Cop
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install -r requirements.txt

Usage

python3 graphql-cop.py -t '<TARGET>'

Insecure Direct Object Reference

IDOR

Let’s suppose that we face a web application that carries out the query below to a GraphQL endpoint to retrieve information about the current logged-in user

Zoom in

The web app passes our username to the username parameter of the user field

Therefore, if we know valid usernames, we could try to request information about any of them, which would be an authorization flaw

Zoom in

However, the information we get is not sensitive at all. So, we could send an introspection query to list all existing fields for the userObject type

{ __type( name: \"UserObject\" ) { name fields { name type { name kind } } } }

Zoom in

And we have a password field

So, we can leverage the lack of authorization to retrieve this sensitive information for a specific user

Zoom in


SQL Injection

SQLi

Since GrapQL is a query language, it has to fetch data from some kind of storage, typically a database

So, as with any other web application, we could test for SQL Injection to see whether the given GraphQL API properly sanitizes the user input

Therefore, we should look for any GraphQL that requires or supports arguments, and analyze these arguments for potential SQL Injection

So, following the IDOR example, we have the following GraphQL query used by the web application in question to retrieve some information for a specific user

Zoom in

The given user is specified in the username parameter of the user field

With this in mind, we can test it for SQL Injection. If we enter a simple quote, we get the following error, which indicates that it’s vulnerable

Zoom in

Since the error is displayed in the response, it seems that we can proceed with an UNION-based approach to extract sensitive information

Zoom in