uscybergames

Touch grass [150 pts]

Writeup author: lolmenow

Provided files: N/A

Description: ARIA has ordered you to touch grass. Now you actually have to do it. Make up for all the times you havent touched it.

Since there is no source provided, we have to start pentesting.

I made an account to check things out.

image

Hmmm we need 100000 pieces of grass?

Lets check out the page source.

image(1)

Okay, we see that we can go to /api/click with a POST request to get a click

image(2)

Hmmm okay, content type/json should fix this.

image(3)

Nevermind, lets supply it with our /register json data.

image(4)

Oh an Admin API?

At this point, I tried bruteforcing and trying to find the admin API. This did absolutely nothing until someone from the discord server says to “check how users are made”.

So, I go back to the registration page and I notice something.

image(5)

Registration.js! This should be interesting.

$(document).ready(function() {
    $('#register_button').on('click', register);
    console.log("ready");
});

const register = async() => {
    $('#register_button').prop('disabled', true);

    // prepare alert
    let card = $("#resp-msg");
    card.attr("class", "alert alert-info");
    card.text("Sending registration...");
    card.show();

    // validate
    let username = $("#username").val();
    let first_name = $("#first_name").val();
    let last_name = $("#last_name").val();
    let password = $("#password").val();

    await fetch(`/api/register`, {
        // copy from the /admin/api/register endpoint
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({username: username, first_name: first_name, last_name: last_name, password: password}),
        })
        .then((response) => response.json()
            .then((resp) => {
                card.attr("class", "alert alert-danger");
                if (response.status == 200) {
                    card.attr("class", "alert alert-info");
                    card.text(resp.message);
                    card.show();
                    window.location = "/dashboard";
                }
                card.text(resp.message);
                card.show();
            }))
        .catch((error) => {
            card.text(error);
            card.attr("class", "alert alert-danger");
            card.show();
        });

        $('#register_button').prop('disabled', false);
}

There it is! Our admin API! We can now make accounts with the status of admin. Lets make one.

image(6)

Seems to work. Now that we know the admin api, we can assume the click endpoint would be on /api/admin/click since we are an “admin” account.

image(8)

Missing count parameter? No problem, lets add it! We know we need 100000 for the flag

image(7)

The parameters might be getting in our away. Lets try only our user and count parameter, as the other fields were only necessary for registration.

image(9)

Count updated! Lets check the dashboard.

ezgif-2-873430a4b0

There it is! Our flag!

Final flag: SIVBGR{T0uch_1t}