Skip to content

Instantly share code, notes, and snippets.

@me0wday
Last active October 17, 2023 15:16
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save me0wday/69d5dfcdde0cbd094810b2ea4f4bc25a to your computer and use it in GitHub Desktop.
Save me0wday/69d5dfcdde0cbd094810b2ea4f4bc25a to your computer and use it in GitHub Desktop.
Blind Graphql Discovery to Altair Schema

Playing with GraphQL when introspection is disabled

Quick write up on extracting a GraphQL schema when introspection is disabled. Bits and pieces sourced from various sources. Successfully tested on an Apollo instance.

TLDR: Some GraphQL instances provide name autocomplete suggestions. Some peeps have written tools to automate the extraction process. (ref https://youtu.be/nPB8o0cSnvM).

1. Bruteforce schema without introspection

First step is using a tool called clairvoyance by @nikitastupin (https://github.com/nikitastupin/clairvoyance). I found the main repo to lack error handling and support for additional features such as proxy.

The following fork by @mchoji (https://github.com/mchoji/clairvoyancex) has fixed most of these issues.

Install

git clone https://github.com/mchoji/clairvoyancex.git
cd clairvoyancex
pip3 install -r requirements.txt

Get/create wordlist

I recommend creating a compound wordlist, this can include general english words, common API objects etc. We also want to create a target specific list based on the site (as mentioned on the clairvoyance repo). Eg.

  1. Grab one of the wordlists from the most common English words extracted from Google: https://github.com/first20hours/google-10000-english

  2. Make a target specific list. I found the best way was to grab the following:

    • JS files from the target site
    • Any existing GraphQL queries and responses
    • HTML source files

    Put them all together and run a Regex query to grab all possible names [[_A-Za-z][_0-9A-Za-z]*](http://spec.graphql.org/June2018/#sec-Names). Because we will have a lot of junk there, I recommend removing any short words with sed -nri.bak '/^.{3,}$/p' farmed_words.txt.

  3. Put the two lists together cat google-10000-english.txt >> farmed_words.txt.

Run

python3 -m clairvoyancex -o output_schema.json -w farmed_words.txt -k https://somesite.url/graphql

Note:

  • -k ignores certificate errors on HTTPS sites
  • You may need the following flags too:
    • -t 20 if the site is slow to respond add a longer timeout
    • -d "mutation { FUZZ }" changing the initial fuzzing query may help (default "query { FUZZ }"
    • -H "Cookie: somecookie=something" in case an auth cookie or header is required

Bonus note: Highly recommended to throw the output JSON file into GraphQL Voyager to get a nice map/view of the available names, types and schema.

2. Convert JSON schema to .gql schema file

Here's a quick script to convert the JSON schema file into a .gql file supported by most GraphQL playground apps. Requires NodeJS.

Setup commands

npm init
npm install graphql --save
touch index.js

index.js

const { buildClientSchema, printSchema } = require("graphql");
const fs = require("fs");
if (process.argv.length === 2) {
	console.error('Expected at least one argument!');
	process.exit(1);
} else if (process.argv.length === 3) {
	console.error('Syntax: node index.js input.json output.gql');
	process.exit(1);
}
const introspectionSchemaResult = JSON.parse(fs.readFileSync(process.argv[2]));
const graphqlSchemaObj = buildClientSchema(introspectionSchemaResult.data);
fs.writeFileSync(process.argv[3], printSchema(graphqlSchemaObj));

Run

node index.js <input.json> <output.gql>

3. Import into Altair

Altair is a GraphQL client that helps with a lot of the query building, autocomplete and refactoring of GraphQL queries. The Chrome plugin is invaluable for testing as it can be run inline with your proxy server and side by side on your web app test.

  1. Grab and install the Chrome plugin here

  2. Open the Altair view in Chrome

  3. Chuck your GraphQL endpoint in the POST/GET text box and press Docs

    https://i.imgur.com/GoJtIKT.png

  4. Hit the 3 dots and Load the .GQL schema file we generated earlier.

    https://i.imgur.com/RkTbY80.png

  5. The bruteforced schema will now be loaded into the Docs view and will help you navigate names and generate queries. If you hover over a Query/Mutation name or type it will let you Add query to your Query request pane.

    https://i.imgur.com/eAYGXPc.png

Tip: If you get errors when sending a request saying that a field requires subfields, put your cursor on the specific field in the query and hit Ctrl+Shift+Enter to auto populate the type.

Summary

Das' it. My leeched notes to help with GraphQL inspection when introspection doesn't exist. Thanks to a few people for pointing out some tools and refs (@infosec_au, @nnwakelam).

My boring Twitter @me0wday

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment