Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 10

SSTI Temelleri ve Jinja2 Exploit Uygulamaları

Recommended resources

Merhaba, bir önceki dersimizde, verinin depolandıktan sonra farklı bir bağlamda tetiklendiği ikinci dereceden enjeksiyon saldırılarını ele almıştık. Bu saldırılar, veri akışının zaman ve mekan boyutunda ayrılması nedeniyle tespiti zor zafiyetler oluşturuyordu.

Bu dersimizde, enjeksiyon zafiyetlerinin bir başka kritik türüne, sunum katmanını hedef alan ve genellikle doğrudan Uzaktan Kod Çalıştırma (Remote Code Execution - RCE) ile sonuçlanan Sunucu Taraflı Şablon Enjeksiyonu (Server-Side Template Injection - SSTI) saldırılarına odaklanacağız. Veritabanlarını manipüle etmek yerine, bu kez uygulamanın dinamik içerik oluşturmak için kullandığı şablon motorlarının (template engines) mantığını istismar edeceğiz. Amacımız, SSTI'ın temel mekanizmasını analiz etmek ve popüler bir şablon motoru olan Jinja2 üzerinde pratik bir exploit uygulamaktır.

Bu görsel, bir SSTI saldırısının konseptini özetler: Saldırgan tarafından hazırlanan zararlı payload, bir şırınga gibi, web uygulamasının şablon motoruna enjekte edilir. Şablon motoru bu girdiyi veri olarak değil, kod olarak yorumladığında, saldırgan sunucu üzerinde dosya okuma veya komut çalıştırma gibi yetkisiz işlemler gerçekleştirebilir.

Şablon Motorları ve Zafiyetin Kaynağı

Modern web uygulamaları, genellikle MVC (Model-View-Controller) gibi mimari desenler kullanarak geliştirilir. Bu yaklaşımda, sunum katmanı (View), iş mantığından (Controller) ve veriden (Model) ayrılır. Şablon motorları, bu ayrımı kolaylaştıran araçlardır. Statik bir HTML şablonu alıp, veritabanından veya kullanıcı oturumundan gelen dinamik verilerle doldurarak nihai HTML çıktısını oluştururlar.

Örneğin, bir kullanıcıya "Hoş geldin, [kullanıcı_adı]" demek için şablonda Hoş geldin, {{ username }} gibi bir ifade kullanılır. Şablon motoru, {{ username }} kısmını gerçek kullanıcı adıyla değiştirir.

SSTI zafiyeti, bu noktada kritik bir hata yapıldığında ortaya çıkar: Kullanıcıdan gelen veri, şablonun içine yerleştirilecek bir veri olarak değil, şablonun kendisi olarak yorumlandığında.

Güvenli kullanım:
render_template('profil.html', username=kullanici_girdisi)

Tehlikeli kullanım:
render_template_string("Hoş geldin, " + kullanici_girdisi)

İkinci örnekte, eğer kullanici_girdisi {{ 7 * 7 }} gibi bir ifade içeriyorsa, şablon motoru bunu bir string olarak değil, yürütülmesi gereken bir komut olarak algılayabilir ve çıktıda "49" yazabilir. Bu, zafiyetin ilk işaretidir.

Server Side Template Injection (SSTI) - Geleceği Yazanlar - Turkcell

Turkcell Geleceği Yazanlar blogundaki bu makale, SSTI kavramını, MVC mimarisindeki yerini ve şablon motorlarının çalışma prensibini Türkçe olarak net bir şekilde açıklamaktadır.

Lütfen makalenin başından "Test Metodolojisi" başlığına kadar olan kısmı okuyun. Özellikle şu noktalara odaklanın: MVC Yaklaşımı ve Template Engine: Bu bölüm, şablon motorlarının modern uygulamalardaki rolünü ve dinamik içerik oluşturma sürecini özetler. Zafiyetin Temeli: Bu paragraflar, kullanıcı girdisinin sunucu tarafında bir şablonun parçası olarak işlenmesinin nasıl RCE'ye yol açabileceğini ve popüler şablon motorlarını listeler.


Tespit ve Tanımlama: Şablon Motorunu Parmak İzleme

Bir girdi noktasında SSTI'den şüphelendiğimizde, ilk adım zafiyetin varlığını doğrulamak ve ardından arka planda çalışan şablon motorunun türünü belirlemektir. Bu süreç, "parmak izleme" (fingerprinting) olarak adlandırılır. Her şablon motorunun kendine özgü bir sözdizimi (syntax) ve davranış biçimi vardır. Bu farklılıkları kullanarak motoru teşhis edebiliriz.

Süreç genellikle şu adımları izler:

  1. Basit bir matematiksel ifade gönderin. Örneğin, {{7*7}}. Çıktıda 49 görürseniz, bu Twig veya Jinja2 gibi bir motorun işareti olabilir.
  2. Eğer sonuç vermezse, farklı sözdizimlerini deneyin: ${7*7}, <%= 7*7 %> vb.
  3. Farklı motorların string birleştirme veya matematiksel işlemlere verdikleri özgün yanıtları test eden payload'lar gönderin.

Aşağıdaki karar ağacı, bu süreci görselleştirmek için etkili bir kılavuzdur.

Bu karar ağacı, farklı şablon motorlarını ayırt etmek için kullanılan bir dizi test payload'ını göstermektedir. Örneğin, `${7*7}` girdisine "49" yanıtı alırsanız, bir sonraki adımı izlersiniz. Yanıt alamazsanız, `{{7*7}}` gibi farklı bir payload ile devam edersiniz. Bu metodoloji, hedefteki şablon motorunu sistematik olarak tanımlamanızı sağlar.

Server Side Template Injection (SSTI) - Geleceği Yazanlar - Turkcell

Aynı makalenin devamında, zafiyetin nasıl tespit edileceği ve hata mesajları veya spesifik çıktılar aracılığıyla şablon motorunun nasıl tanımlanacağı pratik olarak anlatılmaktadır.

Lütfen "Test Metodolojisi" başlığı altındaki Tespit Etme ve Tanımlama bölümlerini inceleyin. Özellikle, zafiyeti doğrulamak için matematiksel ifadelerin nasıl kullanıldığına ve farklı motorların kendine has yorumlama farklılıklarının parmak izlemede nasıl bir rol oynadığına dikkat edin.


Exploit Uygulama: Jinja2 Üzerinden RCE

Şablon motorunu (örneğin Jinja2) belirledikten sonraki hedefimiz, genellikle Uzaktan Kod Çalıştırma (RCE) yeteneği kazanmaktır. Jinja2, Python tabanlı olduğu için, istismar süreci Python'un nesne modelini ve çalışma zamanı ortamını (runtime environment) manipüle etmeye dayanır.

Temel strateji, şablon içinde erişilebilir olan bir nesneden yola çıkarak Python'un tüm yüklü sınıflarına ulaşmak ve aralarından os veya subprocess gibi tehlikeli modülleri çalıştırabilecek birini bulmaktır. Bu süreç, bir "gadget chain" (araç zinciri) oluşturma olarak da bilinir.

Aşağıdaki adımlar, sıfırdan bir RCE payload'ının nasıl oluşturulduğunu gösterir:

  1. Başlangıç Noktası Bulma: Şablonun global kapsamında bulunan bir nesneye erişin. Bu, request, config, g gibi Flask/Jinja2'ye özgü global bir nesne veya basitçe boş bir string ('') olabilir.
  2. Sınıfa Erişme: __class__ özniteliğini kullanarak nesnenin sınıfını elde edin. Örn: {{ ''.__class__ }} -> <class 'str'>
  3. Miras Hiyerarşisinde Yükselme: __mro__ (Method Resolution Order - Metot Çözümleme Sırası) veya __base__ özniteliklerini kullanarak kalıtım ağacında yukarı doğru, en temel object sınıfına ulaşın. __mro__, bir sınıfın metotlarının arandığı sınıf sırasını içeren bir demettir. object sınıfı genellikle bu demetin sonlarına doğru yer alır.
  4. Tüm Alt Sınıfları Listeleme: object sınıfına ulaştıktan sonra, __subclasses__() metodunu çağırarak o anda Python interpreter'ında yüklü olan tüm sınıfların bir listesini alın.
  5. Tehlikeli Bir Sınıf Bulma: Bu uzun listede, komut çalıştırmanıza veya dosya okumanıza olanak tanıyan bir sınıf arayın. Örneğin, subprocess.Popen veya dosya işlemleri için <class '_io.FileIO'>. Bu sınıfın listedeki indeks numarasını bulmanız gerekir.
  6. Payload'ı Çalıştırma: Bulduğunuz sınıfı indeksiyle çağırın ve istediğiniz komutu parametre olarak verin.

Bu adımları birleştirdiğimizde, tipik bir Jinja2 RCE payload'ı ortaya çıkar:
{{ ''.__class__.__mro__[1].__subclasses__()[INDEX]('KOMUT').read() }}

Burada [INDEX], hedef sınıfın __subclasses__() listesindeki konumudur.

Server Side Template Injection with Jinja2

Bu OnSecurity makalesi, Jinja2 SSTI zafiyetini istismar etme sürecini teknik olarak en ince ayrıntısına kadar açıklamaktadır. Payload geliştirme mantığını anlamak için mükemmel bir kaynaktır.

Lütfen makaledeki şu bölümleri dikkatle inceleyin: What is ‘MRO’?: Bu bölüm, MRO'nun ne olduğunu ve payload oluşturmadaki kilit rolünü açıklıyor. Simple testing example arena: Bu kısımda verilen basit Flask uygulamasını yerel makinenizde kurarak anlatılan payload'ları canlı olarak test edebilirsiniz. Bu, konuyu derinlemesine anlamanız için şiddetle tavsiye edilir. Listing all classes & types through template: Bu kısa bölüm, __mro__ ve __subclasses__ kullanarak tüm sınıfların nasıl listeleneceğini gösterir. Payload development from 0: Bu bölüm, get_flashed_messages gibi global bir fonksiyondan başlayarak adım adım dosya okuma (ve dolayısıyla RCE) payload'ının nasıl geliştirildiğini gösteren Final evolution listesini içerir. Bu adımlar, istismar mantığının temelini oluşturur.

Blind SSTI ve WAF Atlatma Teknikleri

Saldırganlık deneyiminizden bildiğiniz gibi, her zaman doğrudan bir çıktı alamayabiliriz. SSTI de "kör" (blind) olabilir. Bu durumda, if koşulları ve sleep gibi komutlar kullanarak, Blind SQL Injection'a benzer şekilde, evet/hayır sorularıyla bilgi sızdırabiliriz.

Ayrıca, Web Application Firewall (WAF) gibi güvenlik önlemleri . , _, [] gibi karakterleri engelleyebilir. Jinja2'nin |attr() ve |format() gibi filtreleri, bu tür engellemeleri atlatmak için yaratıcı yollar sunar.

Server Side Template Injection with Jinja2

Aynı makale, daha ileri seviye istismar ve atlatma tekniklerini de kapsamaktadır.

Aşağıdaki ileri seviye bölümleri de gözden geçirin: WAF atlatma: Bu bölümde, . (nokta), _ (alt çizgi) ve [] (köşeli parantez) gibi karakterlerin |attr() filtresi kullanılarak nasıl atlatıldığı gösterilmektedir. Blind RCE: Bu bölümde, {{}} etiketleri engellendiğinde {% %} bloklarının nasıl kullanılabileceği ve Blind SQLi benzeri bir yaklaşımla komut çıktısının nasıl sızdırılabileceği anlatılmaktadır. Format String ile Atlatma: Bu kısım, |join filtresini atlatmak için format filtresinin nasıl zekice kullanılabileceğini gösterir. Nokta (.) Karakterini Atlatma: Bu bölüm, . karakterinin engellendiği durumlarda [] notasyonunun veya |attr filtresinin alternatif olarak nasıl kullanılabileceğini açıklar.


Savunma Stratejileri

SSTI'ya karşı en etkili savunma, zafiyetin kök nedenini ortadan kaldırmaktır.

  1. Güvenli Şablon Kullanımı: Asla ve asla kullanıcıdan gelen girdiyi doğrudan şablon olarak işlemeyin. render_template_string(kullanici_girdisi) gibi fonksiyonlardan kaçının. Bunun yerine, render_template('sablon_dosyasi.html', data=kullanici_girdisi) gibi, girdiyi sadece veri olarak kabul eden fonksiyonları kullanın.
  2. Sandboxing: Kullanıcıların şablonları düzenlemesine izin vermek zorundaysanız, şablon motorunu sıkı bir "sandbox" (korumalı alan) içinde çalıştırın. Jinja2'nin SandboxedEnvironment sınıfı bu amaçla tasarlanmıştır. Bu ortam, tehlikeli modüllere ve özniteliklere erişimi kısıtlar. Ancak, sandbox'ların da atlatılabileceğini unutmayın, bu yüzden tek başına bir çözüm değildir.
  3. Mantıksal Ayrım: Kullanıcıların şablonların tamamını değil, sadece belirli parçalarını (örneğin renk teması, başlık metni) değiştirmesine izin verin ve bu girdileri şablona güvenli bir şekilde entegre edin.

Server Side Template Injection (SSTI) - Geleceği Yazanlar - Turkcell

Makalenin sonundaki "Önlemler" bölümü, bu zafiyete karşı alınması gereken temel savunma stratejilerini özetlemektedir.

Lütfen bu listeyi inceleyerek savunma tarafındaki en iyi pratikleri gözden geçirin.


Özet ve Sonraki Adımlar

Bu dersimizde, sunum katmanını hedef alan ve genellikle RCE ile sonuçlanan kritik bir zafiyet olan Sunucu Taraflı Şablon Enjeksiyonu'nu (SSTI) derinlemesine inceledik.

Ana Çıkarımlar:

  • SSTI, kullanıcı girdisinin veri olarak değil, şablonun bir parçası olarak yorumlanmasıyla ortaya çıkar.
  • Tespit süreci, farklı şablon motorlarının sözdizimlerine özgü payload'lar göndererek hedefi "parmak izlemeye" dayanır.
  • Jinja2 gibi Python tabanlı motorlarda istismar, __class__, __mro__, __subclasses__ gibi Python'un iç mekanizmalarını kullanarak tehlikeli fonksiyonlara erişmeyi içerir.
  • En etkili savunma, kullanıcı girdisini asla şablonun kendisi olarak yorumlamamak ve mümkünse sandbox ortamları kullanmaktır.

Önceki derslerde SQL ve NoSQL enjeksiyonları ile veri katmanını, bu derste ise SSTI ile sunum/mantık katmanını hedef aldık. Bir sonraki dersimizde, tekrar veri katmanına döneceğiz ve özellikle modern uygulamalarda yaygınlaşan NoSQL veritabanlarına yönelik enjeksiyon saldırılarını analiz edeceğiz. MongoDB gibi belge tabanlı veritabanlarının, geleneksel SQL'den farklı, kendilerine özgü operatör manipülasyonu gibi saldırı vektörlerine nasıl sahip olduğunu ve bunlara karşı nasıl savunma mekanizmaları tasarlayacağımızı öğreneceğiz.