Kitle istismarı olasılığı düşük olan kritik öneme sahip bir Windows güvenlik açığının kapsamlı analizi ve değerlendirmesi
ESET araştırmacıları, yalnızca özel olarak hazırlanmış bir JPG dosyası (en yaygın kullanılan görüntü formatlarından biri) açarak uzaktan kod yürütme imkânı sağlayan ciddi bir Windows güvenlik açığı olan CVE-2025-50165’i inceledi. Zscaler ThreatLabz tarafından bulunan ve belgelenen bu kusur, Microsoft’un ciddiyetini kritik olarak değerlendirmesine rağmen istismar edilme olasılığının düşük olduğunu düşünmesi nedeniyle ilgimizi çekti. Kök neden analizimiz, hatalı kodun tam yerini belirlememizi ve çökmeyi yeniden oluşturmamızı sağladı. Sömürü senaryosunun göründüğünden daha zor olduğuna inanıyoruz.
Bu blog yazısının ana noktaları:
- ESET araştırmacıları, CVE-2025-50165 güvenlik açığına ilişkin, sözde kod parçacıklarıyla açıklanan derinlemesine bir analiz sunuyor.
- Basit bir 12 bit veya 16 bit JPG görüntüsü ve ilk yayımlanan yamanın incelenmesi yoluyla çökmeyi yeniden üretme yöntemimizi sunuyoruz.
- CVE-2025-50165, JPG görüntüsünün kod çözme sürecinde değil, kodlama ve sıkıştırma sürecinde bulunan bir kusurdur.
- Sonuçlarımızda, bu kusurun istismar edilebilirliği ve saldırı senaryosu araştırılmakta ve yeniden değerlendirilmektedir.
GENEL BAKIŞ
20 Kasım 2025’te Zscaler ThreatLabz, WindowsCodecs.dll’de bulunan ve yüksek etkili bir uzaktan kod yürütme güvenlik açığı olan CVE-2025-50165’in keşfini belgeleyen bir makale yayımladı. Bu kütüphane, JPG, PNG, GIF, BMP vb. gibi en yaygın görüntü dosyası formatlarını işlemekten sorumlu Windows’un ana arayüz kütüphanesidir. Zscaler’ın bulguları ve Microsoft tarafından sağlanan açıklama, bu kusurun Windows Görüntüleme Bileşeni’nin bir parçası olan WindowsCodecs.dll’deki başlatılmamış bir işlev işaretçisinin dereferansından kaynaklandığını ortaya koymaktadır. Zscaler, jpeg_finish_compress işlevinin içindeki dereferans sorununu tespit etmeyi başardı. Bu işlev, bir JPG görüntü akışı sıkıştırıldığında ve (yeniden) kodlandığında çağrılır. Görüntü işleme güvenlik açıkları söz konusu olduğunda ilk akla gelen, görüntü işlendiği anda ortaya çıkan ayrıştırma ve kod çözme hatalarıdır. Bu nedenle, bu oldukça spesifik güvenlik açığı içeren kod yolu, cevaplamak istediğimiz bazı sorular bırakmıştır:
- Başlatılmamış işlev işaretçisinin dereferansına yol açan güvenlik açığı içeren kod yolunu izlemek için tam olarak hangi koşullar gereklidir?
- jpeg_finish_compress ne zaman çağrılır?
- İşlev işaretçisi neden başlatılmıyor?
JPG görüntülerin web’de ne kadar yaygın olduğunu göz önünde bulundurarak cevaplar bulmak istedik ve bu nedenle çökmeye neden olan kodu araştırmaya başladık.
ÇÖKME YERİ
CVE-2025-50165 giriş açıklamasına göre, 10.0.26100.0 ve 10.0.26100.4946 öncesi WindowsCodecs.dll sürümleri etkilenmektedir. Güvenlik açığı bulunan 10.0.26100.4768 (SHA-1: 5887D96565749067564BABCD3DC5D107AB6666BD) sürümünü analiz ettik ve ardından ilk yamalı 10.0.26100.4946 (SHA-1: 4EC1DC0431432BC318E78C520387911EC44F84FC) ile ikili karşılaştırma yaptık. İlgili sembolleri indirdikten sonra, çökmeye neden olan jpeg_finish_compress işlevini inceledik. WindowsCodecs.dll dosyasında bulunan sürüm dizesine göre – libjpeg-turbo version 3.0.2 (build 20250529) – DLL, JPG görüntülerini işlemek için libjpeg-turbo kütüphanesinin oldukça eski bir uygulamasını (24 Ocak 2024 tarihinde yayımlanmıştır) kullanmaktadır. Halka açık depo, ilgili ikili kod ve yapıların çoğunu kaynak kod eşdeğerlerine eşlememizi sağladı. Örneğin, jpeg_finish_compress’in derlenmiş sürümü, Şekil1 ‘de gösterildiği gibi, burada bulunan kaynak kod eşdeğerine çok benziyor.

Şekil1 . Hex-Rays IDA decompiler’ın jpeg_finish_compress işlevinin çıktısı, alıntılanan kaynak koduna benzer.
Zscaler’ın bulgularına göre, çökme jpeg_finish_compress+0xCC adresinde meydana geliyor. Bu adres, Şekil1 adresindeki 48. satıra karşılık geliyor ve bilinmeyen bir yapının (pub) 0x10 ofsetinde bulunan bir işlev işaretçisinin referansı kaldırılırken ortaya çıkıyor. libjpeg-turbo kaynak koduna göre, bu adres compress_data_12 adlı bir işlev işaretçisine karşılık geliyor. Bu belirli yola ulaşmak için jpeg_compress_struct’un data_precision üyesi 12 olarak ayarlanmalıdır. Bu, bit derinliğine, başka bir deyişle renkleri tanımlamak için kullanılan bit sayısına karşılık gelir. Esasen, WindowsCodecs.dll, 12 bit hassasiyetli bir JPG görüntüsünü kodlamaya çalıştığında çökmektedir.
YAMA FARKI VE KÖK NEDEN ANALİZİ
İkili fark bulma aracı Diaphora’yı kullanarak, Şekil2 ‘de gösterildiği gibi, güvenlik açığı bulunan 10.0.26100.4768 sürümü ile yamalı 10.0.26100.4946 sürümü arasında bir fark bulma işlemi gerçekleştirdik.

Şekil2 . Diaphora, her iki kütüphane arasında kısmen eşleşen ve eşleşmeyen işlevleri başarıyla vurguladı.
Şaşırtıcı bir şekilde, makalede bahsedilen çökme fonksiyonu jpeg_finish_compress mevcut değildir. Ancak iki kodlama ile ilgili fonksiyon değiştirilmiştir: rawtransencode_master_selection ve jinit_c_rawtranscode_coef_controller_turbo. Rawtransencode_master_selection’ın savunmasız ve yamalı sürümleri arasındaki fark Şekil3 ‘te gösterilmektedir.

Şekil3 . rawtransencode_master_selection işlevinin güvenlik açığı bulunan (solda) ve yamalanmış (sağda) sürümleri arasındaki farklar
Tek ilgili fark, daha önce rawtransencode_master_selection işlevinin gövdesinde satır içi olarak bulunan jinit_c_rawtranscode_coef_controller_turbo işlevinin artık ayrılmış olmasıdır. jinit_c_rawtranscode_coef_controller_turbo işlevinin yamalı sürümüne bakıldığında daha önce başlatılmamış olan yapı üyesi compress_data_12’nin artık Şekil4 ‘te gösterildiği gibi rawtranscode_compress_output_16 adlı bir işlevi işaret edecek şekilde ayarlandığı görülmektedir.

Şekil4 . jinit_c_rawtranscode_coef_controller_turbo işlevinin yamalı sürümü
Güvenlik açığı bulunan sürümde de başlatılmamış olan compress_data_16 alanı, yamalı sürümde de rawtranscode_compress_output_16 işlevini işaret edecek şekilde ayarlanmıştır. Bu işlev, rawtranscode_compress_output işlevini çağıran basit bir stub işlevidir, bu da 12 bit veya 16 bit hassasiyetli JPG görüntülerini işlemek için özel bir kod bulunmadığını gösterebilir.
ÇÖKMENİN YENİDEN ÜRETİLMESİ
Zscaler’ın makalesinde belirtildiği gibi, Microsoft tarafından önerilen kod parçasını (https://learn.microsoft.com/en-us/windows/win32/wic/-wic-codec-jpegmetadataencoding#jpeg-re-encode-example-code) derleyerek bir JPG görüntüsünü kod çözebilir ve yeniden kodlayabilirsiniz.
Bu program derlendikten sonra, 12 bit veya 16 bit JPG dosyası sağlayarak çökme yeniden üretilebilir. Libjpeg-turbo deposundaki örnekleri inceleyerek, 12 bit hassasiyetli örnek bir görüntüyü https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/testimages/testorig12.jpg adresinden indirebilirsiniz. Bu görüntüyü yeniden kodlama örnek uygulamasına beslemek, Zscaler’ın makalesinde bahsedilen tam olarak aynı konumda bir çökmeye neden oldu. Şekil5 , hata ayıklama oturumu sırasında çökmenin bağlamını göstermektedir.

Şekil5 . Yeniden kodlama örnek uygulaması, 12 bitlik bir JPG görüntüsünü işlerken sıkıştırma rutini sırasında çöküyor.
Bellek adresinin işaret ettiği tekrarlanan 0xBAADF00D onaltılık değeri, bir program bellek ayırmak için HeapAlloc işleviniçağırdığında C çalışma zamanı (CRT) yığını tarafından kullanılan bir sihirli değerdir. Bu değer, belleği başlatılmamış olarak işaretler (bkz. https://www.nobugs.org/developer/win32/debug_crt_heap.html).
Daha önce belirtildiği gibi, analiz edilen WindowsCodecs.dll sürümlerinin her ikisi de 16 bit hassasiyetli JPG görüntülerini işleyebiliyor gibi görünüyor. Ancak bu tür görüntüleri test ederken Şekil6 ‘da görüldüğü gibi, compress_data_16 işlev işaretçisinin referansı kaldırıldığında yeniden kodlama uygulaması çöküyor.

Şekil6 . Yeniden kodlama örnek uygulaması, 16 bitlik bir JPG görüntüsünü işlerken sıkıştırma rutini sırasında çöküyor
Çökmeyi yeniden oluşturduktan sonra, bu özel güvenlik açığının libjpeg-turbo kütüphanesinin kaynak kodunda da mevcut olup olmadığını merak ettik.
KAYNAK KODUNU İNCELEME
libjpeg-turbo’nun commit’lerini inceleyerek, benzer sorunların 18 Aralık 2024’te e0e18de commit’iyle 3.1.1 sürümünün tanıtılmasıyla çözüldüğünü ortaya çıkardık. Esasen, bu commit, yapıların sıfırla başlatılmasını ve bir işaretçi NULL ise bir hata verilmesi sağlanır. Bu commit ile getirilen tüm sıfırla başlatma ve kontroller, WindowsCodecs.dll’nin güvenlik açığı bulunan ve yamalanmış sürümlerinde bulunmamaktadır.
Yama mesajı, diğer potansiyel savunmasız kod yollarını da ima etmekte ve daha da önemlisi, Şekil7 adresinde gösterilen jdapistd.c dosyasının farkı ile vurgulandığı gibi, JPG görüntüsünü işlerken sıkıştırma açma işleminde de çökmelerin meydana gelebileceğini belirtmektedir.

Şekil7 . jdapistd.c dosyasında uygulanan sıkıştırma açma rutinlerinin farkı
Commit açıklamasında açıkça belirtildiği gibi, çağıran uygulama (başlatılmamış bir işlev işaretçisinin dereferansı nedeniyle) yalnızca jpeg_start_compress veya jpeg_start_decompress rutinlerini çağırdıktan sonra data_precision alanını hatalı bir şekilde değiştirirse çöker. Bu, WindowsCodecs.dll kullanan bir uygulamanın iç yapıların durumunu değiştireceği oldukça spesifik ve muhtemelen gerçekçi olmayan bir senaryo oluşturur. Bu tür uygulamalar mevcut olsa da Windows Görüntüleme Bileşeni API’sı bu tür davranışlara izin vermiyor gibi görünmektedir.
KULLANILABİLİRLİK
Kök neden analizimizin ortaya koyduğu gibi, CVE-2025-50165’in temel sorunu, WindowsCodecs.dll’nin geleneksel ve standart 8 bit dışındaki veri hassasiyet değerine sahip JPG görüntülerini işleme biçiminde yatmaktadır. İki hassasiyet özel işlev işaretçisi (compress_data_12 ve compress_data_16) sıkıştırma işlemi sırasında başlatılmamış ve yalnızca bir JPG görüntüsünü (yeniden) kodlarken erişilebilir gibi görünen iki savunmasız kod yolu oluşturmuştur. Özel olarak hazırlanmış bir görüntüyü açmak, dolayısıyla kodunu çözmek ve görüntülemek, güvenlik açığını tetiklemez. Ancak görüntü kaydedildiğinde veya Microsoft Photos uygulaması gibi bir ana uygulama, Şekil8 ‘de gösterildiği gibi görüntülerin küçük resimlerini oluşturduğunda güvenlik açığına sahip jpeg_finish_compress işlevi çağrılabilir.

Şekil8 . Güvenlik açığı bulunan jpeg_finish_compress işlevi, bir görüntünün küçük resmi oluşturulurken çağrılır.
Bir programın güvenlik açığına sahip olarak kabul edilebilmesi için aşağıdaki özelliklere sahip olması gerekir:
- WindowsCodecs.dll dosyasının güvenlik açığı bulunan bir sürümünü kullanır,
- 12 bit veya 16 bit JPG dosyasını kod çözme sırasında çökmez veya iptal etmez ve
- görüntünün yeniden kodlanmasına izin verir.
Ayrıca Zscaler araştırmacılarının belirttiği gibi, bu güvenlik açığını istismar etmek için adres sızıntısı ve yığın üzerinde yeterli kontrol zorunludur.
SONUÇ
JPG daha eski, yaygın olarak kullanılan ve belki de bulanık testlerde en popüler dijital görüntü formatı olmasına rağmen bazı kodeklerde hâlâ güvenlik açıkları bulunabilir. CVE-2025-50165 ile ilgili bu çalışma, üçüncü taraf kitaplıkları kullanırken güvenlik güncellemelerini takip etmenin önemini de vurgulamaktadır.
Kök neden analizi ve yama karşılaştırması, ilk sorularımızı yanıtlamamızı sağlayan çok güçlü bir kombinasyon olduğunu kanıtladı. WindowsCodecs.dll, 12 bit veya 16 bit hassasiyetli bir JPG akışını kodladığında her iki hassasiyet özel işlev işaretçisi de dereferanslanmadan önce başlatılmadığı veya kontrol edilmediği için hatanın tetiklenebileceğini keşfettik. Ayrıca bu işlemin böyle bir görüntü kaydedildiğinde veya ondan bir küçük resim oluşturulduğunda gerçekleştiğini de anladık.
Bu araştırma, bu güvenlik açığının istismar edilebilirliği konusunda Microsoft’un vardığı sonuçla benzer bir sonuca ulaşmamızı sağladı. Nitekim, WindowsCodecs.dll bir kütüphane olduğundan JPG görüntülerinin (yeniden) kodlanmasına izin veren bir ana uygulama güvenlik açığına sahip kabul edilir ve yalnızca saldırganın uygulama üzerinde yeterli kontrole sahip olması durumunda (adres sızıntısı, yığın manipülasyonu) istismar edilebilir. Tüm bunları bir araya getirdiğimizde istismar olasılığının gerçekten düşük olduğu görülüyor.
Son olarak, bu yazının yazıldığı tarihte ve yaptığımız testlere göre, WindowsCodecs.dll dosyasının yeni sürümlerinde (örneğin 10.0.22621.6133, SHA-1: 3F3767D05E5A91184005D98427074711F68D9950) libjpeg-turbo’nun taahhüdünde belirtilen farklı değişiklikleri uygulayarak başlatma ve işlev işaretçisi doğrulamasının eksikliğini etkili bir şekilde gidermektedir.