1 puan yazan GN⁺ 2025-03-16 | 1 yorum | WhatsApp'ta paylaş
  • ruby-saml 1.17.0 ve öncesinde bulunan CVE-2025-25291 ve CVE-2025-25292, tek bir geçerli imzayla herhangi bir kullanıcı olarak oturum açmayı mümkün kılarak SAML SSO ortamlarında hesap ele geçirme riskini artırıyor
  • Açık, imza doğrulama akışında REXML ile Nokogiri'nin aynı XML belgesindeki farklı Signature öğelerini yorumlayabilmesine yol açan ayrıştırıcı farkından kaynaklanıyor
  • SignedInfo, SignatureValue, assertion hash'i ve DigestValue, farklı ayrıştırıcı sonuçlarından bir araya gelirken her kontrol geçse de hash ile imza arasındaki bağ kopabiliyor
  • GitHub, ruby-saml'i yeniden devreye almayı değerlendirirken bug bounty ve Security Lab incelemesi yürüttü; GitLab'de istismar edilebilir örnekler bulup güvenlik ekibine bildirdi; şu anda GitHub kimlik doğrulamasında ruby-saml kullanılmıyor
  • Kullanıcıların ruby-saml 1.18.0 sürümüne güncellemesi gerekiyor; omniauth-saml gibi ruby-saml'e bağlı kütüphaneler de düzeltilmiş sürümü referans alan bir sürüme birlikte yükseltilmeli

ruby-saml kimlik doğrulama atlatmasının etkisi

  • ruby-saml 1.17.0 ve öncesinde yüksek önem dereceli 2 kimlik doğrulama atlatma açığı tespit edildi
    • CVE-2025-25291
    • CVE-2025-25292
  • Saldırgan, hedef kuruluşun SAML response veya assertion doğrulamasında kullanılan anahtarla üretilmiş tek bir geçerli imzaya sahipse doğrudan bir SAML assertion oluşturup istediği kullanıcı olarak oturum açabiliyor
  • Olası imza kaynakları şunlar olabilir
    • Yetkisi düşük başka bir kullanıcının imzalı assertion'ı veya response'u
    • Bazı durumlarda, herkese açık erişilebilen bir SAML IdP'nin imzalı metadata'sı
  • Bu açık sonuç olarak hesap ele geçirme saldırılarında kullanılabiliyor
  • GitHub şu anda kimlik doğrulamada ruby-saml kullanmıyor; ancak SAML kimlik doğrulamasında açık kaynaklı bir kütüphaneyi yeniden kullanma seçeneğini değerlendirirken ruby-saml'i incelemeye aldı
  • ruby-saml başka popüler projelerde ve ürünlerde de kullanılıyor; GitHub, GitLab'de istismar edilebilir bir örnek tespit ederek GitLab güvenlik ekibine bildirdi

GitHub neden ruby-saml'i yeniden değerlendirdi?

  • GitHub 2014'e kadar ruby-saml kullanıyordu, ancak o dönemde gerekli özellikler eksik olduğu için kendi SAML uygulamasına geçti
  • Sonrasında kendi uygulamasında da şifrelenmiş assertion'larla ilgili CVE-2024-9487 gibi bug bounty raporları gelince GitHub, ruby-saml'i yeniden devreye alma seçeneğini değerlendirmeye başladı
  • Ekim 2024'te ahacker1 tarafından bulunan ruby-saml kimlik doğrulama atlatma açığı CVE-2024-45409 kamuya açıklandı
  • GitHub, ruby-saml'e geçiş olasılığını daha yakından değerlendirmek için özel bir bug bounty başlattı
    • Seçilen araştırmacılara, ruby-saml ile SAML kimlik doğrulaması yapan GitHub test ortamına erişim sağlandı
    • GitHub Security Lab de ruby-saml'in saldırı yüzeyini birlikte inceledi

İki XML ayrıştırıcısının oluşturduğu doğrulama tutarsızlığı

  • Kod incelemesi sırasında ahacker1 ve GitHub Security Lab, ruby-saml'in imza doğrulama yolunda iki XML ayrıştırıcısının birlikte kullanıldığını belirledi
    • REXML: Tamamen Ruby ile yazılmış bir XML ayrıştırıcısı
    • Nokogiri: libxml2, libgumbo ve JRuby için Xerces gibi bileşenleri saran API'ler sunar ve XML ile HTML ayrıştırmayı destekler
  • Sorunlu akış xml_security.rb içindeki validate_signature metoduydu
  • Bu metod ilk Signature öğesini ve gerçek SignatureValue değerini REXML ile okuyor
    • REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
  • Buna karşılık aynı doğrulama akışı içinde Signature ve SignedInfo, Nokogiri ile yeniden bulunup canonicalize ediliyor
    • document.at_xpath('//ds:Signature', 'ds' => DSIG)
    • noko_signed_info_element.canonicalize(canon_algorithm)
  • assertion, Nokogiri ile çıkarılıp canonicalize edilip hash'lenirken karşılaştırma için kullanılan DigestValue REXML'den geliyor
  • Son doğrulama malzemesi şu şekilde ayrışıyor
    • assertion, Nokogiri ile çıkarılıp canonicalize edildikten sonra hash'leniyor
    • karşılaştırılan hash, REXML'in okuduğu DigestValue değerinden geliyor
    • SignedInfo, Nokogiri ile çıkarılıp canonicalize ediliyor
    • SignatureValue, REXML ile çıkarılıyor

SAML imza doğrulamasında kopan güvenlik bağı

  • SAML response, IdP'den SP'ye oturum açan kullanıcı bilgisini XML biçiminde taşır
  • HTTP POST binding kullanıldığında SAML response kullanıcının tarayıcısından geçerek SP'ye ulaştığı için, kullanıcının mesajı değiştirememesini sağlamak adına imza doğrulaması gerekir
  • Basitleştirilmiş bir SAML response'ta önemli bilgiler genellikle Assertion içindeki Subject ve NameID alanlarında bulunur
  • Genellikle assertion veya tüm SAML response imzalanabilir
  • assertion imzalıysa doğrulama iki adımda yapılır
    • Signature çıkarılmış assertion canonicalize edilip hash'lenir ve DigestValue ile karşılaştırılır
    • SignedInfo canonicalize edilir ve SignatureValue ile imza doğrulanır
  • Bu açıkta iki adım ayrı ayrı başarılı olsa bile aynı veriyi doğruladıkları garanti edilmez
    • hash gerçek assertion'ın hash'i olabilir
    • imza ise başka bir SignedInfo öğesine ait olabilir
  • Gerekli güvenlik özelliği, hash'lenen içerik, hash ve imza arasında doğrudan bağ kurulmasıdır; doğrulama sonrasında da bilgi yalnızca gerçekten doğrulanmış bölümden okunmalıdır

Gerçek istismarın nasıl kurulduğu

  • Temel koşul, REXML ile Nokogiri'nin aynı XML belgesinde farklı Signature öğeleri görmesini sağlamaktı ve bunun gerçekten mümkün olduğu gösterildi
  • ahacker1, bug bounty sürecinde önce ayrıştırıcı farkına dayalı çalışan bir istismar geliştirdi
  • GitHub Security Lab ise Trail of Bits'in Ruby fuzz aracı ruzzy ile başka bir ayrıştırıcı farkı tabanlı istismar oluşturdu
  • Örnek istismar, StatusDetail öğesi içine yalnızca Nokogiri'nin görebildiği ek bir Signature yerleştiriyor
  • Doğrulama akışı şu şekilde ayrılıyor
    • Nokogiri'nin gördüğü signature içindeki SignedInfo canonicalize ediliyor
    • doğrulama, REXML'in gördüğü signature'dan çıkarılan SignatureValue ile yapılıyor
    • Nokogiri'nin ID ile bulduğu assertion canonicalize edilip hash'leniyor
    • bu hash, REXML'in okuduğu DigestValue ile karşılaştırılıyor
  • Sonuçta geçerli SignedInfo ile geçerli imza birbiriyle uyuşuyor; manipüle edilmiş assertion ile onun hesaplanan digest'i de uyuştuğu için ruby-saml assertion'ı kabul ediyor

Azaltma önlemleri ve tespit sınırlamaları

  • SAML response Nokogiri ile ayrıştırılırken ayrıştırma hatalarının kontrol edilmesi, şu anda bilinen bazı özel istismarları engelleyebilir
  • Nokogiri ayrıştırma hataları istisna olarak fırlatılmadığı için, ayrıştırılmış belgenin errors üyesi doğrudan kontrol edilmelidir
  • Örnek kod Nokogiri::XML::ParseOptions::STRICT | Nokogiri::XML::ParseOptions::NONET seçeneklerini kullanıyor ve doc.errors.any? olduğunda hata üretiyor
  • Bu yaklaşım tam bir düzeltme olmasa da, en az bir istismarı çalışamaz hale getiriyor
  • Bilinen güvenilir bir ihlal göstergesi yok
    • Olası bir gösterge yalnızca debug benzeri ortamlarda çalışıyor
    • Bunu açıklamak, çalışan istismarın uygulama ayrıntılarını fazla ortaya çıkaracağı için paylaşılmadı
  • Önerilen kontrol yöntemi, SP tarafında kullanıcının beklenen konumuyla uyuşmayan IP adreslerinden gelen SAML oturum açma kayıtları gibi şüpheli girişleri aramaktır

Düzeltme yönü ve güncellenmesi gerekenler

  • İlk düzeltme, API uyumluluğu sorunları nedeniyle XML ayrıştırıcılardan birini kaldırmıyor
  • Daha temel sorun, hash doğrulaması ile imza doğrulamasının ayrılmış olmasıydı ve bu ayrım ayrıştırıcı farkları üzerinden istismar edilebildi
  • XML ayrıştırıcılardan birini kaldırma çalışması zaten başka nedenlerle planlanmıştı; ek iyileştirmelerle birlikte büyük bir sürümde yapılması mümkün görünüyor
  • ruby-saml kullanıcıları, düzeltmeyi içeren 1.18.0 sürümüne güncelleme yapmalı
  • ruby-saml kullanan kütüphaneler de birlikte kontrol edilmeli
    • Örnek: omniauth-saml
    • Bu kütüphane de düzeltilmiş ruby-saml sürümünü referans alan bir sürüme güncellenmeli
  • GitHub Security Lab, ileride GitHub Security Lab repository içinde kavram kanıtı istismar kodunu yayımlamayı planlıyor

Açıklama ve müdahale takvimi

  • 2024-11-04: ruby-saml ile SAML kimlik doğrulamasını değerlendiren GitHub test ortamı için kimlik doğrulama atlatmasını kanıtlayan bug bounty raporu alındı
  • 2024-11-04: Olası azaltma yöntemlerini belirleme ve test çalışmaları başladı
  • 2024-11-12: İlk azaltma planını etkisiz kılan ikinci bir kimlik doğrulama atlatması bulundu
  • 2024-11-13: ruby-saml maintainer'ı Sixto Martín ile ilk temas kuruldu
  • 2024-11-14: İki ayrıştırıcı farkı ruby-saml'e bildirildi ve maintainer hemen yanıt verdi
  • 2024-11-14: maintainer ile ahacker1 olası yama üzerinde çalışmaya başladı
    • İlk fikirlerden biri XML ayrıştırıcılardan birini kaldırmaktı, ancak geriye dönük uyumluluğu bozmadan bu mümkün olmadı
  • 2025-02-04: ahacker1, geriye dönük uyumluluğu olmayan bir düzeltme önerdi
  • 2025-02-06: ahacker1, geriye dönük uyumlu bir düzeltme de önerdi
  • 2025-02-12: GitHub Security Lab advisory için 90 günlük süre doldu
  • 2025-02-16: maintainer, geriye dönük uyumluluğu koruyan ve anlaşılması kolay bir düzeltme yaklaşımı üzerinde çalışmaya başladı
  • 2025-02-17: ruby-saml sürümü ile GitLab on-premises ürün sürümünü koordine etmek için GitLab ile ilk temas kuruldu
  • 2025-03-12: Düzeltilmiş ruby-saml sürümü yayımlandı

1 yorum

 
GN⁺ 2025-03-16
Hacker News yorumları
  • GitHub’ın SAML implementasyonunun işe yaramaz olduğunu düşünüyorum.
    Asıl amaç kişisel hesapları enterprise ortama getirip kullanmak; GitHub sitesinin içinde bir ölçüde çalışıyor ama GitHub ile giriş yapan bir uygulama organizasyon düzeyinde onaylandıktan sonra organizasyon üyeliklerini okumasını engellemiyor.
    SAML oturumu yalnızca ilgili uygulama o kullanıcıdan aldığı token ile veri çekerken gerekli oluyor; pratikte ise SAST araçları neredeyse her zaman uygulama instance token’ı kullanıyor ve organizasyon içinde bir GitHub hesabı olduğu sürece kodu gösteriyordu.
    Tailscale’e bildirince düzeltti; Sonarcloud kimseye söylemememi istedi; GitHub ise birkaç hafta sonra “tamamen beklenen davranış” diye yanıt verdi. Ama bildirdiğim hiçbir vendor bunu böyle anlamamıştı ve dokümantasyon da GitHub’ın yanıtıyla çelişiyordu.
    Güvenlik bug’ı bildirmek, tesadüfen bulsanız bile tatmin edici olmayan bir iş; bunu meslek olarak yapmayı hayal etmek zor.

    • “Kişisel hesabı enterprise’a getirme” yaklaşımı, yetkilendirmenin ötesinde sorunlar da yaratıyor.
      GitHub’ın, iş PR’larını merge ederken çok nadiren kişisel e-posta adresini varsayılan olarak kullandığı olmuştu; biri sorarsa, GitHub’da ya da başka yerde kişisel ve iş amaçlı kullanımı aynı hesapta karıştırmamasını öneririm.
    • Vendor tarafını da bir ölçüde anlayabiliyorum; çünkü GitHub burada doğru implementasyonu yapmayı aşırı zorlaştırıyor.
      Depo/commit/PR analiz aracı olan https://dev.log.xyz’yi geliştirirken “GitHub’da görülebilen şey Devlog’da da görülebilir” ilkesini tutturmak için çok uğraştık ve tüm deneyim çok bunaltıcıydı.
      GitHub’ın OAuth izin seçicisi de gereğinden fazla kafa karıştırıcı; “GitHub ile giriş yap” sırasında hangi organizasyonun hangi bilgisinin paylaşıldığından emin olmak zor.
    • Bu işletim biçimi her katmanda tekrarlanıyor.
      JavaScript’e aşina genç bir geliştiriciyi istemci tarafı doğrulamanın tek başına yeterli olmadığına ikna etmek bile zor; özellik gereksinimlerini ve bütçeyi belirleyen işletme sahiplerini ikna etmek daha da zor.
    • Paylaşılan kimlik bilgilerinden gelen kolaylık ve SSO ile güvenliğin artabileceği varsayımı, böyle tek bir açıkla çöküyor.
      Herhangi bir tür parola kasası, hatta fiziksel bir kasa ya da parolaların yeniden kullanılması bile sonuçta daha güvenli hale gelebilir.
      Sonuçta minimalizm yine kazanmış oluyor.
    • Yukarıdakileri bu açık araştırmasıyla ilişkilendirmeye çalışanlar için: bu bağlantılı görünmüyor.
      “GitHub doesn’t currently use ruby-saml for authentication, but began evaluating the use of the library with the intention of using an open source library for SAML authentication once more” deniyor.
  • Yakın zamanda SAML implementasyonu yapmak zorunda kaldım; bu başlık hiç şaşırtıcı gelmedi.
    SAML spesifikasyonunun kendisi oldukça makul, ama dayandığı XML imzaları, hatta daha da ötesinde XML canonicalization, eğer buna standart denebilirse, gerçekten akıl almaz düzeyde.
    Böyle çarpık ve bozulmuş bir spesifikasyonu ancak bir komite üretebilir; tek bir kişinin zihni bu kadar çelişkili fikirleri bir arada tutup birleştiremezdi gibi geliyor.
    İmzayı sadece out-of-band iletmek bile SAML’yi implementasyonu keyifli bir şey haline getirirdi.

    • Söylediğinden çok daha kötü.
      XML kelimenin tam anlamıyla eXtensible Markup Language iken, SAML standardizasyon komitesi bunun üstüne bir de kendilerine ait genişletme mekanizması dili icat etmiş.
      Bir kimlik doğrulama çerezine girecek bilgiden pek de farklı olmayan küçücük bir veri için protokol üstüne protokol bindirmek, ancak en büyük ve en bürokratik komitelerin üretebileceği özel bir aptallık türü.
    • SSO baştan kurtarılabilir bir şey mi, emin değilim.
      Farklı hesaplara ayrı ayrı giriş yapma fikrinin kendisi makul görünüyor.
      Hesapları birbirine bağlayıp tek seferde büyük ölçekli ele geçirilmeye açık hale getiren yapı ise temelden daha riskli.
  • SAML, daha geniş anlamda XML-DSIG, yaygın kullanılan güvenlik protokolleri arasında kelimenin tam anlamıyla en kötüsü bence.
    Genel olarak ne pahasına olursa olsun OAuth’a geçilmeli; en azından yeni bir ürünü piyasaya çıkarırken buna dayanmayı reddederdim.
    Çok tehlikeli ve pratik biçim doğrulamada bir atılım olmadığı sürece bunun son DSIG açığı ya da en kötü açık olacağını hayal etmek zor.

    • Bir gün XML DSig’in yaptığı inanılmaz aptalca şeylerin hepsini yazacağım.
      Kriptografiye daha dokunmadan bile enterprise yazılım düşüncesinin zirvesi bu.
      Birilerinin WS-* ve OASIS/XACML gibi şeylerin mailing list’lerini ve standardizasyon kurumlarındaki felaketi derinlemesine kazması gerekiyor.
    • Security Cryptography Whatever’ın bu haftaki SAML curcunasını nasıl ele alacağını görmek eğlenceli olacak.
    • Anladığım doğruysa, SAML’de SSO sağlayıcısının oturumu iptal edebilmesi gibi ayırt edici bir özellik hâlâ var.
      Doğru mu?
  • Ugh, başka seçenek yoksa dışında kimse REXML kullanmamalı.
    Hatalı XML’i bile seve seve parse ediyor ve sonraki aşamalarda sonsuz sayıda soruna yol açıyor.
    Kelimenin tam anlamıyla XML’i düzenli ifadelerle parse ediyor; bunun neden yapılmaması gerektiğini gösteren harika bir örnek.
    Projeler Nokogiri kullanmaya performans için değil, doğruluk için başladı.

    • Ders kitaplık örnek değil mi?
      Düzenli dil olmayan bir şeyi düzenli ifadelerle parse etmeyin.
    • Yapay zeka kod yardımcılarının risklerinden biri, büyük kod tabanlarında kullanılan kütüphanenin daha geniş bağlamını mutlaka görmemeleri.
      Yakın zamanda o3’ü test ettim; belirli bir kod bloğundaki kütüphaneyle ilgisiz bir sorunu düzeltmeye çalıştığında, o bloğun kullandığı kütüphaneyi sürekli değiştiriyordu.
      Sonnet’te böyle bir şey görmedim.
      Bu şekilde düzeltme sürecinde, kod tabanında ya da standart kütüphanede zaten bulunduğu için testleri geçen ve Gemfile değişikliği de gerektirmeyen daha düşük nitelikli bir kütüphaneye/gem’e geçilerek sorunun içeri sızması kolay görünüyor.
  • SAML tasarımı gereği güvenli değil
    Eskiden beri bunu daha iyi açıklayan yazılar var; örneğin https://joonas.fi/2021/08/saml-is-insecure-by-design/
    Buradaki eski bir başlıktan aklımda kalan ifade “anlama değil, baytlara imza at” idi
    Ayrıştırıcılar arasındaki farklar öngörülebilir ve bazen kaçınılmazdır
    İmzalı yanıttan ne elde etmeye çalıştığınız çok önemlidir
    Modern TLS’in ikilemlerinden biri şu: bazen tek bir dahili CA’ya güvenmek istersiniz ve bu kolay yoldur; ancak bir iş ortağının CA sertifikasını kabul ediyorsanız ve birden fazla iş ortağınız varsa, artık yalnızca uç sertifikaya bakamazsınız, zincirin kökü de karar verme sürecinde aynı derecede önemli hale gelir
    Bu yüzden mümkünse AWS imza algoritmasından da kaçınmayı öneririm
    V4 teoride güvenli, ancak AWS bunu iki kez berbat etti; SigV1 ve SigV3 tasarım gereği güvenli olmamasına rağmen her nasılsa tasarım incelemesinden geçip kamuya açıldı

  • Harika bir yazı
    Yazıda da belirtildiği gibi, ahacker1 büyük bir alkışı hak ediyor
    SAML uygulamalarını güvenli hale getirmek için çok incelikli ve değerli işler yapıyor; SSOReady de onun çalışmalarına gerçekten minnettar
    Bu haftanın başında WorkOS da ahacker1 ile işbirliği hakkında güzel bir yazı yayımladı: https://workos.com/blog/samlstorm

  • “GitLab’da bu açığın istismar edilebilir bir örneğini bulduk ve güvenlik ekibine bildirdik” kısmı var; merak edenler için, GitLab düzeltmeyi zaten yayımladı
    https://about.gitlab.com/releases/2025/03/12/patch-release-g...

  • İlgili bir yazı olarak Latacora’nın 2019 tarihli How (not) to sign a JSON object[1] yazısı var
    Özetle, ağaç yapılarını iç içe geçirerek imzalamak zor ve tuzaklarla dolu bir iş
    Zarfın mesajı ham bir dize olarak taşıması ve o ham dizenin imzalanması daha kolaydır
    [1]: https://www.latacora.com/blog/2019/07/24/how-not-to/

  • Buradaki daha basit sonuç, imzanın olması gereken yerde imzayı aramak değil mi?
    “//ds:Signature” gibi aşırı genel bir XPath kullanıp beklenmedik bir konumdaki herhangi bir imzayı bulmaya çalışmayın

    • Güvenlik açıklarına verilen tepkilerin genellikle fazla gevşek olduğunu düşünüyorum
      Yalnızca tehlikeli bileşeni cerrahi biçimde çıkarmak değil; biraz da bebeği banyo suyuyla birlikte atmak, geniş çaplı kesip biçmek ve kemoterapi uygular gibi davranmak gerekir
      Kendine saygısı olan bir BT yöneticisi, gelecek planlarından SAML’i çıkarmalı
      SSO fikrinin tamamı da şüpheli; XML ayrıştırma haftada iki kez darbe yediğine göre bundan sonra kaçınılmalı
      XML’i JSON ile değiştirme politikasında ne sorun var?
    • Biraz sert söylemek gerekirse, sonuç şu: büyük bir sopa alıp web geliştiricilerinin güvenlik açısından hassas koda yaklaşmasını engellemek gerekir
      Tasarım, protokoller ve veri biçimleri düzeyinden başlayarak böyle olmalı
      Genel web geliştirme alışkanlıkları ve tasarım kaygıları, güvenlik kodunun gerektirdikleriyle uyuşmaz; çoğu zaman doğru kod yazmak için gerekenlerin de tam tersidir
  • Blog yazısının açığı anlatırken asıl sorun olan ayrıştırıcı farkını atlaması biraz sinir bozucu
    Hikâyenin girişini yazıp doruk noktasını atlamak gibi

    • Kardeş yorumdaki blog yazısında <https://news.ycombinator.com/item?id=43374972> bununla ilgili ayrıntılar vardı
      (...//ds:DigestValue).firstChild.nodeValue yapılırken .firstChild’ın Node olup olmadığı kontrol edilmemiş; sorunlu durumda bu bir Comment idi
      Bu yüzden normalleştirilmemiş taraf “gizlenmiş” imzayı gördü, yorumu atan düzeltilmiş taraf ise Node’u gördü; iki uygulama imzalı belge hakkında farklı hüküm verince tatsız şeyler oluyor
    • Dünya çapında sayısız sistemde yetki atlamayı mümkün kılan bir sıfırıncı gün açığını, o sistemlerin sorumluları düzeltme fırsatı bulmadan doğrudan açıklamanın sorumluluğunu üstlenmek istememiş gibi görünüyor
      Somut ayrıntılar yakında ortaya çıkar herhalde