Reported to vendor: reported, vendor not yet remediated
Severity: Critical (CVSS v3.1 = 9.8) (Full system compromise risk)
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-502
Etki Kapsamı:
Startupv3.29.6.4Sınıflar:
com.lbs.start.JLbsStartup, com.lbs.start.SocketToken
Uygulama, JNLP dosyasında yer alan DOCUMENT_URI parametresini istemci sunucu akışında kullanıyor ve bu URI/uç nokta üzerinden dönen istek gövdesini HTTP metodu ne olursa olsun (HEAD dahil) okuyup ObjectInputStream.readObject() ile deserialize ediyor. Sonuç olarak saldırgan, kimlik doğrulaması olmadan bile serialized bir gövdeyi HEAD isteğiyle taşıyıp sunucu tarafında gadget zincirini tetikleyebiliyor ve RCE elde edebiliyor. Bu davranış, HTTP standardında HEAD yanıt gövdesinin olmamasıyla karıştırılabiliyor ancak istek gövdesi uygulama katmanında yanlış tasarımla okunuyorsa, HEAD de dahil olmak üzere metot agnostik bir akış ortaya çıkıyor ve deserialize zinciri aynı şekilde çalışıyor.
Zincirin pratik akışı şöyle gerçekleşiyor: İstemci tarafından sunulan JNLP, DOCUMENT_URI’yi uygulama başlatma parametresi olarak içeriyor; bu parametre sunucu tarafındaki web bileşenine aktarılıyor ve burada ilgili handler/servlet, isteğin gövdesini metot kontrolü yapmadan request.getInputStream() ile tüketiyor. Ardından bu akış bir servis katmanına devredilip new ObjectInputStream(in).readObject() çağrısına ulaşıyor. Deserialize sırasında sınıf yükleme ve readObject()giriş noktalarına bağlı bir gadget zinciri çalıştırılarak komut yürütme sağlanıyor. Bu nedenle saldırgan, ysoserial ile ürettiği bir payload.ser dosyasını Content-Type: application/x-java-serialized-object başlığıyla HEAD isteği gövdesine koyduğunda, uç nokta POST/PUT yerine HEAD ile çağrılsa bile, uygulamanın metot-agnostik gövde okuması yüzünden içerik deserialize edilip komut çalıştırılabiliyor. Küçük boyutta yapılan HEAD çağrıları 200 OK döndürüp JNLP sunabiliyor, bu, uç noktanın HEAD’i işlediğini ve gövdeyi en azından kısmen tükettiğini gösteriyor.
- Girdi güvenliği: Uygulama, doğrulanmamış/veri türü zorlanmamış bir girdi akışını doğrudan
ObjectInputStream.readObject()’a iletiyor. Sınıf allowlist’i/object filter (JEP-290) gibi savunmalar yok ya da etkisiz. - HTTP semantiği ihlali: Handler/filtre/servlet katmanında HTTP metoduna göre gövde okuma ayrımı yapılmıyor.
doHeadveya ortak birservicedalında, koşulsuzgetInputStream()tüketimi söz konusu; bu da HEAD ile bile gövde taşınmasını anlamlı ve sömürülebilir kılıyor.
Startupv3.34.8.3.jar’ın istemci başlangıç rolü ve arka tarafta Apache-Coyote/Tomcat yığını yer almıştır. WAF/405 sonradan, CVE tahsisinden sonra eklenmiştir; bu, PoC’nin bazı varyantlarını engellese de deserialize kodu kaldırılmadığı sürece kalıcı bir çözüm değildir.
Olay Akışı
http://xx.xxx.xx.xxx:xxxx/xxxx/xxxx/runapp?...uç noktası tespit edildi; yanıt olarak JNLP döndürdüğü ve kimlik doğrulaması istemediği görüldü.- JNLP içinde ana bileşenler
Startupv3.29.6.4gibi JAR’lara işaret ediyor. Startupv3.29.6.4JAR analizi sırasındacom.lbs.start.SocketTokensınıfındanew ServerSocket(port)venew ObjectInputStream(...).readObject()çağrıları belirlendi; gelen mesajlar filtre/allow-list olmadan işleniyor.ysoserialile hazırlananpayload.serCommonsCollections2 + TemplatesImpl +Runtime.execHEAD isteğinin gövdesi olarak/smart/runapp’a gönderildi ve sunucuda dosya oluşturma ile RCE doğrulandı.
Teknik kanıt
runapp.jnlp içeriğinden doğruca startup.jar dosyasına yönlendirme var, ilgili linke gidip jar dosyasını sistemimde decode edip analiz ettim.JAR içindeki
com.lbs.start.SocketToken / new ServerSocket(port) + ObjectInputStream.readObject() çağrıları gelen socket üzerinde doğrudan readObject() çağırıyor.
- Ayrıca
initListen(...)içindems_Instance.accept()ile kabul edilen bağlantılarda yinenew ObjectInputStream(connection.getInputStream())çağrısı veprocessor.processToken(message)ile gelen nesnenin uygulama mantığına verildiği görülüyor. - Gelen veriye hiçbir güvenlik filtresi uygulanmadan
readObject()çağrısı yapılmakta.
exploit.py // HEAD ile tetikleme
exploit.py
Payload.ser
DOCUMENT_URI okunup uygulama/applet’e setDocumentURI(String) ile aktarılıyor. Yani bu parametre, istemci tarafındaki ana bileşene “sunucuya hangi endpoint üzerinden bağlanacağını / doküman servisinin nerede olduğunu” bildiriyor. Dosyanın içinde bu akış net: satır ~524’te getParameter("DOCUMENT_URI") alınıyor, hemen ardından yansımayla setDocumentURI(...) çağrılıyor JLbsStartup.java içinde tespit edilen bölüm:
DOCUMENT_URI, istemci başlatılırken JLbsStartupden setDocumentURI(...) akışıyla ana uygulamaya aktarılıyor; böylece istemci, sunucu tarafındaki ‘document’ servisine hangi URI’dan konuşacağını biliyor. Deserialization ise bu istemci kodunda değil; server-side endpoint’te gerçekleşiyor.
Kanıtın Gözlemi
Payload.ser’i Yukarıda verdiğim şekilde CommonsCollections2 ile hazırla ve exploit.py yi çalıştır

exploit.py’yi çalıştırdığım zaman sunucuda tmp/pwned klasörü oluştuğunu görebiliriz.

Zaman Çizelgesi
- 05.10.2025 – İlk bildirim
- 22.10.2025 – CVE tahsisi
- 22.10.2025 sonrası – Vendor WAF/endpoint davranışını değiştiriyor (POST/PUT → 405; büyük gövdede RST; GET/HEAD 200 ile JNLP servis ediyor).
Saldırı yüzeyi
- Giriş noktası:
/xxxx/smart/runapp(JNLP üretim noktası) HEAD/GET isteklerine yanıt veriyor. - Parametre kökeni: JNLP içindeki
DOCUMENT_URIargümanı istemci tarafından okunuyor; sunucu tarafında bu URI’ye karşılık gelen belge/akış işlenirken gövde verisi HTTP metodundan bağımsız olarak elde edilebiliyor. - Metot semantiği ihlali: HTTP/1.1’de HEAD gövdesi anlamsal olarak yok sayılmalıdır; ancak uygulama ortak handler’da
getInputStream()’i koşulsuz okuduğu için HEAD ile gönderilen serialized içerik de işlenebiliyor.
İstismar önkoşulları
- Kimlik doğrulama: Gerekmiyor.
- Ağ erişimi: internet.
- Gadget zinciri:
CommonsCollections2
İstismar kolaylığı (Exploitability)
- Ağ vektörü (AV:N): Uzak ağdan tetikleniyor.
- Düşük karmaşıklık (AC:L): HEAD ile gövde kabul eden handler var
- Kullanıcı etkileşimi (UI:N): Yok.
- Ayrıcalık gereksinimi (PR:N): Yok.
- Güvenlik kapsamı (S:U): Tipik olarak aynı bileşen içinde
- Etkiler:
- Gizlilik (C:H): Process yetkisiyle dosya/kimlik bilgisi sızdırma, JDBC dizeleri, erişim anahtarları.
- Bütünlük (I:H): Keyfi komut ve bytecode çalıştırma.
- Süreklilik (A:H): Hizmet kesintisi.
- Güvenirlik: Aynı sürüm/sınıf yolu/gadget seti yakalandığında yüksek; WAF devredeyken ayarlama gerektirebilir (chunked, içerik türü/farklı başlıklar, boyut eşikleri, farklı metodlar).
Not (HEAD neden çalışıyor?): Uygulama,doHead()’idoGet()/process()’e delege ediyor veya tek bir “process” bloğu tüm metodlarda koşulsuzrequest.getInputStream()okuyor. Bu, standart uygulama farkından kaynaklanan bilinen bir “pitfall”; HEAD gövdeyi okumamalı, fakat okur ve deserialize ederse RCE’ye yol açabilir.
Neden risk yüksek?
- Kimlik doğrulamasız, uzaktan, tek paketle tetiklenebilir bir RCE vektörü.
- HEAD ile bile çalışabilmesi, klasik WAF kural setlerinin “sadece POST/PUT gövdesini incele” varsayımını bozar.
- Java kurumsal ekosisteminde gadget bolluğu, pratikte yüksek istismar olasılığı demektir.
Kısıtlar Çevresel faktörler
- Sonradan eklenen WAF: Büyük/şüpheli gövde gönderiminde **RST **veya
405döndürüyor; bu semptomu gizler, kök nedeni kaldırmaz. - Class-path farklılıkları: Bazı sürümlerde belirli gadget’lar bulunmayabilir, ancak alternatif zincirler genelde mevcuttur.
Mitigasyon
Mitigasyon sonrası POST/PUT 405, büyük gövdede RST (WAF) ve HEAD/GET sadece JNLP döndürüyor ve dolayısıyla exploit yolu uygulamada kapatılmış görünüyor. Güncel testler ile hali ile:
Hashler
Payload.serSHA-256 Hash: 3d302311134368d4fd6bd5e3ca6703510608bae3a0856281b11415dba952bff5
Boyut: 4.096
Startupv3.29.6.4.jar
SHA-256 Hash: d1b18391d76822a61a0434d47334d64d56471e1e2d89cd8e1962dfea16b96004
boyut: 200.704
Deserialization Kaynaklı RCE Nasıl Oluşur.

readObject() / ObjectInputStream gibi objeler olabilir, obje oldukça masumane bir şekilde ilgili sisteme veri getir götür işlemlerini yaparken, burada zafiyet olduğunu tespit eden Kötü Niyetli Saldırgan kişisi A olayında olduğu gibi, olan veriyi Serileştirerek içeriye sokar.B olayında ise eğer kötü niyetli saldırgan serileştirilmiş veriyi gönderebilirse deserialization dediğimiz olay gerçekleşir ve sistem içeride bu veriyi seri durumdan çıkarır ve sistemi içeriye sokar. C olayında ise artık saldırganın içeride komut çalıştırmasının önünde bir engel kalmaz.
Bu çalışma yalnızca güvenlik araştırması ve farkındalık amacıyla yapılmıştır. İlgili kurum bilgilendirilmiş, güvenlik açığı kapatılana kadar exploit detayları paylaşılmamıştır.