Professional Documents
Culture Documents
437-Flustered HTB Official Writeup Tamarisk
437-Flustered HTB Official Writeup Tamarisk
Difficulty: Medium
Classification: Official
Synopsis
Flustered is a medium difficulty Linux machine which showcases two different storage solutions (GlusterFS
and the Azure Storage emulator Azurite) that can be accessed at different stages in order to obtain different
levels of access to the system. First, unauthenticated mount of a GlusterFS volume allows attackers to read
Squid credentials from a database, granting access to a local HTTP server where the source code of the
main web application can be read, discovering an SSTI vulnerabilty that results in remote command
execution. World-readable SSL certificates allow access to a second GlusterFS volume that is mounted as
/home , where public keys can be planted in order to SSH in as a second user. Finally, an Azure Storage blob
contains a public SSH key for the root user.
Skills Required
Enumeration
Pivoting
MySQL / MariaDB knowledge
Skills Learned
Mounting GlusterFS volumes
Identifying and exploiting SSTI vulnerabilities
Accessing Azure Storage
Enumeration
Nmap
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.131 | grep ^[0-9] | cut -d '/' -f 1 | tr
'\n' ',' | sed s/,$//)
nmap -p$ports -sV -sC -Pn 10.10.11.131
Nmap scan shows that OpenSSH, nginx and Squid are listening on their default ports. A few more ports,
which Nmap identified as rpcbind , are open.
Nginx
Browsing to port 80 we see an empty page with a background image but no actual content.
The page title is steampunk-era.htb - Coming Soon , which means the web site is still under development.
Squid
The Squid proxy requires authentication.
GlusterFS
A quick web search reveals that 24007 and 49152 are standard Gluster ports. After installing the GlusterFS
client, we can run the following command to list the available volumes:
The log file ( /var/log/glusterfs/mnt.log ) shows additional information about the mount failure, which
seems to be caused by a DNS resolution error:
We add an entry to the /etc/hosts file and attempt to mount vol1 again:
This fails again, and the log file shows an SSL related error:
Foothold
Having obtained access to MariaDB files, we are now able to read data stored in the database tables. The
mysql_upgrade_info file reveals the MariaDB version:
We can run our own MariaDB server (using the same version as above to ensure compatibility) copying data
from vol2 into /var/lib/mysql . This can be easily accomplished using Docker, enabling auth_socket
authentication to avoid entering a password:
mkdir /tmp/mysql
cp -R /mnt/* /tmp/mysql/
We can now read data from the passwd table in the squid database:
A quicker way to obtain the same information without running MariaDB server would be to use the
strings command:
Either way, we have obtained a user named lance.friedman with password o>WJ5-jD<5^m3 . Using these
credentials, we can successfully authenticate to Squid:
We run gobuster (notice that we have to URL-encode some characters in order to get a valid userinfo ):
Searching for Python files inside the /app directory, a file named app.py is found:
def getsiteurl(config):
if config and "siteurl" in config:
return config["siteurl"]
else:
return "steampunk-era.htb"
template = f'''
<html>
<head>
<title>{getsiteurl(config)} - Coming Soon</title>
</head>
<body style="background-image: url('{url_for('static', filename='steampunk-
3006650_1280.webp')}');background-size: 100%;background-repeat: no-repeat;">
</body>
</html>
'''
return render_template_string(template)
if __name__ == "__main__":
app.run()
The siteurl field is parsed from a JSON object in the request body and added to the page template, which
is then rendered via render_template_string() . This makes the application vulnerable to Server-Side
Template Injection. We can verify the vulnerability by sending the {{7*7}} payload:
We open a listener on port 7777 and then send the following request:
Lateral Movement
Running the mount command we see that the GlusterFS volume vol1 , which we were unable to mount
remotely due to SSL certificate issues, is mounted locally to the /home/jennifer directory:
As shown in the Gluster documentation, SSL key and certificates are located in the /etc/ssl directory.
All three files are world-readable (including glusterfs.key , which is not by default, meaning its
permissions were changed), so we can copy them to our local /etc/ssl directory. This allows us to mount
the vol1 volume from our attacking machine:
mkdir /mnt/jennifer
mount -t glusterfs flustered:/vol1 /mnt/jennifer
We can read the user flag in /mnt/jennifer/user.txt and put our public key in .ssh/authorized_keys
in order to get a shell as jennifer .
Privilege Escalation
The /var/backups directory contains a key file which is readable by the jennifer group:
The ip a command shows that the machine has an interface on a Docker network, with IP address
172.17.0.2:
We discover a running container with IP address 172.17.0.2.
Open port 10000 was discovered. We make a cURL request to this port:
Searching the web for InvalidQueryParameterValue , we find out it is an error related to Azure Storage. In
fact, port 10000 is used as default port by the Azurite emulator.
To be able to interact with the Azure Storage instance, we download and install the Azure Storage Explorer
application. We use SSH local port forwarding to access the service locally:
We run Storage Explorer and add a new connection to a Local Storage Emulator:
We enter jennifer as the Account name and the base64 data from /var/backups/key as the Account
key:
Two blob containers, documents and ssh-keys , are available.