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
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
We can access the machine via SSH service
We can read the user flag by typing the “cat user.txt” command
Escalate to Root Privileges Access
By default, we can obtain the SUID binary by running the “sudo -l” command
(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
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.
We managed to obtain the root password
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
No responses yet