In this post, I would like to share a walkthrough of the Format Machine from Hack the Box.

This room will be considered a medium machine on Hack the Box

What will you gain from the Format machine?

For the user flag, you will need to create a subdomain on the web which we can modify the TXT field to perform an LFI attack. We can use the HMSET vulnerability to become a PRO account which we are provided with a new function for uploading images. We can exploit the application and access the machine via www-data privileges which we can retrieve the cooper credentials from redis-cli.

As for the root flag, you need to execute a script with a license binary which will be given the password for the root access from the REDIS-CLI command

Information Gathering on Format Machine

Once we have started the VPN connection which requires a download from Hackthebox, we can start the information gathering on the machine by executing the command nmap -sC -sV -p- <IP Address> -PN

┌─[✗]─[darknite@parrot]─[~/Document/htb/format]
└──╼ $nmap -sC -sV 10.10.11.213 -oA initial 
Starting Nmap 7.92 ( https://nmap.org ) at 2023-05-15 21:55 EDT
Nmap scan report for 10.10.11.213
Host is up (0.16s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 c3:97:ce:83:7d:25:5d:5d:ed:b5:45:cd:f2:0b:05:4f (RSA)
|   256 b3:aa:30:35:2b:99:7d:20:fe:b6:75:88:40:a5:17:c1 (ECDSA)
|_  256 fa:b3:7d:6e:1a:bc:d1:4b:68:ed:d6:e8:97:67:27:d7 (ED25519)
80/tcp   open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Site doesn't have a title (text/html).
3000/tcp open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://microblog.htb:3000/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 44.36 seconds
┌─[darknite@parrot]─[~/Document/htb/format]
└──╼ $

Let’s access the website interface

Firstly, we have a website interface that looks something like as above.

Another website looks like a Gitea website interface.

Therefore, i need to register a new account.

We also can create a subdomain

It will look something as shown above if the subdomain is successfully created

At last, the blog has been successful we can edit the content of the blog

There are some functions that can be posted.

As a result, let’s inspect the packet with /etc/passwd

Boom! We managed to obtain the /etc/passwd information.

By default, the screenshot above shows the output on the browser’s version.

However, the activity of entering the credentials as Cooper failed.

Finally, we have accessed the Gitea version by entering the http://microblog.htb:3000/cooper.

I noticed that there are two potential usernames on the machine

We managed to notice that Redis has been installed on the machine

PHP
function provisionProUser() {
    if(isPro() === "true") {
        $blogName = trim(urldecode(getBlogName()));
        system("chmod +w /var/www/microblog/" . $blogName);
        system("chmod +w /var/www/microblog/" . $blogName . "/edit");
        system("cp /var/www/pro-files/bulletproof.php /var/www/microblog/" . $blogName . "/edit/");
        system("mkdir /var/www/microblog/" . $blogName . "/uploads && chmod 700 /var/www/microblog/" . $blogName . "/uploads");
        system("chmod -w /var/www/microblog/" . $blogName . "/edit && chmod -w /var/www/microblog/" . $blogName);
    }
    return;
}

We managed to notice the account should be a pro version so that we can escalate further

Therefore, we should be executing the command via the Curl command

We managed to obtain the pro version by refreshing the page.

Let’s start our nc listener

At last, we managed to execute the command injection on the machine

Let’s try to retrieve a reverse shell connection back to us by using the bash command. Sadly, we didn’t retrieve any connection back to us.

Finally, we managed to obtain a reverse shell connection back to us.

Another method to obtain the shell is by grabbing a shell file using the curl command

Firstly, we are required to create a file that contains our reverse shell command

Therefore, let’s start our python server

As we managed to execute a command injection previously, let’s execute the curl command as shown above.

As a result, we managed to grab a file on the python server

We should be getting the reverse shell connection using this method too.

Redis Enumeration

We managed to find a redis-server is running from the pspy64 output

We should execute the redis-cli command to see any useful information and i notice there’s one user that we should analyze further

At last, we found a potential password for the username of cooper.dooper

A picture containing screenshot, multimedia software

Description automatically generated

We can access the machine via SSH service

A picture containing screenshot, text, font, colorfulness

Description automatically generated

We can read the user flag by typing the “cat user.txt” command

Escalate to Root Privileges Access

A picture containing text, screenshot, font

Description automatically generated

By default, we can obtain the SUID binary by running the “sudo -l” command

Python
(remote) cooper@format:/home/cooper$ cat /usr/bin/license 
#!/usr/bin/python3

import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.fernet import Fernet
import random
import string
from datetime import date
import redis
import argparse
import os
import sys

class License():
    def __init__(self):
        chars = string.ascii_letters + string.digits + string.punctuation
        self.license = ''.join(random.choice(chars) for i in range(40))
        self.created = date.today()

if os.geteuid() != 0:
    print("")
    print("Microblog license key manager can only be run as root")
    print("")
    sys.exit()

parser = argparse.ArgumentParser(description='Microblog license key manager')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-p', '--provision', help='Provision license key for specified user', metavar='username')
group.add_argument('-d', '--deprovision', help='Deprovision license key for specified user', metavar='username')
group.add_argument('-c', '--check', help='Check if specified license key is valid', metavar='license_key')
args = parser.parse_args()

r = redis.Redis(unix_socket_path='/var/run/redis/redis.sock')

secret = [line.strip() for line in open("/root/license/secret")][0]
secret_encoded = secret.encode()
salt = b'microblogsalt123'
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=salt,iterations=100000,backend=default_backend())
encryption_key = base64.urlsafe_b64encode(kdf.derive(secret_encoded))

f = Fernet(encryption_key)
l = License()

#provision
if(args.provision):
    user_profile = r.hgetall(args.provision)
    if not user_profile:
        print("")
        print("User does not exist. Please provide valid username.")
        print("")
        sys.exit()
    existing_keys = open("/root/license/keys", "r")
    all_keys = existing_keys.readlines()
    for user_key in all_keys:
        if(user_key.split(":")[0] == args.provision):
            print("")
            print("License key has already been provisioned for this user")
            print("")
            sys.exit()
    prefix = "microblog"
    username = r.hget(args.provision, "username").decode()
    firstlast = r.hget(args.provision, "first-name").decode() + r.hget(args.provision, "last-name").decode()
    license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)
    print("")
    print("Plaintext license key:")
    print("------------------------------------------------------")
    print(license_key)
    print("")
    license_key_encoded = license_key.encode()
    license_key_encrypted = f.encrypt(license_key_encoded)
    print("Encrypted license key (distribute to customer):")
    print("------------------------------------------------------")
    print(license_key_encrypted.decode())
    print("")
    with open("/root/license/keys", "a") as license_keys_file:
        license_keys_file.write(args.provision + ":" + license_key_encrypted.decode() + "\n")

#deprovision
if(args.deprovision):
    print("")
    print("License key deprovisioning coming soon")
    print("")
    sys.exit()

#check
if(args.check):
    print("")
    try:
        license_key_decrypted = f.decrypt(args.check.encode())
        print("License key valid! Decrypted value:")
        print("------------------------------------------------------")
        print(license_key_decrypted.decode())
    except:
        print("License key invalid")
    print("")
(remote) cooper@format:/home/cooper$ 

The script above shows how the binary works

A screen shot of a computer

Description automatically generated with low confidence
A screen shot of a computer code

Description automatically generated with low confidence

We should be getting the PHPREDIS_Session that we can abuse for root privileges access

Finally, we can run the command above so that we can move on with further escalation.

A picture containing screenshot, text

Description automatically generated

We managed to obtain the root password

A picture containing screenshot, font, text

Description automatically generated
A picture containing screenshot, display, multimedia software, software

Description automatically generated

Finally, we can access the machine via SSH service.

We should be able to read the root flag by running the “cat root.txt” command

Extra Information

A picture containing screenshot

Description automatically generated

Categories:

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *