Bu yazıda, ruby-saml kütüphanesinde bulunan bazı davranış farklılıklarını kullanarak round-trip saldırıları ve namespace confusion (isim alanı karışıklığı) tekniklerinin nasıl birleştirilebileceğini ve bunun GitLab üzerinde kimlik doğrulaması olmadan yönetici yetkileri elde edilmesine nasıl yol açabileceğini ayrıntılı biçimde ele alacağız.
REXML, belgeyi ayrıştırır ve dijital imzayı doğrular.
Nokogiri, belgedeki özniteliklere (attribute’lara) erişmek için kullanılır.
Eğer bu iki aşama arasında belge üzerinde herhangi bir biçimsel değişiklik oluşursa, XML belgesi ikinci kez ayrıştırıldığında ilk haliyle tamamen aynı olmayabilir.
Yetkilendirme işleminin güvenli olabilmesi için belgenin her aşamada tutarlı biçimde işlenmesi gerekir. Aksi halde yapısal farklılıklar ortaya çıkabilir. Bu farklılıklar, round-trip saldırıları olarak adlandırılan yöntemlerle kötüye kullanılabilir. XML yorum satırları (comments) ve CDATA bölümleri kullanılarak, belge dönüşüm sırasında yapısal olarak değiştirilebilir ve bu durum imza doğrulamasının beklenen şekilde çalışmamasına yol açabilir. Sonuç olarak, sistem farklı bir kullanıcıya ait bir kimlik bilgisini geçerli kabul edebilir.
Ruby-SAML / REXML Üzerinde Round-Trip Analizi
Bu tür davranış farklılıklarını tespit edebilmek için, round-trip zafiyetlerini inceleyen ve birden fazla SAML kütüphanesini karşılaştırmaya olanak tanıyan bir test ortamı geliştirildi. İlk olarak Document Type Definition (DOCTYPE) bölümüne odaklandık, çünkü geçmişte benzer sorunlar bu alanda ortaya çıkmıştı. Özellikle XML entity’lerinin nasıl yorumlandığını inceleyerek testler gerçekleştirdik.
Juho’nun ilk çalışmasında, tırnak işaretlerinin farklı yorumlanmasına neden olan notation declaration kullanılmıştı. Bu yaklaşımdan yola çıkarak, benzer başka davranış farklılıklarının bulunup bulunmadığını araştırdık. Uzun süren denemeler sonucunda, SYSTEM identifier alanı içinde de beklenmeyen dönüşümlerin oluşabildiğini gözlemledik.
Belge ilk kez ayrıştırıldığında karşılaşılan ilk etiket, orijinal “assertion” etiketi olmaktadır:
Görüldüğü üzere, tek tırnakla tanımlanmış SYSTEM tanımlayıcısı çift tırnağa dönüştürülmektedir. Ancak tanımlayıcının kendi içinde zaten çift tırnaklar bulunduğundan, bu dönüşüm XML belgesinin sözdizimini değiştirir. Bunun sonucunda XML yorum satırı işlenir ve tamamen farklı bir düğüm (node) ortaya çıkar. bu dönüşümü daha sade ve etkili bir saldırı vektörüne dönüşmüştür:
Bu vektör, Ruby-SAML kütüphanesini kullanan GitLab ve benzeri tüm uygulamalarda belgenin manipüle edilmesi ve assertion öğelerinin sahte olarak oluşturulması yoluyla herhangi bir kullanıcı olarak oturum açılmasına olanak tanımaktadır. Ancak bu, saldırının yalnızca ilk aşamasıdır. Ekip arkadaşım Zak, bunun GitLab üzerinde kimlik doğrulaması olmadan yönetici erişimi elde edecek şekilde nasıl genişletilebileceğini gösterecektir.
Bir round-trip gerçekleşmeden önce, kütüphane SAMLResponse içerisinde geçerli bir sertifikanın gömülü olup olmadığını kontrol eder. Bu, sertifikanın karma (hash) değerinin hesaplanıp sunucuda kayıtlı olan parmak izi (fingerprint) ile karşılaştırılmasıyla yapılır. Daha sonra bu sertifika, dijital imzanın doğrulanmasında kullanılır. Bu noktada imza, saldırının kritik bir bileşenidir; çünkü kuruma ait gerçek kimlik bilgilerine sahip olmadan tam bir hesap ele geçirmeye imkân tanıyabilir.
Eğer saldırgan assertion öğesini imza doğrulamasını atlatacak şekilde oluşturursa, sistemde ek güvenlik kontrolleri devreye girer. En kritik kontroller şunlardır:
Burada ds, XML namespace’ini (isim alanını) ifade etmektedir. Normalde namespace’ler öğe adları arasındaki çakışmaları önler. Ancak XPath aramalarında namespace’lerin nasıl yorumlandığına dair bir tutarsızlıktan yararlanılmaktadır. Aşağıdaki senaryoyu ele alalım:”
İlk Signature öğesi doğrudan bir namespace tanımı içermez (xmlns="XML-Signature Syntax and Processing"). Bunun yerine bir XML Doctype tekniği kullanılır. Güvenlik uzmanları genellikle XXE saldırılarında !ENTITY bildirimlerine odaklanır; ancak !ATTLIST bildirimleri de benzer şekilde kullanılabilir. !ATTLIST, Signature öğesini tanımlar ve ona bir namespace özniteliği atar. Hem REXML hem de Nokogiri doctype tabanlı namespace tanımlarını destekler, ancak REXML’de kritik bir hata bulunmaktadır.”
XML standartları, aynı ada sahip birden fazla özniteliğin bulunmasını yasaklar.
Ancak REXML, doctype bildirimleri içinde bu kısıtlamayı yok sayar.
Bu durum, iki çelişen namespace özniteliğinin tanımlanmasına olanak tanır; ikinci tanım birincinin üzerine yazılır. Sonuç olarak REXML sahte (FAKE) bir Digest değerini okurken, Nokogiri gerçek (REAL) olanı okur.
İlk XML ayrıştırma: REXML, !ATTLIST değerini başlangıçta yok sayar ve bunu yalnızca bir metin dizisi (string literal) olarak ele alır.
İkinci XML ayrıştırma: REXML bu kez !ATTLIST bildirimini tanır; bu da söz konusu tekniğin tam olarak etkili olmasına yol açar.
Federasyon metadata belgeleri, yetkisiz kullanıcılar dâhil herkes tarafından erişilebilir durumdadır. Bunun için yalnızca uygulamaya ait benzersiz kimlik (application ID) gerekir; bu bilgi genellikle IdP’nin URL’sinden çıkarılabilir ya da bir arama motoru yardımıyla bulunabilir.
Bu metadata belgesi, geçerli bir SAML metadata belgesi olmasa da, namespace confusion yaklaşımı açısından yalnızca geçerli bir Signature öğesi yeterlidir. Önemli olan bu imzanın, Hizmet Sağlayıcıda (Service Provider) kayıtlı olan sertifikayla imzalanmış olmasıdır ve bu koşul sağlanmaktadır.
Bu herkese açık imzalı belge kullanılarak aşağıdaki adımlar mümkün olur:
Öne çıkan noktalar:
Bir Çeviridir üstüne eklentiler yapılmıştır.
Round-Trip Saldırılarına Giriş
SAML kütüphaneleri çoğu zaman bir XML belgesini okur, onu bir metin dizisi olarak saklar ve daha sonra tekrar ayrıştırır. Ruby-SAML’de bu işlem iki farklı ayrıştırıcı (parser) ile gerçekleştirilir:REXML, belgeyi ayrıştırır ve dijital imzayı doğrular.
Nokogiri, belgedeki özniteliklere (attribute’lara) erişmek için kullanılır.
Eğer bu iki aşama arasında belge üzerinde herhangi bir biçimsel değişiklik oluşursa, XML belgesi ikinci kez ayrıştırıldığında ilk haliyle tamamen aynı olmayabilir.
Yetkilendirme işleminin güvenli olabilmesi için belgenin her aşamada tutarlı biçimde işlenmesi gerekir. Aksi halde yapısal farklılıklar ortaya çıkabilir. Bu farklılıklar, round-trip saldırıları olarak adlandırılan yöntemlerle kötüye kullanılabilir. XML yorum satırları (comments) ve CDATA bölümleri kullanılarak, belge dönüşüm sırasında yapısal olarak değiştirilebilir ve bu durum imza doğrulamasının beklenen şekilde çalışmamasına yol açabilir. Sonuç olarak, sistem farklı bir kullanıcıya ait bir kimlik bilgisini geçerli kabul edebilir.
Ruby-SAML / REXML Üzerinde Round-Trip Analizi
Bu tür davranış farklılıklarını tespit edebilmek için, round-trip zafiyetlerini inceleyen ve birden fazla SAML kütüphanesini karşılaştırmaya olanak tanıyan bir test ortamı geliştirildi. İlk olarak Document Type Definition (DOCTYPE) bölümüne odaklandık, çünkü geçmişte benzer sorunlar bu alanda ortaya çıkmıştı. Özellikle XML entity’lerinin nasıl yorumlandığını inceleyerek testler gerçekleştirdik.
Juho’nun ilk çalışmasında, tırnak işaretlerinin farklı yorumlanmasına neden olan notation declaration kullanılmıştı. Bu yaklaşımdan yola çıkarak, benzer başka davranış farklılıklarının bulunup bulunmadığını araştırdık. Uzun süren denemeler sonucunda, SYSTEM identifier alanı içinde de beklenmeyen dönüşümlerin oluşabildiğini gözlemledik.
Belge ilk kez ayrıştırıldığında karşılaşılan ilk etiket, orijinal “assertion” etiketi olmaktadır:
Kod:
Ancak belge yeniden ayrıştırıldığında sonuç tamamen değişir ve bu kez saldırganın ‘assertion’ değeri geçerli olarak yorumlanır
Görüldüğü üzere, tek tırnakla tanımlanmış SYSTEM tanımlayıcısı çift tırnağa dönüştürülmektedir. Ancak tanımlayıcının kendi içinde zaten çift tırnaklar bulunduğundan, bu dönüşüm XML belgesinin sözdizimini değiştirir. Bunun sonucunda XML yorum satırı işlenir ve tamamen farklı bir düğüm (node) ortaya çıkar. bu dönüşümü daha sade ve etkili bir saldırı vektörüne dönüşmüştür:
Bu vektör, Ruby-SAML kütüphanesini kullanan GitLab ve benzeri tüm uygulamalarda belgenin manipüle edilmesi ve assertion öğelerinin sahte olarak oluşturulması yoluyla herhangi bir kullanıcı olarak oturum açılmasına olanak tanımaktadır. Ancak bu, saldırının yalnızca ilk aşamasıdır. Ekip arkadaşım Zak, bunun GitLab üzerinde kimlik doğrulaması olmadan yönetici erişimi elde edecek şekilde nasıl genişletilebileceğini gösterecektir.
Round-Trip Saldırısı Yoluyla GitLab’te Yetki Yükseltme
Zafiyetin Anlaşılması
GitLab, SAML tabanlı kimlik doğrulama için Ruby-SAML kütüphanesini kullanmaktadır. Ancak kimlik doğrulaması olmadan erişim sağlanabilmesi için doğrulama sürecinin daha yakından incelenmesi gerekir; çünkü bu süreç saldırının merkezinde yer almaktadır.Bir round-trip gerçekleşmeden önce, kütüphane SAMLResponse içerisinde geçerli bir sertifikanın gömülü olup olmadığını kontrol eder. Bu, sertifikanın karma (hash) değerinin hesaplanıp sunucuda kayıtlı olan parmak izi (fingerprint) ile karşılaştırılmasıyla yapılır. Daha sonra bu sertifika, dijital imzanın doğrulanmasında kullanılır. Bu noktada imza, saldırının kritik bir bileşenidir; çünkü kuruma ait gerçek kimlik bilgilerine sahip olmadan tam bir hesap ele geçirmeye imkân tanıyabilir.
İmza Doğrulama Süreci
Sertifika SAMLResponse içinden çıkarıldıktan sonra asıl imza doğrulama süreci başlar. İlk olarak belge, bellekteki temsilinden tekrar XML formatına dönüştürülür. İşte Gareth’in round-trip saldırısı tam olarak bu aşamada devreye girer. Bu noktada kütüphane, saldırgan tarafından oluşturulan assertion öğesini dikkate almaz ve imzayı orijinal öğe üzerinden doğrulamaya devam eder.Eğer saldırgan assertion öğesini imza doğrulamasını atlatacak şekilde oluşturursa, sistemde ek güvenlik kontrolleri devreye girer. En kritik kontroller şunlardır:
- İmzalanmış öğenin ID değeri her iki belgede de aynı olmalıdır.
- Canonicalization (XML belgelerini normalize eden işlem) özellikleri her iki sürümde de birebir eşleşmelidir.
XML Şema Kısıtlamalarının Aşılması
İmzalı bir XML belgesinin sahte olarak oluşturulmasındaki temel zorluklardan biri, XML şema doğrulamasının Nokogiri tarafından önceden tanımlanmış şema dosyaları kullanılarak yapılmasıdır. Bu durum önemli bir kısıt oluşturur: geçerli görünen, imzalı bir XML belgesi üretilebilmesi için, belgenin öncelikle XML şema doğrulamasını geçmesi gerekir.XML Şema Doğrulamasının Anlaşılması
Bir XML şeması, SAML XML belgelerinin yapısını tanımlar ve aşağıdaki unsurları belirler:- Hangi öğelerin (elements) ve özniteliklerin (attributes) geçerli olduğu
- Alt öğelerin sırası ve sayısı
- Öğeler ve öznitelikler için veri türleri
GitLab’e Kimlik Doğrulaması Olmadan Erişim
Saldırıya geçmeden önce SAML şema doğrulamasının nasıl çalıştığını tekrar hatırlamak gerekir. Kimlik Sağlayıcı (IdP), tüm assertion öğesini değil, yalnızca Signature düğümünü imzalar. Ruby-SAML ise iki farklı XML ayrıştırıcı kullanır:- REXML, Signature öğesini okur.
- Nokogiri, DigestValue öğesini okur.
Burada ds, XML namespace’ini (isim alanını) ifade etmektedir. Normalde namespace’ler öğe adları arasındaki çakışmaları önler. Ancak XPath aramalarında namespace’lerin nasıl yorumlandığına dair bir tutarsızlıktan yararlanılmaktadır. Aşağıdaki senaryoyu ele alalım:”
İlk Signature öğesi doğrudan bir namespace tanımı içermez (xmlns="XML-Signature Syntax and Processing"). Bunun yerine bir XML Doctype tekniği kullanılır. Güvenlik uzmanları genellikle XXE saldırılarında !ENTITY bildirimlerine odaklanır; ancak !ATTLIST bildirimleri de benzer şekilde kullanılabilir. !ATTLIST, Signature öğesini tanımlar ve ona bir namespace özniteliği atar. Hem REXML hem de Nokogiri doctype tabanlı namespace tanımlarını destekler, ancak REXML’de kritik bir hata bulunmaktadır.”
XML standartları, aynı ada sahip birden fazla özniteliğin bulunmasını yasaklar.
Ancak REXML, doctype bildirimleri içinde bu kısıtlamayı yok sayar.
Bu durum, iki çelişen namespace özniteliğinin tanımlanmasına olanak tanır; ikinci tanım birincinin üzerine yazılır. Sonuç olarak REXML sahte (FAKE) bir Digest değerini okurken, Nokogiri gerçek (REAL) olanı okur.
Yöntem
Bu tutarsızlıktan yararlanmak için yaklaşım şöyledir:- İki adet Signature öğesi oluşturulur:
- Biri geçerli bir Digest değeri içerir.
- Diğeri ise değiştirilmiş (forged) bir Digest değeri taşır.
- Biri geçerli bir Digest değeri içerir.
Namespace Confusion ile Round-Trip Saldırısının Birleştirilmesi (Ruby < 3.4.2)
Namespace confusion tek başına Ruby-SAML üzerinde etkili olabilse de bir sınırlaması vardır: REXML’in XML marshalling ve unmarshalling işlemlerini hatalı yönetmesi yeni bir round-trip problemi doğurur. Ruby 3.4.2 öncesinde REXML, doctype bildirimlerindeki !ATTLIST dizgelerini keserek (truncate ederek) bu tekniği kırılgan hale getirir. GitLab bağlamında bu durum tek başına saldırıyı engelleyebilir; ancak her iki zafiyet birlikte kullanıldığında yine de etkili bir senaryo ortaya çıkabilir.
İlk XML ayrıştırma: REXML, !ATTLIST değerini başlangıçta yok sayar ve bunu yalnızca bir metin dizisi (string literal) olarak ele alır.
İkinci XML ayrıştırma: REXML bu kez !ATTLIST bildirimini tanır; bu da söz konusu tekniğin tam olarak etkili olmasına yol açar.
İmzalı XML Elde Etmek İçin WS-Federation’dan Yararlanma
Geçerli ve imzalı bir XML belgesi bulmak her zaman kolay değildir. Ancak Kimlik Sağlayıcıları (Identity Provider, IdP) çoğu zaman her tenant için varsayılan olarak WS-Federation adlı Tek Oturum Açma (SSO) protokolünü sessizce destekler. WS-Federation, aşağıdakine benzer şekilde imzalı metadata XML uç noktaları sağlar:Federasyon metadata belgeleri, yetkisiz kullanıcılar dâhil herkes tarafından erişilebilir durumdadır. Bunun için yalnızca uygulamaya ait benzersiz kimlik (application ID) gerekir; bu bilgi genellikle IdP’nin URL’sinden çıkarılabilir ya da bir arama motoru yardımıyla bulunabilir.
Bu metadata belgesi, geçerli bir SAML metadata belgesi olmasa da, namespace confusion yaklaşımı açısından yalnızca geçerli bir Signature öğesi yeterlidir. Önemli olan bu imzanın, Hizmet Sağlayıcıda (Service Provider) kayıtlı olan sertifikayla imzalanmış olmasıdır ve bu koşul sağlanmaktadır.
Bu herkese açık imzalı belge kullanılarak aşağıdaki adımlar mümkün olur:
- Geçerli bir Signature öğesinin çıkarılması
- Sahte bir imzalı assertion oluşturulması
Sonuç
Bu saldırı, round-trip teknikleri ile namespace confusion yaklaşımının birlikte kullanıldığında GitLab’e kimlik doğrulaması olmadan erişime yol açabildiğini göstermektedir. Zafiyetin temelinde, farklı XML ayrıştırıcılarının belge doğrulamasını tutarsız biçimde ele alması yatmaktadır; bu da imza doğrulama sürecinin yönlendirilebilmesine olanak tanır.Öne çıkan noktalar:
- XML ayrıştırma farklılıkları, güvenlik açısından istismar edilebilir tutarsızlıklar doğurabilir.
- Namespace karışıklığı, imza doğrulamasının atlatılmasına olanak tanıyabilir.
Bu tür saldırıları önlemek için, imzalı XML belgelerinin hem ayrıştırılması hem de doğrulanması aşamalarında aynı kütüphanenin kullanılması gerekir. Güvenilmeyen kullanıcı girdilerinin serileştirilip yeniden ayrıştırılmasından kaçınılmalıdır. Bu güvenlik açıkları GitLab Community Edition (CE) ve Enterprise Edition (EE) için 17.9.2, 17.8.5 ve 17.7.7 sürümlerinde giderilmiştir.Bir Çeviridir üstüne eklentiler yapılmıştır.
