[TR] Server-Side Template Injection nedir?
Herkese merhaba. Ben Anıl Çelik. Uzun bir süredir aklımda olan çeşitli platformlarda yazdığım blog yazılarımı tek bir yere toplamak fikrini nihayet hayata geçirerek yazılarımı Medium’a taşımaya karar verdim. Bu yazım da buradadaki ilk paylaşımım :)
Bu yazımda, sizlere Server-Side Template Injection’ın (SSTI) ne olduğunu anlatmaya çalışacağım, sonrasında ise son günlerde TryHackMe platformunda yayınlanan ZTH: Obscure Web Vulns odasında bulunan SSTI Exploitation yöntemlerini göstermeye çalışacağım.
Konuya giriş yapmadan önce, Server-Side Template Injection (SSTI) zafiyetinin adından da anlaşılabileceği gibi Template Engine ler üzerinde gerçekleştirildiği bilgisini vererek başlayalım.
- Öncelikle, Template Engine nedir?
Günümüzde çoğu web developer, Template Engine adı verilen ve web sitelerinde hazır kullanılmak üzere oluşturulan Template, yani Şablonları içerisinde bulunduran ve developerların üzerinde dinamik olarak değişiklikler yapabilecekleri, en kaba tabiriyle statik web sayfalarını bulunduran sistemlerdir. Bunlara; Twig, Nunjucks, Pub, FreeMaker vb. gibi Template Engine ler örnek verilebilir.
- Server-Side Template Injection (SSTI) nedir?
Server-Side Template Injection, kullanıcının girdiği input ile Template Engine üzerinde çeşitli parametreleri manipüle ederek kod çalıştırma işlemidir. Daha açık olmak gerekirse, Server Side Template Injection (SSTI) zafiyeti, template’ın bulunduğu sayfa render işlemine uğramadan önce, template data’ya gelen güvenli olmayan user input ile yapılan manipülasyon işleminden kaynaklanmaktadır. SSTI’ın kritik bir web güvenlik zafiyeti olmasının sebebi, hedef sistemde tespit edilmesinden sonra XSS gibi güvenlik zafiyetlerine de sebep verip, hedef sistemde Remote Code Execution’a (RCE) kadar gidebilmesidir.
- Server-Side Template Injection’ın Tespiti:
Burada, yazımın başında da bahsetmiş olduğum TryHackMe platformunda bulunan zafiyetli makineden faydalanarak ilerleyen örneklerimi size göstereceğim:
Öncelikle, hedef sisteme ait web sayfasına gittiğimizde, bize 2+2'nin cevabını soran ve input girmemizi bekleyen bir adet textbox bulunmakta:
Buraya herhangi bir input yazdığımızda, bize girdiğimiz herhangi bir inputu tekrar output olarak döndürdüğünü görebiliriz:
Deneme amaçlı “hello world” inputunu girdiğimde, gördüğümüz gibi “hello world” yazısı bana tekrar output olarak geri döndü. Bir textbox’da SSTI zafiyet ararken birçok payload kullanılabilir; bkz. Ancak, biz öncelikle genelde SSTI zafiyeti ararken ilk denenen payload olan “{{2+2}}” input’u ile zafiyeti test edeceğiz:
Gördüğümüz gibi, yukarda belirtmiş olduğum input’u sisteme verdiğimde, sistem bana girdiğim inputu doğrudan “{{2+2}}” şeklinde output olarak döndürmek yerine, verdiğim aritmetiksel işlemi sistem içerisinde gerçekleştirerek bana bu işlemin sonucunu, yani “4” ü döndürüyor. Bu noktada, verdiğim güvenilir olmayan input ile içeride bir kod çalıştırabildiğimi görüp, sonrasında başka payloadlar deneyerek bu sistem üzerinden neler elde edebileceğimi görebilirim. Örneğin, file read payload’u kullanarak sistem üzerindeki “/etc/passwd” dosyasını okumaya çalışabiliriz. Ancak bundan önce, hedef sistemde çalışan Template Engine’in hangisi olduğunu anlayabilmemiz için, aşağıdaki figüre göz atabiliriz:
Buradaki şemaya göre, ilk girdiğimiz “{{2+2}}” inputuna göre, karşımızdaki Template Engine ya Jinja2, ya da Twig. Burada istersek karşı tarafta SSTI zafiyetinin gerçekten olup olmadığını teyit etmek için bir sonraki input türü olan “{{7*’7‘}}” değerini deneyebiliriz. Ancak hedef makinenin zaten SSTI zafiyeti bulundurduğunu bildiğim için, bu kısmı atlayıp direk Jinja2 ve Twig enginelerine ait payloadları deneyerek, yukarıda da bahsetmiş olduğum “/etc/passwd” dosyasını okumaya çalışacağım:
Jinja2 için aşağıdaki payloadu denediğimde, istediğim output’u elde ediyorum ve dolayısıyla sistemin de Jinja2 çalıştırdığını anlıyorum:
Payload: “{{“.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read()}}”
Output:
Gördüğümüz gibi, istediğimiz output’u elde etmeyi başardık.
İkinci bir örnek olarak, SSTI’ı bir textbox üzerinden göstermektense, adres çubuğundan gönderilen bir request ile test
Gördüğümüz gibi, açılan sayfada TryHackMe platformunun bir introsu bulunmakta. Adres çubuğuna dikkat ettiğimizde, bulunduğumuz dizin üzerisinde object request yapmamıza olanak veren bir parametre var: “/?hackme=” . Bu parametre ile herhangi bir şey göndermeye çalışalım:
Yukarıda olduğu gibi “/?hackme=” parametresine “0xpr0N3rd” değerini verdiğimde, az önce “Hello” şeklinde görünen yerin sonuna string concatenation işlemi uygulanarak girmiş olduğum parametre yazdırıldı ve dönen output “Hello 0xpr0N3rd” şeklinde oldu. Yani kısaca buradan az önce textbox’da denediğimiz gibi, girilen inputun bize aynı şekilde output olarak döndüğünü görüyoruz. Bu bize bir SSTI zafiyeti olabileceğinin sinyalini veriyor. İlk adım olarak, yine içeride aritmetik bir işlemin çalışmasına sebep olacak bir input verelim:
Bu sefer, içeride oluşabilecek aritmetik işlemi tetiklemek için “4/2” inputunu denedim ve vermiş olduğum “int(4/2)” ile de çıkacak sonucu integer’a parse ederek output edilmesini sağladım. Sonuç olarak; “2” output’unu elde etmeyi başardık ve tekrar burada da bir SSTI zafiyeti olduğunu anladık. Burada da son olarak “/etc/passwd” dosyasını okumaya çalışalım:
Az önce “/etc/passwd” dosyasını okumak için kullandığımız payload’u tekrar kullandığımda, bu sefer bir hatayla karşılaştım. Kullandığım payload Jinja2'ye ait bir payload ancak bu payload’u kullandığımda bir hata alıyorum ve çıkan hata mesajında karşı sistemin “Tornado” çalıştırdığını görüyorum. O halde, aynı işlemi bir Tornado payload’u ile tekrar deneyelim. İlgili payload’a buradan ulaşabilirsiniz.
Payload: {% import os %}{{ os.popen(“cat /etc/passwd”).read() }}
Output:
Gördüğümüz gibi, yine başarılı bir şekilde istediğimiz output’u elde ettik.
Manual exploitation işlemlerini gösterdikten sonra, bir de SSTI zafiyetini automated şekilde exploit edebileceğimiz bir tool olan tplmap’i göstermek istiyorum. İlgili tool’a buradan ulaşabilirsiniz.
tplmap’i hedef sistemin URL veya IP adresini, exploit edilebileceğinden şüphelendiğimiz parametreyi ve son olarak çalıştırmak istediğimiz komutu ekleyerek kullanabiliriz. İlk örneğimizi ele alarak öncelikle exploit edilebileceğinden şüphelendiğimiz parametreyi bulmaya çalışalım:
Sitenin kaynak kodlarını incelediğimizde, input olarak verdiğimiz değeri tutan değişkenin isminin “name” olduğunu görüyoruz. Şimdi ise bu bilgileri tplmap’e verelim:
Gördüğümüz gibi, automated exploitation işlemi ile de istediğimiz bilgiye ulaştık.
Yazımı sonlandırmadan önce, son olarak SSTI saldırılarından nasıl korunabileceğine de değinmek istiyorum:
- Template içerisine dynamic bir input almamız gerektiğinde, bu işlemi direkt olarak template file üzerinde yapmaktansa, Template Engine içerisinde bulunan built-in fonksiyonlar kullanılarak bunların kontrolü sağlanabilir.
- İkinci bir korunma yöntemi olarak, sayfayı direkt olarak ana makine üzerinden host etmektense, Docker containerlar kullanılabilir.
Server-Side Template Injection hakkında bahsetmek istediklerim bu kadardı. Yazımı okuduğunuz için teşekkür ederim.
Bir sonraki yazıda görüşmek üzere.
Kaynaklar:
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
- https://opsecx.com/index.php/2016/07/03/server-side-template-injection-in-tornado/
- https://portswigger.net/research/server-side-template-injection
- https://www.netsparker.com/blog/web-security/server-side-template-injection/
- https://tryhackme.com/room/zthobscurewebvulns
- https://tryhackme.com/room/nonamectf