Kötü amaçlı kod çalıştırmak için serileştirilmiş verilerin yetkisiz manipülasyonu olan serileştirme saldırıları, kuruluşlara ciddi zararlar verebilir. Geliştiriciler ve güvenlik ekipleri, saldırının nasıl, ne zaman ve nerede gerçekleştiğini ortaya çıkaran temel güvenlik açıklarını proaktif olarak belirlemelidir.
Bu tehdidin yakın tarihli bir örneği, Apache Kafka için Spring'de RCE'ye (uzaktan kod yürütme) yol açabilen bir deserialization saldırı vektörü olan CVE-2023-34040'tır. Aslında, serileştirme güvenlik açıklarının yaygınlığı, en kritik 10 web uygulaması güvenlik riskinden biri olarak "Güvenilmeyen Verilerin Serileştirilmesi" ni içeren OWASP Top 10 listesinde vurgulanmaktadır.
SBOMSoftware Bill of Materials) motoruna sahip OPSWAT MetaDefender Core™ gibi araçlar, deserialization saldırılarını tespit etmek ve önlemek için çok önemlidir. Bunlar, geliştiricilerin kodlarını verimli bir şekilde tarayıp analiz etmelerine olanak tanıyarak hiçbir güvenlik açığının gözden kaçmamasını sağlar.
Bu blogda, Yüksek Lisans Bursiyerlerimiz CVE-2023-34040 ve istismarının ayrıntılarını ve açık kaynaklı bileşenlerin benzer tehditlere karşı nasıl güvence altına alınacağını tartışacaklar.
CVE-2023-34040 Hakkında
CVE-2023-34040, Spring for Apache Kafka'da olağandışı bir yapılandırma uygulandığında yararlanılabilecek bir serileştirme saldırı vektörünü ortaya çıkarır. Bu güvenlik açığı, bir saldırganın serileştirme istisnası kayıt başlıklarından birinde kötü amaçlı serileştirilmiş bir nesne oluşturmasına olanak tanır ve bu da RCE ile sonuçlanabilir. Güvenlik açığı Spring for Apache Kafka'nın 2.8.1 ila 2.9.10 ve 3.0.0 ila 3.0.9 sürümlerini etkilemektedir.
Özellikle, bir uygulama/tüketici aşağıdaki belirli yapılandırmalar ve koşullar altında savunmasızdır:
- ErrorHandlingDeserializer sınıfı kaydın anahtarı ve/veya değeri için yapılandırılmamıştır.
- Tüketicinin checkDeserExWhenKeyNull ve/veya checkDeserExWhenValueNull özellikleri true olarak ayarlanır.
- Güvenilmeyen kaynakların bir Kafka konusuna yayın yapmasına izin verilir.
Apache Kafka
Apache Software Foundation tarafından geliştirilen Apache Kafka, veritabanları, sensörler ve mobile cihazlar dahil olmak üzere çeşitli kaynaklardan gelen gerçek zamanlı veri akışlarını yakalamak, işlemek, yanıtlamak ve yönlendirmek için tasarlanmış dağıtılmış bir olay akışı platformudur.
Örneğin, bir ürün ödemesini tamamlamak veya ödeme yapmak gibi müşteri faaliyetlerine tepki veren hizmetlere bildirim akışı sağlayabilir.
Apache Kafka'da, kayıt veya mesaj olarak da adlandırılan bir olay, veri okunduğunda veya yazıldığında uygulamadaki bir olayı temsil eden bir veri birimi olarak hizmet eder. Her olay bir anahtar, değer, zaman damgası ve isteğe bağlı meta veri başlıkları içerir.
Anahtar-ikili (null olabilir) | Değer-ikili (null olabilir) | ||||
Sıkıştırma Tipi [none, gzip, snappy, lz4, zstd] | |||||
Üstbilgiler (isteğe bağlı)
| |||||
Bölme + Ofset | |||||
Zaman damgası (sistem veya kullanıcı ayarı) |
Olaylar dayanıklı bir şekilde depolanır ve konular halinde düzenlenir. Kafka konularına olay gönderen (yazan) istemci uygulamaları üretici olarak adlandırılırken, olaylara abone olan (okuyan ve işleyen) uygulamalar tüketici olarak bilinir.
Apache Kafka için Spring
Apache Kafka'yı Spring ekosistemine bağlamak için geliştiriciler, Java uygulamalarında entegrasyonu kolaylaştıran Spring for Apache Kafka'yı kullanabilirler.
Spring for Apache Kafka, Kafka ile olay gönderme ve alma sürecini basitleştiren sağlam araçlar ve API'ler sunarak geliştiricilerin bu görevleri kapsamlı ve karmaşık kodlama yapmadan gerçekleştirmelerini sağlar.
Serileştirme ve Serileştirmeyi Kaldırma
Serileştirme, bir nesnenin durumunu bir dizeye veya bayt akışına dönüştürme mekanizmasıdır. Buna karşılık, serileştirme tersine bir işlemdir ve serileştirilmiş veri tekrar orijinal nesnesine veya veri yapısına dönüştürülür. Serileştirme, karmaşık verilerin bir dosyaya kaydedilebilmesi, bir ağ üzerinden gönderilebilmesi veya bir veritabanında saklanabilmesi için dönüştürülmesini sağlar. Serileştirme ve seriden çıkarma, dağıtılmış sistemlerde veri alışverişi için gereklidir ve bir yazılım uygulamasının çeşitli bileşenleri arasındaki iletişimi teşvik eder. Java'da serileştirme için writeObject(), serileştirmeden çıkarma için ise readObject() kullanılır.
Derileştirme, bir bayt akışının veya dizenin bir nesneye dönüştürülmesine izin verdiğinden, girdi verilerinin yanlış işlenmesi veya uygun şekilde doğrulanmaması, potansiyel olarak bir RCE saldırısına yol açan önemli bir güvenlik açığına neden olabilir.
Güvenlik Açığı Analizi
CVE açıklamasına göre, OPSWAT Bursiyerleri güvenlik açığını tetiklemek için checkDeserExWhenKeyNull ve checkDeserExWhenValueNull öğelerini true olarak yapılandırmıştır. Boş bir anahtar/değer içeren bir kayıt göndererek ve üreticiden bir Kafka kaydı alırken tüketicide hata ayıklama yaparak ayrıntılı bir analiz gerçekleştiren mezun arkadaşlarımız, kayıt işleme sırasında aşağıdaki iş akışını ortaya çıkardılar:
Adım 1: Kayıtların (Mesajların) Alınması
Tüketici, kayıtları aldıktan sonra invokeIfHaveRecords() yöntemini çağırır ve bu yöntem daha sonra kayıtların fiilen işlenmesi için kayıtlı bir kayıt dinleyicisini ( @KafkaListener ek açıklamasıyla açıklanmış bir sınıf) tetiklemek üzere invokeListener() yöntemini çağırır.
invokeListener() daha sonra invokeOnMessage() yöntemini çağırır.
Adım 2: Kayıtların Kontrol Edilmesi
invokeOnMessage() yöntemi içinde, kayıt değeri ve yapılandırma özelliklerine karşı çeşitli koşullar değerlendirilir ve ardından yürütülecek bir sonraki adım belirlenir.
Bir kayıt null anahtar veya değere sahipse ve checkDeserExWhenKeyNull ve/veya checkDeserExWhenValueNull özellikleri açıkça true olarak ayarlanmışsa, kaydı incelemek için checkDeser() yöntemi çağrılacaktır.
Adım 3: Üstbilgilerden İstisnayı Kontrol Etme
checkDesr() işlevinde tüketici, varsa kaydın meta verilerindeki istisnaları almak için sürekli olarak getExceptionFromHeader() işlevini çağırır ve sonucu exception adlı bir değişkende saklar.
Adım 4: Üstbilgilerden İstisna Çıkarma
getExceptionFromHeader() yöntemi, bir Kafka kaydının başlığından bir istisnayı ayıklamak ve döndürmek için tasarlanmıştır. Önce kaydın başlığını alır ve ardından bir bayt dizisinde depolanan başlığın değerini elde eder.
Daha sonra, başlık değerinin bayt dizisini daha fazla işlem için byteArrayToDeserializationException() yöntemine iletir.
Adım 5: Verilerin Serileştirilmesi
byteArrayToDeserializationException() işlevinde, resolveClass() işlevi yalnızca izin verilen sınıflarla sınırlandırmak için geçersiz kılınmıştır. Bu yaklaşım, açıkça izin verilmeyen herhangi bir sınıfın serileştirilmesini önler. Başlığın bayt dizisi değeri, byteArrayToDeserializationException() içinde yalnızca DeserializationException sınıfı için serileştirmeye izin veren resolveClass() işlevinde belirlenen koşulu karşılıyorsa serileştirilebilir.
Ancak, DeserializationException sınıfı standart Exception sınıfını genişletir ve dört parametreli bir kurucu içerir. Son parametre olan cause, IOException veya ClassNotFoundException gibi DeserializationException'ı tetikleyen orijinal istisnayı temsil eder.
Throwable sınıfı, Java'da istisna veya hata olarak atılabilen tüm nesneler için üst sınıf görevi görür. Java programlama dilinde, Throwable, Exception ve Error gibi istisna işleme sınıfları güvenli bir şekilde serileştirilebilir. Bir istisna serileştirildiğinde, Java, Throwable sınıflarının üst sınıflarının normal sınıflara uygulananlardan daha az zorlu kontrollerle yüklenmesine ve örneklenmesine izin verir.
İş akışına ve kapsamlı analize dayanarak, serileştirilen veriler Throwable üst sınıfından miras alan kötü amaçlı bir sınıfa karşılık geliyorsa, koşul kontrollerini atlayabilir. Bu, zararlı kod çalıştırabilen ve potansiyel olarak bir RCE saldırısıyla sonuçlanabilecek kötü amaçlı bir nesnenin serileştirilmesine izin verir.
İstismar
Analizde belirtildiği gibi, bu güvenlik açığından yararlanmak, Kafka başlık kaydı aracılığıyla tüketiciye gönderilen kötü amaçlı verilerin oluşturulmasını gerektirir. Başlangıçta, saldırganın Throwable sınıfını genişleten kötü amaçlı bir sınıf oluşturması ve ardından uzaktan kod yürütme elde etmek için bir gadget zinciri kullanması gerekir. Gadget'lar uygulama içindeki istismar edilebilir kod parçacıklarıdır ve saldırgan bunları birbirine zincirleyerek zararlı eylemleri tetikleyen bir "sink gadget "a ulaşabilir.
Aşağıda, Spring for Apache Kafka'daki bu güvenlik açığından yararlanmak için kullanılabilecek kötü amaçlı bir sınıf verilmiştir:
Ardından, kötü amaçlı sınıfın bir örneği oluşturulur ve DeserializationException sınıfının yapıcısındaki neden parametresine argüman olarak aktarılır. DeserializationException örneği daha sonra bir bayt akışına serileştirilir ve bu akış daha sonra kötü amaçlı Kafka kaydının başlığında değer olarak kullanılır.
Saldırgan, kurbanı kötü niyetli üreticisini kullanması için başarılı bir şekilde kandırırsa, tüketiciye gönderilen Kafka kayıtlarını kontrol edebilir ve sistemi tehlikeye atmak için bir fırsat yaratabilir.
Savunmasız tüketici, kötü niyetli üreticiden null anahtarlar ve değerler içeren bir Kafka kaydı ve kayıt başlığında kötü niyetli serileştirilmiş bir örnek aldığında, tüketici, serileştirme işlemi de dahil olmak üzere kaydı işler. Bu sonuçta uzaktan kod yürütülmesine yol açarak saldırganın sistemi tehlikeye atmasına olanak tanır.
MetaDefender Core'da SBOM ile CVE-2023-34040'ın hafifletilmesi
CVE-2023-34040 ile ilişkili riskleri etkili bir şekilde azaltmak için kuruluşların açık kaynak bileşenleri üzerinde görünürlük ve kontrol sağlayan kapsamlı bir çözüme ihtiyacı vardır.
MetaDefender Core içindeki temel bir teknoloji olan SBOM, güçlü bir yanıt sağlar. SBOM, kullanılan tüm yazılım bileşenlerinin, kütüphanelerin ve bağımlılıkların kapsamlı bir envanteri olarak hareket ederek, kuruluşların açık kaynaklı bileşenlerini proaktif ve verimli bir şekilde takip etmelerini, güvence altına almalarını ve güncellemelerini sağlar.
SBOM ile güvenlik ekipleri şunları yapabilir:
- Savunmasız bileşenleri hızla bulun: Derileştirme saldırılarından etkilenen açık kaynaklı bileşenleri hemen belirleyin. Bu, savunmasız kütüphanelerin yamalanması veya değiştirilmesi konusunda hızlı hareket edilmesini sağlar.
- Proaktif yama ve güncellemeler sağlayın: Derileştirme güvenlik açıklarının önüne geçmek için SBOM aracılığıyla açık kaynaklı bileşenleri sürekli izleyin. SBOM eski veya güvensiz bileşenleri tespit ederek güncellemelerin zamanında yapılmasını sağlar ve saldırılara maruz kalma riskini azaltır.
- Uyumluluğu ve raporlamayı sürdürün: SBOM, düzenleyici çerçevelerin yazılım tedarik zincirlerinde şeffaflığı giderek daha fazla zorunlu kılması nedeniyle kuruluşların uyumluluk gereksinimlerini karşılamasına yardımcı olur.
Kapanış Düşünceleri
Deserialization güvenlik açıkları, çok çeşitli uygulamalardan yararlanmak için kullanılabilecek önemli bir güvenlik tehdididir. Bu güvenlik açıkları, bir uygulama kötü amaçlı verileri deserialize ettiğinde ortaya çıkar ve saldırganların keyfi kod çalıştırmasına veya hassas bilgilere erişmesine olanak tanır. Apache Kafka için Spring'deki CVE-2023-34040 güvenlik açığı, deserializasyon saldırılarının tehlikelerini çarpıcı bir şekilde hatırlatmaktadır.
Deserialization saldırılarını önlemek için OPSWAT MetaDefender Core ve SBOM teknolojisi gibi gelişmiş araçları uygulamak çok önemlidir. Kuruluşlar yazılım tedarik zincirlerinde derin bir görünürlük elde edebilir, güvenlik açıklarının zamanında yamalanmasını sağlayabilir ve kendilerini sürekli gelişen tehdit ortamına karşı koruyabilirler. Açık kaynaklı bileşenleri proaktif olarak güvence altına almak sadece en iyi uygulama değil, modern sistemleri potansiyel istismara karşı korumak için bir gerekliliktir.